; 300 To 2000 BAUD LOADER PROGRAM ; (C) 1981 Jay Fenton for Astrovision Inc. ; ; ******************************************************** ; ; Typed in on Dec. 16, 2007 by Adam Trionfo ; ; Compile with Zmac using: ; ; zmac -i -m -o 300-2000.bin -x 300-2000.lst 300-2000.asm ; ; See comments at end of program [for version info] ; ; ******************************************************** ; ; This program loads audio tapes generated by the old ; version of BALLY BASIC into the New and Improved version ; of BALLY BASIC. ; ; Operating Instructions ; ; 1) Load the LOADER PROGRAM into memory using the :RUN ; command. When loaded the screen background ; brightness will change continuously. ; 2) Cue up the 300 baud tape and PLAY it. ; 3) Press the GO key to release the LOADER PROGRAM. ; 4) Observe the program statements accumulating in ; the buffer just below the program zone. The screen ; will reveal the scratchpad during this phase. ; 5) Program loading will stop on any of the following ; conditions: ; a) :RETURN is found in an unnumbered line. ; b) RUN is found in an unnumbered line. ; c) The HALT key is pressed, in which case we ; proceed to end loading. ; d) Any other key in the column beneath HALT ; is pressed. ; Cases a), b), and d) cause the program to go ; back to step 2) ; If no more segments are to be loaded, press ; HALT to proceed to final loading. ; 6) After HALT is pressed the program will convert the ; statements in the buffer into the representation ; used within BALLY BASIC. This is done by moving ; the buffer to the highest possible address and ; using special I/O routines which feed characters ; from this buffer to the BALLY BASIC input routines. ; This will be seen on the screen as a race between ; the input buffer and the program storage area. ; 7) The LOADER PROGRAM will then exit to BALLY BASIC. ; The variables A-Z will be zeroed out, and the screen ; will be cleared. The program may now be executed or ; written out at 2000 baud. ; ; NOTES: ; During the readin phase, lines without line numbers, ; rubout characters, and spaces appearing before and ; immediately after line numbers are filtered out. ; It is permissible to load tapes which contain line ; numbers out of sequence or which delete previous ; lines. ; NOLIST INCLUDE "HVGLIB.H" ; HOME VIDEO GAME LIBRARY ; Defines HLTPORT EQU $15 ; KEYPAD COLUMN FOR HALT KEY ; ; SOME CHARACTER EQUATES NL EQU $0D ; ASCII NEW LINE RUBOUT EQU $1F ; BASIC 'ERASE' CHARACTER ; ; These equates establish addresses within New BALLY BASIC. ; HOOKER EQU $218B ; INITIAL HOOK VECTOR VALUES GL2 EQU $2C68 ; RET ADDR FOR OUTCH TO SKIP GL2A EQU $2C70 ; ADDR IN INPUT LINE ROUTINE TO SKIP TO INIT0 EQU $2531 ; HALT ROUTINE ENTRY ; ; ?? bytes of TAPe input BUFfer [was 48 bytes in Old BALLY BASIC] BUFSTART EQU $4280 ; 300 BAUD BUFFER START [screen line 16] ; ; Scratchpad area: TXTUNF EQU $4E20 ; PROGRAM STORAGE AREA POINTER VARBGN EQU $4E22 ; VARIABLE AREA START ADDR LASTBUF EQU $4E55 ; LAST BYTE WHICH BUFFER CAN USE HKVECT EQU $4E92 ; HOOK VECTOR AREA START CHKIO EQU $4E98 ; INPUT CHARACTER HOOK VECTOR OUTCH EQU $4E9B ; OUTPUT CHARACTER HOOK VECTOR ; ; in unused area between BUFFEND and STKLMT SAVDAT EQU $4F26 ; REMEMBERS DATA BENEATH TXTUNF ; [replacement for TAPe INSert pointer, now a full word wide] POINTER EQU $4F28 ; 300 BAUD INPUT BUFFER POINTER TARGET EQU $4F2A ; ADDR TO RELOCATE I/O ROUTINE TO ; STACK EQU $4FEA ; TOP OF BASIC STACK ZONE [DURAT] ; ; BIT BANGER GOODIES FOLLOW: ; note: New Bally Basic (widely known as Astro Basic)'s Cartridge ; has a built-in 2000 [more likely 1800] baud Tape Interface jack. ; This is accessed by a Read (no Writes allowed!) using 00111100B ; on the upper half of the Address Bus (bits 0 through 9 ignored) ; When READing, the state of Data line D0 follows the tape output. ; To WRITE, Address line 10 is fed to the recorder's mic. input, ; hence the (un-used by this program) BANG1 and BANG0 EQUates : BANGIN EQU $3C00 ; BIT BANGER READ PORT ; BANG1 EQU $3800 ; BIT BANG CODE TO WRITE A ONE ; BANG0 EQU $3C00 ; BIT BANG CODE TO WRITE A ZERO ; ; PARAMETERS FOR 300 BAUD BIT DETECTOR ; THESE SPECIFY THE MINIMUM AND MAXIMUM NUMBER ; OF CONSECUTIVE CYCLES OF TONE REQUIRED TO ; RECOGNIZE A ZERO OR A ONE BIT MIN0 EQU 3 MAX0 EQU 4 MIN1 EQU 6 MAX1 EQU 8 ; LIST ORG $4000 ; :RUN EXECUTION BEGINS HERE BEGIN: STARTUP: DI ; NIX INTERRUPTS XOR A ; USE OTHER COLOR REGISTERS OUT (HORCB),A LD A,$02 ; GREY SCALE FOREGROUND OUT (COL1R),A RLCA OUT (COL2R),A LD A,$07 OUT (COL3R),A LD A,$CC OUT (VERBL),A LD HL,BUFSTART ; RESET 300 BAUD LD (POINTER),HL ; BUFFER POINTER ; WAIT FOR USER TO SWITCH TAPES ; WHEN DONE USING ORGANISM WILL PRESS 'GO' KEY REREAD: CUEW: IN A,($17) ; SENSE 'GO' HEY COL. AND $3F ; IS GO KEY DOWN? JR NZ,GOTQ ; (+$11) YES - WE GOT ONE IN A,(HLTPORT) ; READ HLT COLUMN AND A ; CHECK HALT COLUMN JP NZ,TAF ; IF SO ENDIT INC BC ; SWEEP BC TO SHOW LD A,B ; WE ARE WAITING RRCA ; FOR CUE RRCA RRCA AND $07 ; SWEEP ONLY OUT (COL0R),A ; GRAY SCALE JR CUEW ; (-$17) ; WE GOT THE CUE GOTQ: XOR A ; BACK TO OUT (COL0R),A ; BLACK ; NOW WE WAIT FOR 10 CONSECUTIVE 1 BITS TO APPEAR ; THIS WILL IGNORE ANY GARBAGE APPEARING BEFORE THE ; PROGRAM DATA WLDR: LD L,$0A ; (RE)SET BIT CTR WLL: CALL GETBIT ; GET BIT FROM TAPE JR Z,WLDR ; (-$07) ZERO-START OVER DEC L ; ONE-COUNT IT JR NZ,WLL ; (-$08) AWAIT QUOTA ; WE NOW FALL INTO THE ... ; AWAIT LINE NUMBER STATE-IGNORE EVERYTHING UNTIL A LINE ; NUMBER APPEARS - THIS WILL DISRREGARD ANY UNNUMBERED ; COMMANDS ; IF AN UNNUMBERED 'RUN' OR ; :RETURN COMMAND IS FOUND WE ENTER ; THE AWAIT NEXT SEGMENT CUE STATE WLN: CALL GETBYTE ; GET BYTE FROM TAPE NRET: CP ':' ; HAVE WE GOT A COLON? JR Z,COLN ; (+$1a) YEP, TRY FOR :RETURN CP $6A ; 'RUN' COMMAND? JR Z,REREAD ; (-$2f) YEP- THEN QUIT CALL TSTNUM ; IS SHE A NUMBA? JR NC,WLN ; (-$10) NO-IGNORE IT STUF: CALL STUFBUF ; STORE HER AWAY ; WE ARE NO[W] ON A NUMBER ; NOW WE COPY NUMBERS, AND IGNORE SPACES UNTIL A NONSPACE, ; NONNUMERIC IS DETECTED IGNS: CALL GETBYTE ; FETCH ANOTHER VICTIM CALL TSTNUM ; TEST FOR NUMERIC JR C,STUF ; (-$0b) YEP-KEEP LOOKING CP ' ' ; A SPACE PERHAPS? JR Z,IGNS ; (-$0c) IGNORE THE BLANK JR LIN1 ; (+$11) NONBLANK - LEAVE STATE ; TRY FOR :RETURN STATE - WE CAME HERE AFTER ; READING IN A COLON, SO IF WE GET A 'RETURN' ; WE CAN CEASE LOADING THE SEGMENT COLN: CALL GETBYTE ; READ ANOTHER BYTE CP ' ' ; ALLOW JR Z,COLN ; (-$07) INTERMIXED SPACES CP $70 ; :RETURN TOKEN JR NZ,NRET ; (-$29) IF NOT GO BACK JP REREAD ; YEP-END THIS SEG ; READ LINE STATE ; WE WILL HANG OUT HERE UNTIL A NEW LINE COMES IN ; IN WHICH CASE WE WILL GO BACK TO 'AWAIT LINE NUMBER' LINL: CALL GETBYTE ; FETCH NEXT BYTE LIN1: CP RUBOUT ; IF RUBOUT IGNORE IT JR Z,LINL ; (-$07) CALL STUFBUF ; STUFFER IN THE BUFFER CP NL ; IF NEW LINE JR Z,WLN ; (-$3d) WAIT FOR NEXT LINE # JR LINL ; (-$10) ELSE GOFOR NEXT CHAR ; ROUTINE TO TEST FOR CHARACTER BEING NUMERIC TSTNUM: CP '0' ; LESS THAN ZERO? JR C,NN ; (+$03) NO - JUMP CP '9'+1 ; GREATER THAN NINE? RET C ; RETURN CY IF NOT NN: AND A ; CLEAR CY BIT RET ; TO SAY NOT NUMBER ; ROUTINE TO STORE A CHARACTER INTO THE BUFFER STUFBUF: LD HL,(POINTER) ; GET BUFFER POINTER LD (HL),A ; STUFF CHAR WITHIN INC HL ; BUMP POINTER LD (POINTER),HL ; AND SAVE RET ; AND GO HOME ; GET A BYTE FROM AUDIO TAPE ROUTINE GETBYTE: CALL GET0 ; GET A START BIT JR NZ,GETBYTE ; (-$05) WAIT FOR IT LD HL,$0800 ; INIT BIT CTR AND ACCUM BYTL: CALL GETBIT ; FETCH A BIT OR L ; OR IN DATA SO FAR RRCA ; SHIFT OVER LD L,A ; AND SAVE DEC H ; DCR BIT COUNTER JR NZ,BYTL ; (-$09) FILL OUT BYTE RET ; GET BIT ROUTINE ; ; THIS ROUTINE INPUTS A BIT IN 300 BAUD FORMAT ; USING THE BUILT-IN AUDIO INTERFACE CIRCUIT ; IT DOES THIS BY MEASURING THE FREQUENCY ; OF THE INPUT SQUARE WAVES. ; AS 8 CONSECUTIVE SHORT SQUARE WAVES DENOTES A ONE BIT ; AND 4 CONSECUTIVE LONG WAVES DENOTES A ZERO BIT ; WE MAINTAIN COUNTERS FOR EACH TYPE, AND RETURN ; ONE OR ZERO WHEN ENOUGH CYCLES ARE COUNTED ; ; THE ENTRY 'GET0' IS ENTERED WHEN A START BIT IS ; SOUGHT. 'GET0' INSISTS ON RECIEVING A FULL LENGTH ; ZERO WAVE GET0: LD C,$00 ; SYNC ON START BIT NEXW: LD E,$00 ; RESET BIT LENGTH TIMER IN A,(HLTPORT) ; SENSE HALT COLUMN AND A ; IF ANY DOWN JP NZ,TAF ; KICKOUT LD A,(BANGIN) ; GET TAPE DATA LD D,A ; STUFF IN TRACKER G0L: LD A,(BANGIN) ; SENSE IT AGAIN XOR D ; ANY TRANSITION? RRCA JR C,GOTT ; (+$05) JUMP IF SO INC E ; COUNT TIME JR NZ,G0L ; (-$0a) TIMEOUT COND? JR GET0 ; (-$1a) YEP - START OVER GOTT: LD A,D ; LAST TIME TO ACC LD D,E ; SET NEW LAST TIME ADD A,E ; SUM LAST AND NOW [was non-standard ADD E] CP $0F ; GOOD ENOUGH? JR C,NEXW ; (-$1f) NO-KEEP LOOKIN LD BC,$0001 ; YEP-COUNT THAT ZERO JR GBNEXT ; (+$09) AND JOIN GETBIT ; THIS ENTRY IMPOSES NO SPECIAL CRITERIA ; AND IS ENTERED FROM LEADER WAIT AND TO GET ; CHARACTER DATA BITS ; B=ONE COUNTER, C=ZERO COUNTER GETBIT: LD BC,$0000 ; RESET BIT COUNTERS IN A,(HLTPORT) ; ANOTHER HALT COL AND A ; CHECK JP NZ,TAF GBNEXT: LD E,$00 ; RESET BIT TIMER LD A,(BANGIN) ; SAMPLE TAPE DATA LD D,A ; SAVE IN TRACKER TIME: LD A,(BANGIN) ; SAMPLE AGAIN XOR D ; REVEAL TRANSITION RRCA ; IF WE GOT ONE JR C,TRAN ; (+$05) JUMP OUT INC E ; COUNT TIME JR NZ,TIME ; (-$0a) TIMEOUT CHECK JR GETBIT ; (-$1b) TIMEOUT - START OVER ; WE HAVE ONE HALF CYCLE-SO WE GO FOR THE OTHER HALF ; SAME LOGIC AS ABOVE CODE TRAN: LD A,(BANGIN) XOR D RRCA JR NC,GOTB ; (+$05) INC E JR NZ,TRAN ; (-$0a) ; TIM0: JR GETBIT ; (-$27) WE HAVE TIMED OUT ; WE HAVE A FULL WAVE TIME - WE WILL ; CLASSIFY IT AND INCREMENT THE APPROPRIATE BIT ; COUNTER IF THE 'OTHER' BIT COUNTER MEETS ; MINIMUM CRITERION WE WILL RETURN THE 'OTHER' BIT ; VALUE, ELSE IF THE 'NOW' BIT COUNTER IS HIGH ; ENOUGH WE WILL RETURN THE 'NOW' BIT ; IF NEITHER ARE LARGE ENOUGH WE WILL KEEP SAMPLING GOTB: LD A,E CP $0C ; WHICH HAVE WE? JR C,TRY1 ; (+$0d) JUMP IF ONE TRY0: INC C ; COUNT THE ZERO LD A,B ; ENOUGH ONES? CP MIN1 JR NC,RET1 ; (+$12) YES - RETURN 1 BIT LD A,C ; AT MAX ZEROS? CP MAX0 JR C,GBNEXT ; (-$2e) NO - GET MORE CYCLES RET0: XOR A ; RETURN A ZERO BIT RET TRY1: INC B ; COUNT A ONE BIT LD A,C ; ENOUGH ZERO BITS? CP MIN0 JR NC,RET0 ; (-$08) YEP - GO TO ZERO RETURN LD A,B ; MAX ONE BITS? CP MAX1 JR C,GBNEXT ; (-$3b) YEP RET1: XOR A INC A RET ; THIS SEQUENCE IS ENTERED AFTER THE USING ORGANISM ; PRESSES A KEY IN THE HALT COLUMN ; IF THE KEY WAS NOT THE HALT KEY WE GO BACK FOR AN ; ADDITIONAL SEGMENT. IF IT WAS HALT WE CLOSE THE BUFFER ; AND THEN RELOCATE THE BUFFER TO THE HIGHEST POSSIBLE ; ADDRESS, ESTABLISH THE SPECIAL I/O ROUTINES IN ; THE BASIC STACK ZONE, AND MODIFY THE HOOK VECTORS ; POINT AT THEM ; WE THEN CALL BASIC TO CONVERT THE BUFFER TAF: LD SP,STACK ; RESET THE STACK POINTER RRCA ; WAS THAT A HALT? JP NC,REREAD ; NO - GO BACK FOR NEXT SEGMENT XOR A ; DENOTE OUT OF HALT OUT (COL0R),A LD HL,LASTLINE ; CLOSE THE BUFFER WITH LD DE,(POINTER) ; NL,PRINT,NL,$FF LD BC,EOLL-LASTLINE+1 LDIR EX DE,HL ; HL = POINTER ; MOVE BUFFER UP TO THE HIGHEST POSSIBLE ADDRESSES LD DE,LASTBUF+1 CPYL: DEC HL ; DECREMENT POINTERS DEC DE LD A,(HL) ; FETCH SOURCE LD (HL),$00 ; CLEAR SOURCE LD (DE),A ; STORE AT DEST LD A,H ; BACK AT START? CP BUFSTART >> 8 JR NZ,CPYL ; (-$0b) LOOP BACK LD A,L CP BUFSTART & $FF JR NZ,CPYL ; (-$10) IF NOT YET LD (POINTER),DE ; SAVE CORRECTED PTR LD HL,(TXTUNF) ; REMEMBER DATA BENEATH LD (SAVDAT),HL ; TXTUNF LD HL,$5555 ; INITIALIZE PROGRAM LD ($4002),HL ; STORAGE AREA LD HL,$A004 ; AND TXTUNF LD (TXTUNF),HL LD HL,TARGET ; PLUG HOOK VECTORS LD (CHKIO+1),HL ; WITH SPECIAL I/O INC HL ; ROUTINES INC HL LD (OUTCH+1),HL ; MOVE THE SPECIAL I/O ROUTINES ; INTO BASIC STACK AREA LD HL,CODS LD DE,TARGET LD BC,ENDPRG-CODS LDIR JP INIT0 ; ENTER BASIC ; THIS INFORMATION IS APPENDED TO THE TAPE BUFFER ; TO CLOSE IT OFF. IT WILL CLEAR THE SCREEN AFTER ; THE CONVERSION PROCESS IS COMPLETE LASTLINE: DB NL DB $69 ; TOKEN CODE FOR 'CLEAR' DB NL DB $FF ; LIST TERMINATOR EOLL: CODS: JR LCHKIO ; SPECIAL OUTPUT CHARACTER ROUTINE ; IT REFUSES TO DO ANY PRINTING ; IT DOES CHECK TO SEE WHERE IT WAS CALLED FROM ; IF IT WOULD GO BACK TO GL2 IN ; GLED WE WILL SKIP SEVERAL UGLY INSTRUCTIONS ; WHICH WOULD PUT UP A CURSOR EX (SP),HL ; HL=RETURN ADDR PUSH AF ; SAVE A LD A,H ; CHECK FOR CALL CP GL2 >> 8 ; FROM GL2 JR NZ,OK ; (+$0d) LD A,L CP GL2 & $FF JR NZ,OK ; (+$08) ; WE WERE CALLED FROM GL2, SO SHUFFLE STACK AND ; GO BACK AT GL2A POP AF POP HL PUSH BC PUSH HL PUSH DE JP GL2A ; CALL FROM ELSEWHERE - JUST GO HOME OK: POP AF EX (SP),HL RET ; GET CHARACTER ROUTINE - FETCHES CHARACTER ; FROM 300 BAUD BUFFER ; WE STORE THE DATA BENEATH TXTUNF JUST IN ; CASE OU[R] POINTER POINTS THERE LCHKIO: LD HL,(TXTUNF) ; SAVE CURRENT TXTUNF PUSH HL LD HL,(SAVDAT) ; GET BUFFER DATA LD (TXTUNF),HL ; AND FUDGE LD HL,(POINTER) ; GET BUFFER PTR LD A,(HL) ; AND CHARACTER LD (HL),$00 ; CLEAR CHARACTER INC HL ; BUMP PTR LD (POINTER),HL ; SAVE PTR LD HL,(TXTUNF) ; SAVE BUFFER DATA LD (SAVDAT),HL ; AS MAY BE ZEROED POP HL ; RESTORE TXTUNF LD (TXTUNF),HL INC A ; END OF LIST? JR Z,GEOF ; (+$02) YEP JUMP DEC A ; NO - FIXIT RET ; AND GO BACK ; WE ARE DONE - RESET VARIABLES TO ZERO ; ZERO A-Z GEOF: SYSSUK FILL ; UPI FILL memory with data DW VARBGN ; ... Memory Address = 20002 ($4E22) DW $0034 ; ... Byte Count = 52 DB $00 ; ... Data = 0 ; ; RESET HOOK VECTOR SYSSUK MOVE ; UPI MOVE block transfer DW HKVECT ; ... Destination Address = 20114 ($4E92) DW $000E ; ... Byte Count = 14 DW HOOKER ; ... Source Address = 8587 ($218B) ; LD A,$B0 ; RESET VERTICAL OUT (VERBL),A ; BLANK PORT LD A,$2C ; ADD HORIZONTAL OUT (HORCB),A ; COLOR BOUNDARY JP INIT0 ; HALT BASIC ENDPRG: END ; Comment Section [down past END, needs no ';'s] 300 To 2000 BAUD LOADER PROGRAM (C) 1981 Jay Fenton for Astrovision Inc. ---------------------------------------- NOTE: To assemble this program header file named HVGLIB is required. This program is for the Bally Astrocade game console and the AstroBASIC cartridge. End Comments - Changes/Updates (By Adam Trionfo) ------------------------------ Version 1.0 (Dec. 16, 2007) - Program first re-typed from source-code - All program lines correspond to the original program. - All non-standard Z-80 Mnemonics have been changed to standard Z-80 Mnemonics. - There is an assembler warning for line 247 (LD D,E). This line still assembles to $53 (which it is supposed to). I'm not sure why Zmac is giving this error. - Checked, by hand, that this program assembles and matches, byte-for-byte with the listing by Jay Fenton. ; Version 1.2 - Standardized by Richard C. Degler ; Source code re-listing of the file "300BLOAD.asm" ; ; CPU Type: Z80 - loads with ASTRO Basic ONLY! ; ; Created with dZ80 2.0 using script "BallyHVG.LUA" ; ; on Wednesday, 23 of February 2011 at 02:56 AM ; ; This code can be assembled into a usable binary using the ; ZMac assembler using command line "zmac -i -m 300BLOAD.asm" ; - Sorted the EQUates and added note to "Bit Banger Goodies". - Used only $xx for code instead of mix of 0xxH and decimal. - Wow, Adam - you translated this from TDL's 8080 mnemomics! - Assembler's "non-standard syntax" warning was for "ADD E" on old line 248 (not sure why the previous line was flagged) - Corrected two very mino[r] typos in transcribed comments. - Actually assembled this and compared it to earlier versions. more note: This program uses the entire screen (past its area) as a huge Tape Buffer (instead of having a small Ring Buffer), only saving lines that are numbered. Since 300-baud's direct commands (NLN) and .REMarks might have a few numbers in them, these should be edited from the recording if at all possible. ; ***** End of Comments *****