; THIS FILE IS CONTAINS ALL OF THE SUPPORT FILES USED BY DOUBLETALK MAIN CODE ; ALL CODE WRITTEN BY JOHN HARRISON ; *************************************************************************** ; * * ; * FILE #1: my_defs.inc * ; * * ; *************************************************************************** ;I/O DEFINITIONS ; BIT DEFINITIONS FROM CALLING getkeys: START_KEY EQU 7 SELECT_KEY EQU 6 B_KEY EQU 5 A_KEY EQU 4 DOWN_KEY EQU 3 UP_KEY EQU 2 LEFT_KEY EQU 1 RIGHT_KEY EQU 0 DMACODELOC EQU $ff80 ; needed for eyeoh.h ENDBYTE equ $0d ; needed for eyeoh.h ;RAM area allocation chardata equ $c000 ; 1 byte variable internally needed for eyeoh.h ; THE FOLLOWING ALLOCATION FOR pvoice.asm selectmode equ $c080 ; one byte variable = 0 only if recording. wrtimeoutcnt equ $c081 ; two byte variable used internally for delay loop bankno equ $c083 ; one byte variable is flash rom bank number we wish to access end_of_buffer equ $c084 ; two BYTES RESERVED FOR END OF BUFFER VARIABLE end_of_fbuffer equ $c086 ; two bytes reserved for end of flash buffer NumOfBits equ $c088 ; two byte variable LSB is a fraction/256 BitsAlreadyCounted equ $c08a ; two byte variable. LSB is a fraction OnOne equ $c08c RamPat equ $c08d ; 32 bytes HighNibRam equ $c0ad ; 3 bytes internal variable for printing byte values NumWeAreOn equ $c0b0 ; WE RESERVE $C100 - $C200 FOR FLASH ROM ROUTINES LOADED INTO RAM BANKNUMBER EQU 5 ; using bank 5 for no particular reason, except it works. RAMLOC EQU $C100 FLASHRECBUFFER EQU $6200 RECBUFFER EQU $C200 RECBUFFERMSB EQU $c2 ; buffer start for storing pocketvoice recordings RECBUFFERLSB EQU $00 RECBUFENDMSB EQU $df ; buffer end RECBUFENDLSB EQU $FF BUFFERLENMSB EQU RECBUFENDMSB-RECBUFFERMSB BUFFERLENLSB EQU RECBUFENDLSB-RECBUFFERLSB CMDLINE EQU 17 ; print commands on line 17 ; *************************************************************************** ; * * ; * FILE #2: my_mem.asm * ; * * ; *************************************************************************** ; compare COMPARES TWO LOCATIONS IN MEMORY ; INPUT: HL - ONE LOCATION ; DE - OTHER LOCATION ; BC - NUMBER OF BYTES TO COMPARE ; OUTPUT: Z - SET IF LOCATIONS MATCH, RESET IF LOCATIONS DO NOT MATCH compare: ld a, [de] cp a, [hl] ret nz inc hl inc de dec bc ld a, c cp 0 jr nz, compare ld a, b ret z jr compare ; *************************************************************************** ; * * ; * FILE #3: eyeoh.asm * ; * * ; *************************************************************************** ; INPUT/OUTPUT ROUTINES ; BY JOHN HARRISON ; FIRST VERSION: 07/16/02 ; PRINT ONE CHARACTER AT A TIME ; MAKE SURE IT IS GOING TO SHOW ON THE SCREEN ; END OF DISPLAY IS SHOWN BY $0D ; INPUT: HL = CONTENTS TO PRINT ; D = LINE TO PRINT TO ; E = COLUMN TO PRINT TO ; ; OUTPUT: print: push hl ; save pointer to ROM contents to print ld hl, $97ff-SCRN_VX_B ld bc, SCRN_VX_B ld a,d .skip_line: add hl, bc dec a jr nz, .skip_line ; when finished, hl will point to the correct line ld d,0 add hl, de ; now hl points to actual memory location .next_char: ld a, e cp SCRN_X_B+1 jr z, .next_line ; no more characters on this line, scroll to next .cont_scroll: ld c, e ; store what column we are on in c ld d,h ld e, l ; de points to memory location pop hl ; hl points to character in ROM we wish to print call mem_CopyVBYTE ret z ; we found the last character push hl ld h, d ld l, e inc hl ld e, c inc e jr .next_char .next_line: ld e,1 ld bc, SCRN_VX_B-SCRN_X_B add hl, bc ld bc, $9800+(SCRN_Y_B)*SCRN_VX_B ; ONE BEYOND THE LAST LINE ld a,b cp h jr nz, .cont_scroll ; HL < BC SO WE ARE NOT THROUGH ld a,c cp l jr nz, .cont_scroll ; HL = BC WHICH MEANS WE HAVE SCROLLED ALL OF THE LINES ld a,0 call scroll ld hl, $9800+(SCRN_Y_B*SCRN_VX_B)-SCRN_VX_B ld e, 1 jr .cont_scroll ; SCROLL ROUTINE ; INPUT: A = LINES ON TOP TO PROTECT ; DESTROYS A, BC, DE, HL scroll: ld hl, $9800-SCRN_VX_B ld bc, SCRN_VX_B inc a inc_hl: add hl, bc ; JUMP TO NEXT LINE dec a jr nz, inc_hl scroll_next: ld d, h ld e, l ; DE = LINE ABOVE WE WILL SCROLL TO add hl, bc ; HL = LINE WE ARE SCROLLING FROM ld bc, $9800+(SCRN_Y_B+1)*SCRN_VX_B ; ONE BEYOND THE LAST LINE ld a,b cp h jr nz, scroll_line ; HL < BC SO WE ARE NOT THROUGH ld a,c cp l ret z ; HL = BC WHICH MEANS WE HAVE SCROLLED ALL OF THE LINES scroll_line: ld c, SCRN_X_B ; C COUNTS DOWN COPYING OF VISABLE BYTES push hl ; STORE BEGINNING OF LINE scroll_do: lcd_WaitVRAM ld a, [HL+] ; LOAD A WITH CONTENTS OF HL AND INCREMENT HL ld [DE], a inc de dec c jr nz, scroll_do pop hl ld bc, SCRN_VX_B jr scroll_next mem_CopyVBYTE: di lcd_WaitVRAM ld a, [hl+] cp ENDBYTE ret z ld [de], a ei ret ;************************* ; INPUT ROUTINES ;************************* ; keywait RETURNS WHATEVER KEY IS BEING PRESSED, AND RETURNS THIS VALUE ONLY ONCE, NO ; MATTER HOW LONG THE KEY IS PRESSED. ; THE ROUTINE DESTROYS HL, B. keywait: halt ; SAVE BATTERY. IS THIS A GOOD WAY TO DO THIS? nop call getkeys ld hl, chardata cp [hl] jr z, keywait ld hl, chardata ld [hl], a cp 0 jr z, keywait ret getkeys: ; GETKEYS CODE ADAPTED FROM APOC NOW ld a, P1F_5 ; SET BIT 5 HIGH ldh [rP1], a ; READ P15 ldh a, [rP1] ; GET RESULTS ld a, [rP1] ; RESULTS MIGHT TAKE A FEW CYCLES TO GET cpl ; COMPLEMENT A and $0f ; ONLY FIRST 4 BITS HAVE MEANING swap a ; PUT MEANINGFUL BITS IN UPPER NIBBLE ld b,a ; STORE RESULT IN B ld a, P1F_4 ; SET BIT 4 HIGH ldh [rP1], a ; READ P14 ldh a, [rP1] ; Get RESULTS ldh a, [rP1] ldh a, [rP1] ldh a, [rP1] ldh a, [rP1] ldh a, [rP1] ; RESULTS MIGHT TAKE A FEW CYCLES TO GET cpl and $0f or b ; now old results are in upper nibble of A swap a ; NOW OLD RESULTS ARE IN LOWER NIBBLE, NEW IN UPPER NIBBLE ret ; *************************************************************************** ; * * ; * FILE #4: pvoice.asm * ; * * ; *************************************************************************** ; *** POCKET VOICE ROUTINES *** initpv: ; INITIALIZE POCKET VOICE. DESTROYS HL ld hl,0 ld [hl],0 ; SET SRAM OFF SO WE CAN WRITE TO $A000 REGISTERS ld hl, $a003 ld [hl], 0 ; 0 OFFSET FOR BANK $6XXX AND $7XXX ; ld hl, $6000 ld [hl], 0 ; ld hl, $7000 ld [hl],0 ld hl, $a000 ld [hl], $80 ; ENABLE SOUND CHIP call triggerplay ret triggerplay: ; THIS ROUTINE MUST BE CALLED BEFORE POCKET VOICE CAN ; PLAYBACK FILES (COULD BE SKIPPED IF WE RECORD FIRST) ld de, $200 ; HOW LONG DO WE DELAY? ld a, $82 ; ENABLE RECORD ploop: ld [$a000], a xor $20 ; WHAT PURPOSE DOES THIS SERVE? ld b, a ; STORE CONTENTS OF XORED ACCUMULATOR call delay200us dec de ld a,e or d cp 0 ld a, b jr nz, ploop call geneop ret delay200us: push de ld de, $18 ; 200US jr delayloop delayoneframe ; SAME AS DELAY10MS delay10ms: push de ld de, $600 ; 10 TO 12 MS delayloop: dec de ld a,e cp 0 jp nz, delayloop ; COULD THIS AND THE ONE BELOW BE JR INSTEAD OF JP? ld a,d cp 0 jp nz, delayloop pop de ret geneop: ld a, $84 ld [$a000],a ; IS THIS NECESSARY FOR RECORDING? call delayoneframe geneopplay: ld a, $80 ld [$a000],a ret ; REC RECORDS FROM MIC UNTIL A KEY IS RELEASE OR BUFFER IS FULL. ; OUTPUT: HL = BUFFER LENGTH rec: ld a, $82 ; RECORD MODE ld [$a000], a ld de, RECBUFFER ld bc, 0 recloop: ld a, [$a000] bit 3, a ; BIT 3 IS SET WHEN DATA IS READY TO BE READ jp z, recloop ld a, [$a001] ; GET DATA INTO A ld [de], a ld a, b cp BUFFERLENMSB jr nz, ContRecLoop ld a, c cp BUFFERLENLSB jr z, recfull ContRecLoop: push bc call getkeys pop bc cp 0 jr z, recfull inc de inc bc jr recloop recfull: push bc pop hl call geneop ; MAYBE I ONLY HAVE TO CALL GENEOPPLAY? ret ; PLAY THROUGH POCKETVOICE SPEAKER ; INPUT: DE = START OF BUFFER ; HL = LENGTH OF BUFFER (2 BYTES) play: ld a, $81 ld [$a000], a ld bc, 0 playloop: ld a, [$a000] bit 3,a ; BIT 3 IS SET WHEN PV IS READY FOR ANOTHER BYTE TO PLAY jr z, playloop ld a, [de] ld [$a001], a inc de inc bc ld a, l cp c jr nz, playloop ld a, h cp b jr nz, playloop call geneop ret ; REVERSE PLAY THROUGH POCKETVOICE SPEAKER ; INPUT: DE = START OF BUFFER ; HL = 2 BYTE LENGTH OF BUFFER revplay: ld a, $81 ld [$a000], a push hl add hl, de ld d, h ld e, l pop hl ld bc, 0 revplayloop: ld a, [$a000] bit 3,a ; BIT 3 IS SET WHEN PV IS READY FOR ANOTHER BYTE TO PLAY jr z, revplayloop call reverser ld [$a001], a dec de inc bc ld a, l cp c jr nz, revplayloop ld a, h cp b jr nz, revplayloop call geneop ret ; REVERSES A BYTE I.E. BIT 7 --> 0 BIT 6 --> 1 ETC. reverser: ld a, [de] push bc ld b, a xor a bit 7, b jr nz, set0 cont0: bit 6, b jr nz, set1 cont1: bit 5, b jr nz, set2 cont2: bit 4, b jr nz, set3 cont3: bit 3, b jr nz, set4 cont4: bit 2, b jr nz, set5 cont5: bit 1, b jr nz, set6 cont6 bit 0, b pop bc ret z set 7,a ret set0: set 0, a jr cont0 set1: set 1, a jr cont1 set2: set 2, a jr cont2 set3: set 3, a jr cont3 set4: set 4, a jr cont4 set5: set 5, a jr cont5 set6: set 6,a jr cont6 ; POCKETVOICE ROUTINES PART II ADAPTED FROM BUNG ; THESE ROUTINES USE FLASH ROM FOR INPUT AND OUTPUT ; THEY MUST BE MOVED INTO C000-E000 AREA IN ORDER TO WORK. ; LOAD THE POCKETVOICE FLASH ROUTINES INTO $C100 RAM loadflashcode: ld de, RAMLOC ld hl, beginpvflashroutines ld bc, endpvflashroutines-beginpvflashroutines call mem_Copy ret ; WRITEPAGE WRITES 256 BYTES FROM HL TO DE. DE IS A LOCATION IN FLASH ROM. ; E MUST BE 0 WHEN ROUTINE IS CALLED. I.E. POINT TO THE BEGINNING OF A PAGE OF MEMORY. ; WRITEPAGE ALSO HAS THE ABILITY TO RECORD FROM THE MICROPHONE AT THE SAME TIME. ; DIGITAL RECORDING IS RECORDED AT LOCATION BC ; INPUT: HL - SOURCE (MUST POINT TO RAM LOCATION C000-E000) ; DE - DESTINATION (6000-7FFF AND E = 0 I.E. POINT TO A FULL PAGE) ; BC - DESTINATION OF DIGITIZED RECORDING, IF WE ARE RECORDING ; OUTPUT: HL, DE, AND BC WILL POINT TO ONE BEYOND THE LAST AREA THEY HAVE ACCESSED. ; VARIABLES: selectmode - 0 TO RECORD SOUND FROM MIC. <>0 FOR JUST MOVING MEMORY. ; wrtimeoutcnt - INTERNAL 2 BYTE DELAY COUNTER ; bankno - WHAT BANK IN FLASH ROM WE WISH TO ACCESS beginpvflashroutines: writepage: ld a, $a0 call flashcom - beginpvflashroutines + RAMLOC w1: ld a, [hl+] ld [de], a inc de ld a, e and 3 jr nz, w1 ; THIS IS A TIMING THING. EVERY FOURTH TIME THROUGH THE LOOP WE CHECK ; TO SEE IF WE ARE SIMULTANEOUSLY RECORDING AND NEED TO GRAB A BYTE FROM ; THE MIC. ld a, [selectmode] cp 0 jr nz, w2 ; JUMP IF WE ARE NOT RECORDING call readlvoicedata - beginpvflashroutines + RAMLOC ; CALL IN RAMSPACE w2: ld a, e cp 0 ; HAVE WE COPIED 256 BYTES? jr nz, w1 ; NO? CONTINUE LOOP jr waitwinbondok ; NECESSARY DELAY BEFORE WE CAN CONTINUE. ; ROUTINE FOR writepage READS A BYTE FROM THE MICROPHONE, IF ONE IS AVAILABLE. readlvoicedata: ld a, [$a000] bit 3, a jr nz, r1 ; JUMP IF A BYTE IS READY FOR US scf ret r1: ld a, [$a000] ld [bc], a inc bc scf ccf ret ; DELAY ROUTINE CALLED AFTER WE HAVE COPIED A PAGE OF MEMORY. ; THIS ROUTINE ALLOWS US TO CONTINUE TO RECORD SIMULTANEOUSLY. waitwinbondok: push hl xor a ld [wrtimeoutcnt], a ; SET VARIABLE LSB TO 0 ld a, 2 ld [wrtimeoutcnt+1], a ; SET VARIABLE MSB TO 2 ld hl, $7fff waitwinbondok1: ld a, [hl] xor [hl] and $40 jr z, wa1 ld a, [selectmode] cp 0 jr nz, wa0 call readlvoicedata-beginpvflashroutines+RAMLOC wa0: ld a, [wrtimeoutcnt] sub 1 ld [wrtimeoutcnt], a ld a, [wrtimeoutcnt+1] sbc 0 ld [wrtimeoutcnt+1], a jr nc, waitwinbondok1 pop hl scf ccf ret wa1: pop hl scf ret ; INITIALIZE FLASH MEMORY. CALLED BY writepage flashcom: push af ld a, $82 ld [$a000], a ld a, 2 ld [$6000], a xor a ld [$7000], a ld a, $c2 ld [$a000], a ld a, $aa ld [$7555], a ld a, $82 ld [$a000], a ld a, 1 ld [$6000], a ld a, $c2 ld [$a000], a ld a, $55 ld [$6aaa], a ld a, $82 ld [$a000], a ld a, 2 ld [$6000], a ld a, $c2 ld [$a000], a pop af ld [$7555], a ld a, $82 ld [$a000], a ld a, [bankno] ; SET CURRENT ROM BANK ld [$6000], a ld a, $c2 ld [$a000], a ret endpvflashroutines: ; *************************************************************************** ; * * ; * FILE #5: strings.asm * ; * * ; *************************************************************************** MainTitle: DB "DoubleTalk" db ENDBYTE Play1L3: db "PLAYER 1" db ENDBYTE Play1L5: db " records" db ENDBYTE Play1L7: db " plays forward" db ENDBYTE Play1L8: db " reverses" db ENDBYTE Play1L10: db "