diff --git a/Source/HBIOS/nascom.asm b/Source/HBIOS/nascom.asm index 6752614c..35d78203 100644 --- a/Source/HBIOS/nascom.asm +++ b/Source/HBIOS/nascom.asm @@ -33,7 +33,7 @@ LF .EQU 0AH ; Line feed CS .EQU 0CH ; Clear screen CR .EQU 0DH ; Carriage return CTRLO .EQU 0FH ; Control "O" -CTRLQ .EQU 11H ; Control "Q" +CTRLQ .EQU 11H ; Control "Q" CTRLR .EQU 12H ; Control "R" CTRLS .EQU 13H ; Control "S" CTRLU .EQU 15H ; Control "U" @@ -42,6 +42,11 @@ DEL .EQU 7FH ; Delete ; BASIC WORK SPACE LOCATIONS +; 0200H - 2000H BASIC EXECUTABLE +; 2000H - 2090H STACK +; 2090H - 20F8H BASIC EXECUTABLE VARAIABLES / WORKSPACE +; 20F9H - BASIC PROGRAM START + WRKSPC .EQU BAS_END+90H ; WAS 4090H ; BASIC Work space USR .EQU WRKSPC+3H ; "USR (x)" jump OUTSUB .EQU WRKSPC+6H ; "OUT p,n" @@ -132,7 +137,7 @@ MO .EQU 24H ; Missing operand HX .EQU 26H ; HEX error BN .EQU 28H ; BIN error - .ORG BAS_LOC ; WAS 02000H + .ORG BAS_LOC ; WAS 02000H COLD: JP STARTB ; Jump for cold start WARM: JP WARMST ; Jump for warm start @@ -173,8 +178,8 @@ MSIZE: LD HL,MEMMSG ; Point to message MLOOP: INC HL ; Next byte ; LD A,H ; Above address FFFF ? ; OR L - LD A,H ; Memory top set below HBIOS Proxy @ FE00 - CP $FD + LD A,H ; Memory top set below HBIOS Proxy @ FE00 + CP $FD JP Z,SETTOP ; Yes - 64K RAM LD A,(HL) ; Get contents LD B,A ; Save it @@ -303,7 +308,7 @@ WORDS: .BYTE 'E'+80H,"ND" .BYTE 'C'+80H,"ONT" .BYTE 'L'+80H,"IST" .BYTE 'C'+80H,"LEAR" - .BYTE 'C'+80H,"LOAD" + .BYTE 'P'+80H,"LAY" .BYTE 'C'+80H,"SAVE" .BYTE 'N'+80H,"EW" @@ -392,7 +397,7 @@ WORDTB: .WORD PEND .WORD CONT .WORD LIST .WORD CLEAR - .WORD REM + .WORD PLAY .WORD REM .WORD NEW @@ -573,10 +578,10 @@ CHKSTK: PUSH HL ; Save code string address ADD HL,BC .BYTE 3EH ; Skip "PUSH HL" ENFMEM: PUSH HL ; Save code string address - LD A,0D0H ;LOW -48 ; 48 Bytes minimum RAM + LD A,0D0H ;LOW -48 ; 48 Bytes minimum RAM SUB L LD L,A - LD A,0FFH; HIGH (-48) ; 48 Bytes minimum RAM + LD A,0FFH ; HIGH (-48) ; 48 Bytes minimum RAM SBC A,H JP C,OMERR ; Not enough - ?OM Error LD H,A @@ -1257,34 +1262,36 @@ UPDATA: LD (NXTDAT),HL ; Update DATA pointer EX DE,HL ; Restore code string address RET +; GET CONSOLE INPUT STATUS VIA HBIOS TSTBRK: - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL - ; GET CONSOLE INPUT STATUS VIA HBIOS - LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C - LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS - RST 08 ; HBIOS RETURNS STATUS IN A - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC + PUSH BC ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH DE + PUSH HL + + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS + RST 08 ; HBIOS RETURNS STATUS IN A + + POP HL ; RESTORE REGISTERS (AF IS OUTPUT) + POP DE + POP BC RET Z ; No key, go back - PUSH BC - PUSH DE - PUSH HL - ; INPUT CHARACTER FROM CONSOLE VIA HBIOS - LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C - LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR - RST 08 ; HBIOS READS CHARACTDR - LD A,E ; MOVE CHARACTER TO A FOR RETURN + PUSH BC + PUSH DE + PUSH HL + +; INPUT CHARACTER FROM CONSOLE VIA HBIOS + + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + RST 08 ; HBIOS READS CHARACTDR + LD A,E ; MOVE CHARACTER TO A FOR RETURN ; - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC + + POP HL ; RESTORE REGISTERS (AF IS OUTPUT) + POP DE + POP BC CP ESC ; Escape key? JR Z,BRK ; Yes, break @@ -1292,22 +1299,22 @@ TSTBRK: JR Z,BRK ; Yes, break CP CTRLS ; Stop scrolling? RET NZ ; Other key, ignore -STALL: ; Wait for key - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL +STALL: ; Wait for key + + PUSH BC ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH DE + PUSH HL ; - ; INPUT CHARACTER FROM CONSOLE VIA HBIOS - LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C - LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR - RST 08 ; HBIOS READS CHARACTDR - LD A,E ; MOVE CHARACTER TO A FOR RETURN +; INPUT CHARACTER FROM CONSOLE VIA HBIOS ; - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + RST 08 ; HBIOS READS CHARACTDR + LD A,E ; MOVE CHARACTER TO A FOR RETURN +; + POP HL ; RESTORE REGISTERS (AF IS OUTPUT) + POP DE + POP BC CP CTRLQ ; Resume scrolling? RET Z ; Release the chokehold CP CTRLC ; Second break? @@ -1357,7 +1364,6 @@ NULL: CALL GETINT ; Get integer 0-255 LD (NULLS),A ; Set nulls number RET - ACCSUM: PUSH HL ; Save address in array LD HL,(CHKSUM) ; Get check sum LD B,0 ; BC - Value of byte @@ -1967,8 +1973,8 @@ OPRND: XOR A ; Get operand routine JP C,ASCTFP ; Number - Get value CALL CHKLTR ; See if a letter JP NC,CONVAR ; Letter - Find variable - CP '&' ; &H = HEX, &B = BINARY - JR NZ, NOTAMP + CP '&' ; &H = HEX, &B = BINARY + JR NZ, NOTAMP CALL GETCHR ; Get next character CP 'H' ; Hex number indicated? [function added] JP Z,HEXTFP ; Convert Hex to FPREG @@ -2981,14 +2987,14 @@ VAL: CALL GETLEN ; Get length of string EX (SP),HL ; Save string end,get start PUSH BC ; Save end+1 byte LD A,(HL) ; Get starting byte - CP '$' ; Hex number indicated? [function added] - JP NZ,VAL1 - CALL HEXTFP ; Convert Hex to FPREG - JR VAL3 + CP '$' ; Hex number indicated? [function added] + JP NZ,VAL1 + CALL HEXTFP ; Convert Hex to FPREG + JR VAL3 VAL1: CP '%' ; Binary number indicated? [function added] - JP NZ,VAL2 - CALL BINTFP ; Convert Bin to FPREG - JR VAL3 + JP NZ,VAL2 + CALL BINTFP ; Convert Bin to FPREG + JR VAL3 VAL2: CALL ASCTFP ; Convert ASCII string to FP VAL3: POP BC ; Restore end+1 byte POP HL ; Restore end+1 address @@ -3054,7 +3060,7 @@ POKE: CALL GETNUM ; Get memory address CALL DEINT ; Get integer -32768 to 3276 PUSH DE ; Save memory address CALL CHKSYN ; Make sure ',' follows - .BYTE ',' + .BYTE ',' CALL GETINT ; Get integer 0-255 POP DE ; Restore memory address LD (DE),A ; Load it into memory @@ -4143,19 +4149,21 @@ ATNTAB: .BYTE 9 ; Table used by ATN ARET: RET ; A RETurn instruction +; INPUT CHARACTER FROM CONSOLE VIA HBIOS + GETINP: - PUSH BC - PUSH DE - PUSH HL - ; INPUT CHARACTER FROM CONSOLE VIA HBIOS - LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C - LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR - RST 08 ; HBIOS READS CHARACTDR - LD A,E ; MOVE CHARACTER TO A FOR RETURN - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC + PUSH BC + PUSH DE + PUSH HL + + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + RST 08 ; HBIOS READS CHARACTDR + LD A,E ; MOVE CHARACTER TO A FOR RETURN + + POP HL ; RESTORE REGISTERS (AF IS OUTPUT) + POP DE + POP BC RET CLS: LD A,CS ; ASCII Clear screen @@ -4199,26 +4207,26 @@ DOKE: CALL GETNUM ; Get a number HEX: CALL TSTNUM ; Verify it's a number CALL DEINT ; Get integer -32768 to 32767 PUSH BC ; Save contents of BC - LD HL,PBUFF - LD A,D ; Get high order into A + LD HL,PBUFF + LD A,D ; Get high order into A CP $0 - JR Z,HEX2 ; Skip output if both high digits are zero + JR Z,HEX2 ; Skip output if both high digits are zero CALL BYT2ASC ; Convert D to ASCII - LD A,B - CP '0' - JR Z,HEX1 ; Don't store high digit if zero - LD (HL),B ; Store it to PBUFF - INC HL ; Next location -HEX1: LD (HL),C ; Store C to PBUFF+1 + LD A,B + CP '0' + JR Z,HEX1 ; Don't store high digit if zero + LD (HL),B ; Store it to PBUFF + INC HL ; Next location +HEX1: LD (HL),C ; Store C to PBUFF+1 INC HL ; Next location -HEX2: LD A,E ; Get lower byte +HEX2: LD A,E ; Get lower byte CALL BYT2ASC ; Convert E to ASCII - LD A,D + LD A,D CP $0 - JR NZ,HEX3 ; If upper byte was not zero then always print lower byte - LD A,B - CP '0' ; If high digit of lower byte is zero then don't print - JR Z,HEX4 + JR NZ,HEX3 ; If upper byte was not zero then always print lower byte + LD A,B + CP '0' ; If high digit of lower byte is zero then don't print + JR Z,HEX4 HEX3: LD (HL),B ; to PBUFF+2 INC HL ; Next location HEX4: LD (HL),C ; to PBUFF+3 @@ -4254,6 +4262,7 @@ ADD301 ADD A,$30 ; And make it full ASCII ; Convert "&Hnnnn" to FPREG ; Gets a character from (HL) checks for Hexadecimal ASCII numbers "&Hnnnn" ; Char is in A, NC if char is ;<=>?@ A-z, CY is set if 0-9 +; HEXTFP EX DE,HL ; Move code string pointer to DE LD HL,$0000 ; Zero out the value CALL GETHEX ; Check the number for valid hex @@ -4362,40 +4371,40 @@ CHKBIN: INC DE BINERR: LD E,BN ; ?BIN Error JP ERROR - JJUMP1: LD IX,-1 ; Flag cold start JP CSTART ; Go and initialise +; OUTPUT CHARACTER TO CONSOLE VIA HBIOS + MONOUT: - ; SAVE ALL INCOMING REGISTERS - PUSH AF - PUSH BC - PUSH DE - PUSH HL - ; OUTPUT CHARACTER TO CONSOLE VIA HBIOS - LD E,A ; OUTPUT CHAR TO E - LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C - LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR - RST 08 ; HBIOS OUTPUTS CHARACTDR - ; RESTORE ALL REGISTERS - POP HL - POP DE - POP BC - POP AF - RET - -MONITR: LD A,BID_BOOT ; BOOT BANK - LD HL,0 ; ADDRESS ZERO - CALL HB_BNKCALL ; DOES NOT RETURN + PUSH AF ; SAVE ALL INCOMING REGISTERS + PUSH BC + PUSH DE + PUSH HL + + LD E,A ; OUTPUT CHAR TO E + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR + RST 08 ; HBIOS OUTPUTS CHARACTDR + + POP HL ; RESTORE ALL REGISTERS + POP DE + POP BC + POP AF + RET + +MONITR: LD A,BID_BOOT ; BOOT BANK + LD HL,0 ; ADDRESS ZERO + CALL HB_BNKCALL ; DOES NOT RETURN INITST: LD A,0 ; Clear break flag LD (BRKFLG),A + CALL SET_DUR_TBL ; SET UP SOUND TABLE JP INIT ARETN: RETN ; Return from NMI - TSTBIT: PUSH AF ; Save bit mask AND B ; Get common bits POP BC ; Restore bit mask @@ -4406,19 +4415,265 @@ TSTBIT: PUSH AF ; Save bit mask OUTNCR: CALL OUTC ; Output character in A JP PRNTCRLF ; Output CRLF -TXT_READY: - .DB CR,LF - .TEXT "BASIC READY " - .DB CR,LF,0FFH +; --------------------------------------------------------------------------------------- + +; PLAY O,N,D ; PLAY OCTAVE 0-8, NOTE N (0-11), DURATION (1-8) [1/8 - 8/8 SECONDS] + +PLAY: CALL GETINT ; GET OCTAVE + PUSH AF ; AND SAVE + + CALL CHKSYN ; Make sure ',' follows + .BYTE ',' + + CALL GETINT ; GET NOTE + PUSH HL ; SAVE SYNTAX POINTER + LD L,A + LD H,0 + ADD HL,HL ; X2 + ADD HL,HL ; X4 + LD DE,FRQDURTBL ; POINT TO NOTE ENTRY + ADD HL,DE ; ITS IN HL + + EX (SP),HL ; RESTORE SYNTAX POINTER + ; IN HL. NOTE PTR ON STACK + + CALL CHKSYN ; Make sure ',' follows + .BYTE ',' + CALL GETINT ; GET DURATION + + POP DE ; GET NOTE PTR IN DE + EX (SP),HL ; GET OCTAVE IN HL. SYNTAX POINTER ON STACK + EX DE,HL ; PUT NOTE PTR IN HL, OCTAVE IN DE + + PUSH BC ; SAVE SYNTAX POINTER + LD B,D ; SAVE OCTAVE + PUSH AF ; SAVE DURATION + + LD A,(HL) ; LOAD 1ST ARG + INC HL ; IN DE + LD E,A ; WHICH IS THE + LD A,(HL) ; FREQUENCY FOR + INC HL ; THE EIGHTH + LD D,A ; OCTAVE + + PUSH DE + + LD A,(HL) ; LOAD 2ND ARG + INC HL ; IN DE + LD E,A ; WHICH IS THE + LD A,(HL) ; PITCH + LD D,A + + PUSH DE ; SETUP ARGS IN HL + POP HL ; AND DE + POP DE ; DE = FREQUENCY + ; HL = PITCH + LD A,8 ; DIVIDE THE + SUB B ; FREQUENCY BASED + JR Z,SPK_OCTOK ; ON THE OCTAVE + LD B,A +SPK_OCTDIV: + SRL D ; 0>D>C ; MULTIPLY THE + RR E ; C>E>C ; DURATION EVERY + SLA L ; CC>C ; BCHL = BCHL / 2 + RR H ; C>H>C ; + RR L ; C>L>C ; + SRL C ; 0>C>C ; BCHL = BCHL / 2 + RR H ; C>H>C ; + RR L ; C>L>C ; + SRL C ; 0>C>C ; BCHL = BCHL / 2 + RR H ; C>H>C ; + RR L ; C>L>C ; + + POP DE + EX DE,HL + +; The following SPK_BEEPER routine is a modification of code from +; "The Complete SPECTRUM ROM DISSASSEMBLY" by Dr Ian Logan & Dr Frank O’Hara +; https://www.esocop.org/docs/CompleteSpectrumROMDisassemblyThe.pdf +; +; DE Number of passes to make through the sound generation loop +; HL Loop delay parameter + + PUSH IX + DI ; Disable the interrupt for the duration of a 'beep'. + LD A,L ; Save L temporarily. + SRL L ; Each '1' in the L register is to count 4 T states, but take INT (L/4) and count 16 T states instead. + SRL L + CPL ; Go back to the original value in L and find how many were lost by taking 3-(A mod 4). + AND $03 + LD C,A + LD B,$00 + LD IX,SPK_DLYADJ ; The base address of the timing loop. + ADD IX,BC ; Alter the length of the timing loop. Use an earlier starting point for each '1' lost by taking INT (L/4). + LD A,(RTCVAL) ; Fetch the present border colour from BORDCR and move it to bits 2, 1 and 0 of the A register. +; +; The HL register holds the 'length of the timing loop' with 16 T states being used for each '1' in the L register and 1024 T states for each '1' in the H register. +; +SPK_DLYADJ: + NOP ; Add 4 T states for each earlier entry point that is used. + NOP + NOP + INC B ; The values in the B and C registers will come from the H and L registers - see below. + INC C +BE_H_L_LP: + DEC C ; The 'timing loop', i.e. BC*4 T states. (But note that at the half-cycle point, C will be equal to L+1.) + JR NZ,BE_H_L_LP + LD C,$3F + DEC B + JP NZ,BE_H_L_LP +; + XOR %00000100 ; Flip bit 2. The loudspeaker is now alternately activated and deactivated. + OUT (RTCIO),A ; Perform the 'OUT' operation, leaving other bits unchanged. + LD B,H ; Reset the B register. + LD C,A ; Save the A register. + BIT 4,A ; Jump if at the half-cycle point. + JR NZ,BE_AGAIN +; + LD A,D ; After a full cycle the DE register pair is tested. + OR E + JR Z,BE_END ; Jump forward if the last complete pass has been made already. + LD A,C ; Fetch the saved value. + LD C,L ; Reset the C register. + DEC DE ; Decrease the pass counter. + JP (IX) ; Jump back to the required starting location of the loop. +; +BE_AGAIN: ; The parameters for the second half-cycle are set up. + LD C,L ; Reset the C register. + INC C ; Add 16 T states as this path is shorter. + JP (IX) ; Jump back. + +BE_END: EI + POP IX + POP BC ; RECALL SYNTAX POINTER + POP HL + RET +; +RTCVAL .DB 0 +; +; SETUP THE ONE SECOND TONE DURATION TABLE BASED ON PROCESSOR SPEED AND TONE FREQUENCY +; +; DURATION = (CPUMHZ / 8) / FREQUENCY +; DURATION = (CPUKHZ * 1000 / 8 ) / FREQUENCY +; DURATION = (CPUKHZ * 125 ) / FREQUENCY +; DURATION = (CPUKHZ * 256 / 2 - CPUKHZ - (2 * CPUKHZ) ) / FREQUENCY + +SET_DUR_TBL: + LD B,BF_SYSGET ; GET CPU SPEED + LD C,BF_SYSGET_CPUINFO ; FROM HBIOS + RST 08 ; IN DE + + PUSH DE ; SAVE FOR CALCULATION + POP BC ; - CPUKHZ - (2 * CPUKHZ) + + LD H,E ; DEHL = DE * 256 + LD E,D + LD D,0 + LD L,D + + SRL E ; 0>E>C ; DEHL = DEHL / 2 + RR H ; C>H>C ; + RR L ; C>L>C ; + + SBC HL,BC ; DEHL = DEHL - CPUKHZ + JR NC,FRQ_AJ1 + DEC DE +FRQ_AJ1:SLA C ; C