;---------------------------------------------------; ;---------------------------------------------------; ; Name: PONG.ASM ; ; Use: DTI's version of the PONG game ; ;---------------------------------------------------; ; Copyright: (C)2012 DTI ; ; Dysfunctional Technologies, Inc. ; ; All Rights Reserved ; ;---------------------------------------------------; ; Author: Timothy S. Carlson ; ; Dysfunctional Technologies, Inc. ; ; Date: December 24, 2012 ; ; Version: V3.07 ; ;---------------------------------------------------; ;---------------------------------------------------; ; WEBSITE: www.dysfunctionaltechnologies.com ; ; EMAIL: tscarlson@gmail.com ; ; ; ; You are welcome to use this code as you see fit, ; ; however - not to be used in for-profit products ; ; unless we have come to a monetary agreement. ; ; ; ; If this code is used, credit given is appreciated ; ;---------------------------------------------------; ;---------------------------------------------------; ; VERSION LOG: ; ; V3.00: Modified characters, character placement, ; ; and field to look more like the real PONG ; ; V3.01: Renamed to PIC-PONG ; ; - Added 64x224 mode for copyright message ; ; - Added piezo speaker for sounds ; ; - Added ball 'slow-down' method ; ; - Added special dot as court divider ; ; V3.02: Fixed my program memory page issues. ; ; - Revamped _Draw_Scores. Cleaner, faster. ; ; - Redid title - "PONG FOR THE 12F1840" ; ; - Added _DEBUG_ turns on/off GP2 VSYNC Pulse; ; - Moved some procs to high page: ; ; - _Draw_Title ; ; - _Clear_Court ; ; - _Copyright ; ; - _Initialize_System ; ; - More comments ; ; - Modified comments discussing the number of; ; lines, what they do, and how long (in ms) ; ; for a complete video frame. ; ; 260 lines * 64us each = 16.64ms per frame ; ; The current timing is ~16.645ms per frame ; ; - General Cleanup ; ; - Added the software version number at the ; ; bottom right of the screen, in the copy- ; ; right strip. ; ; V3.03: Updated version number display to V3.03 ; ; - Adding more comments ; ; - Changed references to 'Half_Line' and ; ; 'Full_Line' in some proc titles to ; ; '30us_Line' and '60us_Line' respectively. ; ; (_Blank_Half_Line => _Blank_30us_Line) ; ; - Moved some line generation procs to high ; ; page, added PAGESELs, adjusted timings. ; ; - _Blank_60us_Line ; ; - _Blank_30us_Line ; ; - _Special_30us_Line ; ; - _Inverted_30us_Line ; ; - Everything possible has been moved to the ; ; high page of memory, with the exceptions: ; ; - _Update_Paddle_1 ; ; - _Update_Paddle_2 ; ; - _Update_Ball ; ; I am only using 655 words in the low page ; ; of program memory now (H'000'-H'28E') out ; ; of 4096 bytes (2048 words). The high page ; ; is packed - H'800'-H'D92'. I left the ; ; above procs in the low page as I will be ; ; making modifications / enhancements to ; ; these routines in the near future. ; ; - NOTE: If you see what appears to be stray ; ; NOPs strewn about in the code - DON'T ; ; REMOVE THEM. They are there for video ; ; timings purposes. Remove them and DOOM! ; ; V3.04: Updated version number display to V3.04 ; ; - Changed the use of Timer0 (8bit) from ; ; loading zero and waiting for count to ; ; loading (inverse) count and waiting for ; ; overflow flag (TMR0IF) in INTCON. ; ; - Created _Clear_Items and _Draw_Items. ; ; _Clear_Items clears ball, paddles, scores ; ; _Draw_Items draws ball, paddles, scores ; ; - Removed _Update_Scores, since one half ; ; went into _Clear_Items and the other half ; ; went into _Draw_Items. There was nothing ; ; left, except for 60us line generation, ; ; after that. ; ; V3.05: Updated verion number display to V3.05 ; ; - Changed field size from 32x56 to 32x48 ; ; - Changed VIDEO_BUFFER start from H'2010' to; ; H'2020' to recover 16 bytes of data memory; ; that are now available due to small field ; ; - Added dynamic creation of blank lines ; ; depending on screen size. This will keep ; ; the screen centered (vertically) in the ; ; viewable area of the video frame and keep ; ; the video frame at 60hz ; ; - Added court sidelines so that the limits ; ; of the court can be easily determined no ; ; matter the size of the field. ; ; - Added 'SERVICE' markers (arrows next to ; ; the scores) to easily determine who's turn; ; it is to serve. Last one scored serves. ; ; - Reduced size of title screen and changed ; ; title back to just 'PONG'. Title screen ; ; was too large and the time to draw (or ; ; clear) was blowing WAY past the 60us limit; ; - Changed wall collision detection so that ; ; Ball_Dir_Y can be something other that 1 ; ; or -1. This opens the door to implementing; ; 'english' on the ball ; ; - Service is now done from the paddle, not ; ; center court. And the beginning Ball_Y ; ; position is centered with the paddle ; ; - Ball angle on service (Ball_Dir_Y at 1 or ; ; for the left paddle, -1 or -2 for the ; ; right paddle) depends on paddle position ; ; - The starting position of the scores has ; ; been dropped one line to keep the score ; ; display from bumping against the court ; ; side line. ; ; - With a field of 32x48, PONG has been ; ; testing on a Sony PS1 LCD monitor, a small; ; PHILIPS LCD TV, and a regular CRT TV which; ; all work well. However, a 32" Chinese made; ; LCD TV does not work - maybe because it ; ; wants 50hz? Any feedback on various TVs ; ; used with PONG would be appreciated. ; ; - Added a check to see if the left or right ; ; button is being held - this keeps from ; ; holding the button down and continuously ; ; serving the ball. ; ; - Even MORE comments added. I sure hope I ; ; remove all of the old (irrelevent) ones. ; ; - Back to the large graphics to the title. ; ; I split it into two 60us lines. Also did ; ; a lot of tricks to reduce the instruction ; ; count. _Clear_Screen replaces _Clear_Items; ; and will clear the screen OR display the ; ; title at the appropriate time. ; ; - EVERYTHING uses TIMER0 now, except for ; ; generating a positive 2us sync pulse. Not ; ; enough cycles to incorporate the timer. ; ; - All loose code and commented out lines ; ; removed. All timings at spec. RELEASE! ; ; V3.06: Updated verion number display to V3.06 ; ; - Corrected a few bugs in ball/paddle ; ; collision detection. ; ; - Corrected a bug in _Clear_Screen ; ; - Moved all 30us stuff to a procedure called; ; _Vertical_Sync. ; ; - Split the code as evenly as I could ; ; between the low page and high page of ; ; program memory. Lots of room for editing ; ; now without worrying about bumping the ; ; ceilings. There's around 900 program words; ; free in each page. ; ; - I don't think there are any major bugs - ; ; just enhancements waiting in the wings. ; ; Time to final release and move on! ; ; V3.07: Updated verion number display to V3.07 ; ; - Added a blank line and then two white ; ; lines just after the copyright lines. Just; ; because I like it better. ; ; - Fixed the 'shoot off in a horitontal angle; ; when hitting the upper sideline wall' bug.; ; If you saw the V3.06 demo video, it was ; ; occurring frequently and the OCD in me ; ; said "You gotta fix that". ; ; That's it for this version - RELEASE! ; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ; Project Defines ; ;---------------------------------------------------; #DEFINE _PONG.ASM_ ; #DEFINE _MAIN_MODULE_ ; ;---------------------------------------------------; #DEFINE _DEBUG_ FALSE ; #DEFINE _USE_THUMBSTICKS_ TRUE ; ;---------------------------------------------------; ;---------------------------------------------------; ; Includes ; ;---------------------------------------------------; ; This file has some common defines (TRUE, FALSE, ; ; etc.) used throughout the program. It also has the; ; CONFIGURATION_BITS settings for the PIC, which are; ; only processed in the module that has the define ; ; _MAIN_MODULE_. ; ;---------------------------------------------------; #INCLUDE Common.INC ; ;---------------------------------------------------; ;---------------------------------------------------; ; Macros ; ;---------------------------------------------------; DELAY MACRO DTIME ; ;-----------------------------------------------; ; The time munger used EVERYWHERE ; ;-----------------------------------------------; MOVLW DTIME ; MOVWF DTemp ; DECFSZ DTemp, F ; GOTO $-1 ; ;-----------------------------------------------; ENDM ; ; DO_BIT MACRO THISBIT, NOPS ; ;-----------------------------------------------; ; Sets the DAC either WHITE or BLACK ; ; Does a specified delay in NOPs ; ;-----------------------------------------------; ; NOTE: This is used in the higher resolution ; ; COPYRIGHT lines and when generating the ; ; gameplay data lines. ; ;-----------------------------------------------; ; Note that a WHITE bit check is done first and ; ; then a BLACK bit check. If you reverse the ; ; order, things look a bit differently on the ; ; screen. That is because there is a two ; ; instruction delay between writing the bit in ; ; one state or in the other state. Reversing the; ; order (BLACK first, then WHITE) causes black ; ; 'gaps'. This order is most visually appealing,; ; at least to me. ; ;-----------------------------------------------; BTFSC INDF1, THISBIT ; BSF PORTA, VIDEO_0_BIT ; BTFSS INDF1, THISBIT ; BCF PORTA, VIDEO_0_BIT ; #IF NOPS > 0 ; NOP ; #ENDIF ; #IF NOPS > 1 ; NOP ; #ENDIF ; #IF NOPS > 2 ; NOP ; #ENDIF ; #IF NOPS > 3 ; NOP ; #ENDIF ; #IF NOPS > 4 ; NOP ; #ENDIF ; #IF NOPS > 5 ; NOP ; #ENDIF ; #IF NOPS > 6 ; NOP ; #ENDIF ; #IF NOPS > 7 ; NOP ; #ENDIF ; #IF NOPS > 8 ; NOP ; #ENDIF ; #IF NOPS > 9 ; NOP ; #ENDIF ; ;-----------------------------------------------; ENDM ; ; SET_DAC2BIT MACRO COLOR ; ;-----------------------------------------------; ; Sets the 2bit DAC to the desired color ; ; Both bits are done at once, or else some weird; ; transitions on the DAC can be seen. Okay if ; ; just colors (WHITE, GRAY, BLACK), but if a ; ; sync pulse shows up out context, it can really; ; mess up the video timings ; ;-----------------------------------------------; MOVFW PORTA ; ANDLW ~(VIDEO_0 | VIDEO_1) ; IORLW COLOR ; MOVWF PORTA ; ;-----------------------------------------------; ENDM ; ; NEG_SYNC_4US MACRO ; ;-----------------------------------------------; ; 4us Negative Sync Generation ; ;-----------------------------------------------; ; Not only does this do a 4us negative sync, it ; ; also handles the sound generation during the ; ; game. Sounds are produced by toggling GPIO1 ; ; during HSYNCs - if it is toggled during ALL ; ; HSYNCs, you get a high freq (around 7800hz). ; ; If every other HSYNC, the freq is around lower; ;-----------------------------------------------; ; Don't touch this unless you really understand ; ; it. I am trying to keep the number of cycles ; ; equal even when playing sounds. If this is ; ; changed, it could cause 'tearing' of the ; ; video when a sound is playing. ; ;-----------------------------------------------; START_LINE COLOR_SYNC, 4, 6 ; BTFSS System_Status, BUZZ_BIT ; GOTO $+16 ; DECFSZ Buzz_Count, F ; GOTO $+16 ; MOVFW Buzz_Reload ; MOVWF Buzz_Count ; BANKSEL TRISA ; BCF TRISA, RBUTT_BIT ; Set as OUTPUT BANKSEL MEMORY ; MOVLW RBUTT ; XORWF PORTA, F ; DECFSZ Buzz_Dur_LO, F ; GOTO $+16 ; DECFSZ Buzz_Dur_HI, F ; GOTO $+16 ; BCF System_Status, BUZZ_BIT ; GOTO $+15 ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; WAIT_FOR_LINE_DONE 0 ; ;-----------------------------------------------; ENDM ; ; START_LINE MACRO COLOR, LENGTH, ADJUST ; ;-----------------------------------------------; ; Starts a line of COLOR (usually WHITE, BLACK, ; ; or SYNC), for a specified length (usually 30 ; ; or 60) with an adjustment for the length so ; ; the line timings can be 'fudged' ; ;-----------------------------------------------; SET_DAC2BIT COLOR ; MOVLW ~((LENGTH*4)-ADJUST) ; MOVWF TMR0 ; BCF INTCON, TMR0IF ; ;-----------------------------------------------; ENDM ; ; WAIT_FOR_LINE_DONE MACRO NOPS ; ;-----------------------------------------------; ; Wait for this line to complete. NOPs can be ; ; added by setting NOPS to a number > 0. Only a ; ; maximum of 5 NOPs can be added. This is for ; ; 'fudging' the line timings to get them spot-on; ;-----------------------------------------------; BTFSS INTCON, TMR0IF ; GOTO $-1 ; #IF NOPS > 0 ; NOP ; #ENDIF ; #IF NOPS > 1 ; NOP ; #ENDIF ; #IF NOPS > 2 ; NOP ; #ENDIF ; #IF NOPS > 3 ; NOP ; #ENDIF ; #IF NOPS > 4 ; NOP ; #ENDIF ; ;-----------------------------------------------; ENDM ; ; NEG_SYNC_2US MACRO ; ;-----------------------------------------------; ; 2us Negative Sync Generation ; ;-----------------------------------------------; ; Used during VSYNC only. ; ;-----------------------------------------------; START_LINE COLOR_SYNC, 2, 6 ; WAIT_FOR_LINE_DONE 1 ; ;-----------------------------------------------; ENDM ; ; POS_SYNC_2US MACRO ; ;-----------------------------------------------; ; 2us Positive Sync Generation ; ;-----------------------------------------------; ; Using during VSYNC only. ; ; There is not enough time to use TIMER0 ; ;-----------------------------------------------; SET_DAC2BIT COLOR_BLACK ; ;-----------------------------------------------; ; These NOPs set the timing for the 2us pulse ; ;-----------------------------------------------; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; ;-----------------------------------------------; ENDM ; ; PLAY_SOUND MACRO FREQUENCY, DURATION ; ;-----------------------------------------------; ; This will play a sound of a specified ; ; frequency for a specified duration ; ; The lower the frequency number, the higher ; ; the frequency. Duration is also a function ; ; of the frequency number, so if frequency goes ; ; up, adjust the duration down. ; ;-----------------------------------------------; ; Sound is played during 4us HORIZONTAL SYNC ; ; times of the video signal. There is a short ; ; period during VERTICAL SYNC where nothing is ; ; done with sound because there ARE no 4us ; ; HSYNCs. There are 2us HSYNCs during VSYNC, but; ; there isn't enough time to process the sound ; ; code without stretching out the 2us HSYNCs ; ; beyond 2us, and that will mess up the video ; ; timings. The total time between the last 4us ; ; HSYNC before VSYNC and the first 4us HSYNC ; ; after VSYNC is only ~512us, so it's barely ; ; noticable. After all, it's only a game... ; ;-----------------------------------------------; ; NOTE that a FREQUENCY of 0 is treated as a ; ; frequency of 256. 0<=Freq<=255. The count is ; ; decremented BEFORE it is checked to be 0, so ; ; starting with 0 will dec, see 255, continue ; ; loop. Just so you are warned. ; ;-----------------------------------------------; MOVLW FREQUENCY ; MOVWF Buzz_Count ; MOVWF Buzz_Reload ; MOVLW LOW DURATION ; MOVWF Buzz_Dur_LO ; MOVLW HIGH DURATION ; MOVWF Buzz_Dur_HI ; BSF System_Status, BUZZ_BIT ; ;-----------------------------------------------; ENDM ; ;---------------------------------------------------; ;---------------------------------------------------; ; Defines ; ;---------------------------------------------------; ; You have to chose between using all buttons, ; ; or using a thumbstick with a button. I might ; ; be able to figure out a way to automatically ; ; determine which is connected, but for now you ; ; will just have to decide which you want, set ; ; _USE_THUMBSTICKS_ to either TRUE or FALSE, and; ; re-compile the project. ; ;-----------------------------------------------; #IF _USE_THUMBSTICKS_ ; #DEFINE RJOY H'01' ; Right THUMBSTICK #DEFINE RJOY_BIT 0 ; GPIO 0 - PIN 7 #DEFINE RBUTT H'02' ; Right BUTTON #DEFINE RBUTT_BIT 1 ; GPIO 1 - PIN 6 #DEFINE LJOY H'04' ; Left THUMBSTICK #DEFINE LJOY_BIT 2 ; GPIO 2 - PIN 5 #DEFINE LBUTT H'08' ; Left BUTTON #DEFINE LBUTT_BIT 3 ; GPIO 3 - PIN 4 #ELSE ;!_USE_THUMBSTICKS_ ; #DEFINE RBUTT_1 H'01' ; Right BUTTON 1 #DEFINE RBUTT_1_BIT 0 ; GPIO 0 - PIN 7 #DEFINE RBUTT_2 H'02' ; Right BUTTON 2 #DEFINE RBUTT_2_BIT 1 ; GPIO 1 - PIN 6 #DEFINE LBUTT_2 H'04' ; Left BUTTON 2 #DEFINE LBUTT_2_BIT 2 ; GPIO 2 - PIN 5 #DEFINE LBUTT_1 H'08' ; Left BUTTON 1 #DEFINE LBUTT_1_BIT 3 ; GPIO 3 - PIN 4 #ENDIF ;_USE_THUMBSTICKS_ ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 2bit DAC definitions. The 2bit DAC is just a ; ; pair of resistors on two GPIOs, which feeds ; ; the VIDEO out. ; ;-----------------------------------------------; #DEFINE VIDEO_1 H'10' ; 1K ohm #DEFINE VIDEO_1_BIT 4 ; GPIO 5 - PIN 2 #DEFINE VIDEO_0 H'20' ; 470 ohm #DEFINE VIDEO_0_BIT 5 ; GPIO 4 - PIN 3 ; #DEFINE COLOR_WHITE (VIDEO_0 + VIDEO_1) ; #DEFINE COLOR_BLACK VIDEO_1 ; #DEFINE COLOR_GRAY VIDEO_0 ; #DEFINE COLOR_SYNC 0 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; There are 224 lines created during _Data_Lines; ; However, because of memory limitations, I ; ; cannot allocate enough memory for the video ; ; buffer. So - I do have enough memory for 56 ; ; lines - 1/4 of 224 - so we display each line ; ; of data 4 times. ; ;-----------------------------------------------; #DEFINE MAX_LINES 56 ; DON'T EXCEED 56 ;-----------------------------------------------; ; Make certain NUM_LINES is an even number so ; ; all of the math works out properly. Make sure ; ; NOT to exceed the MAX_LINES value. And don't ; ; change NUM_LINES for less than 9 - that's the ; ; paddle height, so that will probably break it.; ; But then - the paddle height is adjustable ; ; with just changing a define (below), so - who ; ; knows! ; ;-----------------------------------------------; #DEFINE NUM_LINES 48 ; DON'T EXCEED 48 ;-----------------------------------------------; ; ;-----------------------------------------------; ; This is my method of making the game easier or; ; harder - either I update and draw the ball ; ; every frame (fast ball), or every other frame ; ; (not as fast), or every 3rd frame (normal ; ; ball) or higher for slower. Set MAX_BALL_WAIT ; ; to the desired speed (1=fast, 2=not as fast, ; ; 3=normal, 4=slower, etc.). This is hardcoded ; ; right now, a change requires a recompile. I ; ; have plans to allocate another precious byte ; ; of data memory so that the ball speed can be ; ; changed by a menu item. ; ;-----------------------------------------------; #DEFINE DRAW_BALL_BIT 0 ; #DEFINE MAX_BALL_WAIT 3 ; ; ;-----------------------------------------------; ; Just a bunch of hardcoded starting points, ; ; sizes, and bit-munching stuff for the various ; ; graphics. ; ;-----------------------------------------------; ; I use the PIC's LINEAR MEMORY scheme to create; ; a contiguous video buffer. Grab the MicroChip ; ; documentation and read up. Then go search on ; ; the web for some docs that will really explain; ; it for you. ; ;-----------------------------------------------; #DEFINE VIDEO_BUFFER_START H'2030' ; #DEFINE FIELD_HEIGHT NUM_LINES ; #DEFINE FIELD_WIDTH 32 ; #DEFINE LEFT_SCORE_START H'05' ; #DEFINE RIGHT_SCORE_START H'06' ; #DEFINE LEFT_PADDLE_START H'00' ; #DEFINE LEFT_PADDLE_BIT H'40' ; #DEFINE LEFT_PADDLE_MASK H'BF' ; #DEFINE RIGHT_PADDLE_START H'03' ; #DEFINE RIGHT_PADDLE_BIT H'02' ; #DEFINE RIGHT_PADDLE_MASK H'FD' ; #DEFINE PADDLE_HEIGHT 9 ; #DEFINE BALL_HEIGHT 3 ; #DEFINE SERVICE_1_START H'04' ; #DEFINE SERVICE_2_START H'07' ; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; USER_DATA_1 UDATA H'020' ; ;---------------------------------------------------; Ball_X res 1 ; 20 Ball_Y res 1 ; 21 Ball_Dir_X res 1 ; 22 Ball_Dir_Y res 1 ; 23 Paddle_1_Y res 1 ; 24 Paddle_2_Y res 1 ; 25 Score_1 res 1 ; 26 Score_2 res 1 ; 27 Ball_Wait res 1 ; 28 ;---------------------------------------------------; ; Bit definitions for System_Status ; ;---------------------------------------------------; #DEFINE BUZZ H'01' ; #DEFINE BUZZ_BIT 0 ; #DEFINE P1_SERVICE H'02' ; #DEFINE P1_SERVICE_BIT 1 ; #DEFINE P2_SERVICE H'04' ; #DEFINE P2_SERVICE_BIT 2 ; #DEFINE P1_PRESSED H'08' ; #DEFINE P1_PRESSED_BIT 3 ; #DEFINE P2_PRESSED H'10' ; #DEFINE P2_PRESSED_BIT 4 ; ;---------------------------------------------------; System_Status res 1 ; 29 ;---------------------------------------------------; ; Consume Left_Overs / Smaller_Screen for your data ; ; variables as need. LO/SS is just here to pad to ; ; push Video_Buffer1 to the proper spot. ; Left_Overs res 6 ; 2A-2F ;---------------------------------------------------; ; Only 6 bytes left - 2A-2F ; ;---------------------------------------------------; Smaller_Screen res 32 ; 30-4F ;---------------------------------------------------; ; I've pushed the VIDEO_BUFFER to H'2020', since the; ; field has become smaller (32x48 vs 32x56). The ; ; required size of the VIDEO_BUFFER is also less, so; ; this will give up 24 more bytes of data memory for; ; use in game programming. ; ;---------------------------------------------------; ; 16 additional bytes left (smaller screen) - 30-3F ; ;---------------------------------------------------; ; We don't access the Video_BufferX arrays directly,; ; we use LINEAR PAGE memory through the FSR register; ; LINEAR PAGE memory groups the data memory at 0x20,; ; 0xA0, and Ox120 into a contiguous linear page. ; ; Note that the shared memory (at the top 16 bytes ; ; of each page) is NOT included in the LINEAR PAGE ; ; memory mapping. ; ;---------------------------------------------------; ; MEMORY MAP - LINEAR PAGE MEMORY - 240 bytes total ; ; 0x2000-0x204F - 0x020-0x06F 80 bytes ; ; 0x2050-0x20BF - 0x0A0-0x0EF 80 bytes ; ; 0x20A0-0x20EF - 0x120-0x16F 80 bytes ; ;---------------------------------------------------; ; Since out max lines (now) is 48, we need 48x8 ; ; (192) bytes of memory for the screen buffer. This ; ; leaves us with 48 bytes of data memory for program; ; variables, plus the 16 in shared memory for 64! ; ;---------------------------------------------------; Video_Buffer1 res 32 ; 50-6F ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; USER_DATA_2 UDATA H'0A0' ; ;---------------------------------------------------; Video_Buffer2 res 80 ; A0-EF ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; USER_DATA_3 UDATA H'120' ; ;---------------------------------------------------; Video_Buffer3 res 80 ; 120-6F ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; USER_DATA_S UDATA_SHR H'070' ; ;---------------------------------------------------; Temp1 res 1 ; 70 Temp2 res 1 ; 71 DTemp res 1 ; 72 DL_Count res 1 ; 73 Line_Data res 4 ; 74-77 Byte_Count res 1 ; 78 Line_Count res 1 ; 79 Repeat_Count res 1 ; 7A Buzz_Count res 1 ; 7B Buzz_Reload res 1 ; 7C Buzz_Dur_HI res 1 ; 7D Buzz_Dur_LO res 1 ; 7E ;---------------------------------------------------; ; Only 1 bytes left! - 7F ; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ; Reset Vector Code - Entry point from reset ; ;---------------------------------------------------; ;RESET_VECT CODE H'000' ; ;---------------------------------------------------; ; Initialize the hardware and memory elements. ; ; This is a FAR CALL to a proc in the high ; ; page of Program Memory, so it needs the ; ; PAGESEL before and after the CALL to properly ; ; set the upper 2 bits in the program counter. ; ; I am slowly converting ALL CALLs (and some ; ; GOTOs) to having PAGESEL before and after, but; ; the added instruction cycles mess up the video; ; timings in some spots. To be done slowly and ; ; surely. ; ;-----------------------------------------------; ; PAGESEL _Initialize_System ; ; CALL _Initialize_System ; ; PAGESEL $ ; ;-----------------------------------------------; ; Fall through to _Next_Frame ; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ; Interrupt Vector Code ; ; Since we are not using or desire to use interrupts; ; this is not needed. ; ;---------------------------------------------------; ; INT_VECT CODE H'004' ; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; ; User Code in the low page of Program Memory ; ; More user code (USER_CODE_2) can be found in the ; ; high page of Program Memory, starting at H'800' ; ;---------------------------------------------------; USER_CODE_1 CODE H'000' ; ;---------------------------------------------------; _Initialize_System: ; ;---;-----------------------------------------------; ; Initialize Hardware ; ;-----------------------------------------------; BANKSEL OSCCON ; MOVLW B'11110000' ; 32Mhz MOVWF OSCCON ; ; BANKSEL OSCSTAT ; Wait for IS1:MOVFW OSCSTAT ; high speed ANDLW H'79' ; oscillator XORLW H'59' ; to be BTFSS STATUS, Z ; stable and GOTO IS1 ; locked ; BANKSEL ANSELA ; CLRF ANSELA ; ALL I/O as digital #IF _USE_THUMBSTICKS_ ; BSF ANSELA, LJOY_BIT ; BSF ANSELA, RJOY_BIT ; #ENDIF ;_USE_THUMBSTICKS_ ; ; BANKSEL LATA ; CLRF LATA ; ; BANKSEL TRISA ; CLRF TRISA ; BCF TRISA, VIDEO_0_BIT ; Set as OUTPUT BCF TRISA, VIDEO_1_BIT ; Set As OUTPUT #IF _USE_THUMBSTICKS_ ; BSF TRISA, LJOY_BIT ; Set as INPUT BSF TRISA, LBUTT_BIT ; Set as INPUT BSF TRISA, RJOY_BIT ; Set as INPUT BCF TRISA, RBUTT_BIT ; Set as OUTPUT (PIEZO) #ELSE ;!_USE_THUMBSTICKS_ ; BSF TRISA, LBUTT_1_BIT ; Set as INPUT BSF TRISA, LBUTT_2_BIT ; Set as INPUT BSF TRISA, RBUTT_1_BIT ; Set as INPUT BSF TRISA, RBUTT_2_BIT ; Set as INPUT #ENDIF ;_USE_THUMBSTICKS_ ; ; BANKSEL PORTA ; CLRF PORTA ; BCF PORTA, VIDEO_0_BIT ; Set LOW BCF PORTA, VIDEO_1_BIT ; Set LOW #IF _USE_THUMBSTICKS_ ; BSF PORTA, LJOY_BIT ; Set HIGH BSF PORTA, LBUTT_BIT ; Set HIGH BSF PORTA, RJOY_BIT ; Set HIGH BSF PORTA, RBUTT_BIT ; Set HIGH #ELSE ;!_USE_THUMBSTICKS_ ; BSF PORTA, LBUTT_1_BIT ; Set HIGH BSF PORTA, LBUTT_2_BIT ; Set HIGH BSF PORTA, RBUTT_1_BIT ; Set HIGH BSF PORTA, RBUTT_2_BIT ; Set HIGH #ENDIF ;_USE_THUMBSTICKS_ ; ; BANKSEL INTCON ; CLRF INTCON ; ; BANKSEL OPTION_REG ; CLRF OPTION_REG ; ; ;-----------------------------------------------; ; Initialize Timer0 (for counting cycles) ; ;-----------------------------------------------; BANKSEL OPTION_REG ; BCF OPTION_REG, NOT_WPUEN ; BCF OPTION_REG, TMR0CS ; BCF OPTION_REG, PSA ; prescaler to timer0 BCF OPTION_REG, PS2 ; BCF OPTION_REG, PS1 ; 000 - 250ns BCF OPTION_REG, PS0 ; BANKSEL TMR0 ; CLRF TMR0 ; ; ;-----------------------------------------------; ; Initialize Memory ; ;-----------------------------------------------; BANKSEL MEMORY ; CLRF System_Status ; BSF System_Status, P1_SERVICE_BIT ; BSF System_Status, P2_SERVICE_BIT ; MOVLW 0 ; MOVWF Buzz_Count ; MOVWF Buzz_Reload ; MOVLW H'FF' ; MOVWF Buzz_Dur_LO ; MOVLW H'FF' ; MOVWF Buzz_Dur_HI ; MOVLW MAX_BALL_WAIT ; MOVWF Ball_Wait ; MOVLW 0 ; MOVWF Score_1 ; MOVLW 0 ; MOVWF Score_2 ; MOVLW 20 ; MOVWF Paddle_1_Y ; MOVLW 20 ; MOVWF Paddle_2_Y ; MOVLW 15 ; MOVWF Ball_X ; MOVLW 27 ; MOVWF Ball_Y ; MOVLW 0 ; MOVWF Ball_Dir_X ; MOVLW 0 ; MOVWF Ball_Dir_Y ; ; ;-----------------------------------------------; ; Initialize Video Buffer ; ;-----------------------------------------------; PAGESEL _Clear_Screen ; CALL _Clear_Screen ; PAGESEL $ ; ; ;-----------------------------------------------; ; Initialize Other Subsystems ; ;-----------------------------------------------; ; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Next_Frame: ; ;---------------------------------------------------; ; VERTICAL SYNC PULSE Time ; ; This consists of 5 blank half lines, ; ; 4 inverted half lines, and 5 more blank half ; ; lines. This totals 7 full lines of 64us each. ; ; --------------------------------------------- ; ; NOTE: Timing is CRITICAL for a nice, clean ; ; display. If you notice the top part of the ; ; display is skewed or "tearing", your timings ; ; are wrong and need to be adjusted. Make sure ; ; you haven't inadvertently dropped a half frame; ;-----------------------------------------------; ; First, a special blank 30us line. If _DEBUG_ ; ; is enabled, it will produce a pulse on the ; ; GPIO2 pin for debugging purposes (checking the; ; time elapsed for a single video frame). ; ;-----------------------------------------------; PAGESEL _Vertical_Sync ; CALL _Vertical_Sync ; PAGESEL $ ; ;-----------------------------------------------; ; Just a bunch of BLANK LINES, so that the video; ; data doesn't start in the non-display area. ; ; Add or remove lines to adjust the vertical ; ; position of your video. If you add or remove, ; ; make sure to adjust the number of BLANK LINES ; ; which follow the data lines, so that the video; ; stays at 60hz ; ;-----------------------------------------------; MOVLW 14 + ((MAX_LINES - NUM_LINES) * 2) ; MOVWF Line_Count ; _NF_Next_Blank_60us_Line1: ; PAGESEL _Blank_60us_Line ; CALL _Blank_60us_Line ; PAGESEL $ ; DECFSZ Line_Count, F ; GOTO _NF_Next_Blank_60us_Line1 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 2 WHITE lines + 192 DATA lines (assuming ; ; NUM_LINES = 48) + 2 WHITE lines + 1 BLANK line; ;-----------------------------------------------; PAGESEL _Data_Lines ; CALL _Data_Lines ; PAGESEL $ ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Display copyright and software version number.; ; 8 60us lines ; ;-----------------------------------------------; PAGESEL _Copyright ; CALL _Copyright ; PAGESEL $ ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; ;-----------------------------------------------; ; One BLANK line and two WHITE lines: ; ;-----------------------------------------------; PAGESEL _Blank_60us_Line ; CALL _Blank_60us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; ;-----------------------------------------------; PAGESEL _White_60us_Line ; CALL _White_60us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; ;-----------------------------------------------; PAGESEL _White_60us_Line ; CALL _White_60us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; More Blank Lines: ; ;-----------------------------------------------; #IF ((MAX_LINES - NUM_LINES) * 2) > 7 ; MOVLW ((MAX_LINES - NUM_LINES) * 2) - 7 ; MOVWF Line_Count ; _NF_Next_Blank_60us_Line2: ; PAGESEL _Blank_60us_Line ; CALL _Blank_60us_Line ; PAGESEL $ ; DECFSZ Line_Count, F ; GOTO _NF_Next_Blank_60us_Line2 ; #ENDIF ; ;-----------------------------------------------; ;-----------------------------------------------; ; Clear the scores, paddles and ball from the ; ; display - and draw the Title if necessary. ; ; 2 60us lines ; ;-----------------------------------------------; PAGESEL _Clear_Screen ; CALL _Clear_Screen ; 2 blank 60us lines PAGESEL $ ; Screen Clear / Title Draw ;-----------------------------------------------; ; ;-----------------------------------------------; ; All of the game processing is done here, the ; ; last 4 full 60us blank lines ; ;-----------------------------------------------; PAGESEL _Update_Paddles ; CALL _Update_Paddles ; 1 blank 60us line PAGESEL $ ; Paddles Computations PAGESEL _Update_Ball ; CALL _Update_Ball ; 1 blank 60us line PAGESEL $ ; Ball Computations PAGESEL _Draw_Items ; CALL _Draw_Items ; 2 blank 60us lines PAGESEL $ ; Scores/Paddles/Ball Display ;-----------------------------------------------; ; ;-----------------------------------------------; ; So, to summarize (with NUM_LINES = 48): ; ; - 7 VERTICAL SYNC lines (14 30us lines) ; ; - 30 BLANK LINES for screen centering ; ; - 2 WHITE lines for COURT SIDELINE ; ; - 192 DATA lines for GAME FIELD ; ; - 2 WHITE lines for COURT SIDELINE ; ; - 1 BLANK line between SIDELINE & COPYRIGHT ; ; - 8 DATA lines for COPYRIGHT ; ; - 12 BLANK lines for screen centering ; ; - 2 BLANK lines for screen clear / title ; ; - 4 BLANK lines for game processing ; ; ; ; For a total of 260 lines at 64us each, or ; ; 16.637ms, or approximately 60hz. 16.666ms ; ; would be _perfect_. ; ;-----------------------------------------------; ; GOTO _Next_Frame ; ;---------------------------------------------------; ;---------------------------------------------------; _Vertical_Sync: ; ;---------------------------------------------------; ; The _Special_30us_Line will produce a pulse on; ; GPIO2 if the _DEBUG_ flag is set to TRUE. This; ; is for checking the timing of the entire video; ; frame (~60hz, ~16.66ms). ; ;-----------------------------------------------; PAGESEL _Special_30us_Line ; CALL _Special_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 4 blank 30us lines ; ;-----------------------------------------------; PAGESEL _Blank_30us_Line ; CALL _Blank_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; NOP ; NOP ; ;-----------------------------------------------; PAGESEL _Blank_30us_Line ; CALL _Blank_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; NOP ; NOP ; ;-----------------------------------------------; PAGESEL _Blank_30us_Line ; CALL _Blank_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; NOP ; NOP ; ;-----------------------------------------------; PAGESEL _Blank_30us_Line ; CALL _Blank_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; NOP ; NOP ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 4 inverted 30us lines ; ;-----------------------------------------------; PAGESEL _Inverted_30us_Line ; CALL _Inverted_30us_Line ; PAGESEL $ ; PAGESEL _Inverted_30us_Line ; CALL _Inverted_30us_Line ; PAGESEL $ ; PAGESEL _Inverted_30us_Line ; CALL _Inverted_30us_Line ; PAGESEL $ ; PAGESEL _Inverted_30us_Line ; CALL _Inverted_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 5 more blank 30us lines ; ;-----------------------------------------------; PAGESEL _Blank_30us_Line ; CALL _Blank_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; NOP ; NOP ; ;-----------------------------------------------; PAGESEL _Blank_30us_Line ; CALL _Blank_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; NOP ; NOP ; ;-----------------------------------------------; PAGESEL _Blank_30us_Line ; CALL _Blank_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; NOP ; NOP ; ;-----------------------------------------------; PAGESEL _Blank_30us_Line ; CALL _Blank_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; NOP ; NOP ; ;-----------------------------------------------; PAGESEL _Blank_30us_Line ; CALL _Blank_30us_Line ; PAGESEL $ ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Blank_30us_Line: ; ;---------------------------------------------------; ; Used only during VERTICAL SYNC ; ;---------------------------------------------------; ;-----------------------------------------------; ; 30us Blank Signal Generation ; ;-----------------------------------------------; NEG_SYNC_2US ; START_LINE COLOR_BLACK, 30, 12 ; WAIT_FOR_LINE_DONE 1 ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Special_30us_Line: ; ;---------------------------------------------------; ; Used only during VERTICAL SYNC ; ;---------------------------------------------------; ;-----------------------------------------------; ; 30us Blank Signal Generation (SPECIAL) ; ;-----------------------------------------------; ; If _DEBUG_ is TRUE, this will generate a ; ; pulse on GPIO2 for debug purposes - used to ; ; check the timing of a complete video frame. ; ;-----------------------------------------------; NEG_SYNC_2US ; START_LINE COLOR_BLACK, 30, 10 ; ;-----------------------------------------------; ; #IF _DEBUG_ ; BANKSEL TRISA ; BCF TRISA, 2 ; BANKSEL PORTA ; BCF PORTA, 2 ; NOP ; BSF PORTA, 2 ; BANKSEL TRISA ; BSF TRISA, 2 ; BANKSEL MEMORY ; #ENDIF ; _DEBUG_ ; ; ;-----------------------------------------------; ; Wait for this line to complete ; ;-----------------------------------------------; WAIT_FOR_LINE_DONE 3 ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Inverted_30us_Line: ; ;---------------------------------------------------; ; Used only during VERTICAL SYNC ; ;---------------------------------------------------; ;-----------------------------------------------; ; 30us Inverted Signal Generation ; ;-----------------------------------------------; START_LINE COLOR_SYNC, 30, 6 ; WAIT_FOR_LINE_DONE 0 ; ;-----------------------------------------------; ; 2s Positive Sync Generation ; ;-----------------------------------------------; POS_SYNC_2US ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Update_Paddles: ; ;---------------------------------------------------; ;-----------------------------------------------; ; 60us Blank Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 9 ; ;-----------------------------------------------; ; #IF _USE_THUMBSTICKS_ ; _UP1_Update: ; ;-----------------------------------------------; ; ADC Magic (Channel 0) ; ;-----------------------------------------------; BANKSEL ADCON1 ; MOVLW H'60' ; Left Justified MOVWF ADCON1 ; FOSC/64, VREF MOVLW B'00001011' ; AN2, ADC GO, ADC On MOVWF ADCON0 ; BTFSC ADCON0, GO ; Wait for conversion GOTO $-1 ; MOVFW ADRESH ; Get result BANKSEL MEMORY ; ;-----------------------------------------------; ; MOVWF Temp1 ; MOVLW H'60' ; SUBWF Temp1, W ; BTFSS STATUS, C ; DECF Paddle_1_Y, F ; MOVLW H'9F' ; SUBWF Temp1, W ; BTFSC STATUS, C ; INCF Paddle_1_Y, F ; BTFSC Paddle_1_Y, MSB ; CLRF Paddle_1_Y ; MOVLW NUM_LINES - PADDLE_HEIGHT ; SUBWF Paddle_1_Y, W ; BTFSS STATUS, C ; GOTO _UP1_Update_Done ; MOVLW NUM_LINES - PADDLE_HEIGHT ; MOVWF Paddle_1_Y ; _UP1_Update_Done: ; #ELSE ;!_USE_THUMBSTICKS_ ; _UP1_Check_Up: ; CLRW ; XORWF Paddle_1_Y, W ; BTFSC STATUS, Z ; GOTO _UP1_Check_Down ; BTFSS PORTA, LBUTT_1_BIT ; DECF Paddle_1_Y, F ; _UP1_Check_Down: ; MOVLW NUM_LINES - PADDLE_HEIGHT ; XORWF Paddle_1_Y, W ; BTFSC STATUS, Z ; GOTO _UP1_Draw_Paddle ; BTFSS PORTA, LBUTT_2_BIT ; INCF Paddle_1_Y, F ; #ENDIF ;_USE_THUMBSTICKS_ ; ; #IF _USE_THUMBSTICKS_ ; _UP2_Update: ; ;-----------------------------------------------; ; ADC Magic (Channel 0) ; ;-----------------------------------------------; BANKSEL ADCON1 ; MOVLW H'60' ; Left Justified MOVWF ADCON1 ; FOSC/64, VREF MOVLW B'00000011' ; AN0, ADC GO, ADC On MOVWF ADCON0 ; BTFSC ADCON0, GO ; Wait for conversion GOTO $-1 ; MOVFW ADRESH ; Get result BANKSEL MEMORY ; ;-----------------------------------------------; ; MOVWF Temp1 ; MOVLW H'60' ; SUBWF Temp1, W ; BTFSS STATUS, C ; DECF Paddle_2_Y, F ; MOVLW H'9F' ; SUBWF Temp1, W ; BTFSC STATUS, C ; INCF Paddle_2_Y, F ; BTFSC Paddle_2_Y, MSB ; CLRF Paddle_2_Y ; MOVLW NUM_LINES - PADDLE_HEIGHT ; SUBWF Paddle_2_Y, W ; BTFSS STATUS, C ; GOTO _UP2_Update_Done ; MOVLW NUM_LINES - PADDLE_HEIGHT ; MOVWF Paddle_2_Y ; _UP2_Update_Done: ; #ELSE ;!_USE_THUMBSTICKS_ ; _UP2_Check_Up: ; CLRW ; XORWF Paddle_2_Y, W ; BTFSC STATUS, Z ; GOTO _UP2_Check_Down ; BTFSS PORTA, RBUTT_1_BIT ; DECF Paddle_2_Y, F ; _UP2_Check_Down: ; MOVLW NUM_LINES - PADDLE_HEIGHT ; XORWF Paddle_2_Y, W ; BTFSC STATUS, Z ; GOTO _UP2_Draw_Paddle ; BTFSS PORTA, RBUTT_2_BIT ; INCF Paddle_2_Y, F ; #ENDIF ;_USE_THUMBSTICKS_ ; ; ;-----------------------------------------------; ; Wait for this line to complete ; ;-----------------------------------------------; WAIT_FOR_LINE_DONE 0 ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Update_Ball: ; ;---------------------------------------------------; ;-----------------------------------------------; ; 60us Blank Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 10 ; ;-----------------------------------------------; ; _UB_Check_Wait: ; ;-----------------------------------------------; ; This is the delay so the ball isn't so fast ; ;-----------------------------------------------; DECFSZ Ball_Wait, F ; GOTO _UB_Exit ; ; MOVLW MAX_BALL_WAIT ; MOVWF Ball_Wait ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Is the ball moving? (Ball_Dir_X or Ball_Dir_Y ; ; not equal to zero?) If so, update the ball ; ; position. Otherwise, check for serve. ; ;-----------------------------------------------; CLRW ; XORWF Ball_Dir_X, W ; BTFSS STATUS, Z ; GOTO _UB_Update_Ball_X ; CLRW ; XORWF Ball_Dir_Y, W ; BTFSS STATUS, Z ; GOTO _UB_Update_Ball_X ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Check if left player pushed button to serve ; ;-----------------------------------------------; _UB_Check_L_Serve: ; BTFSS System_Status, P1_SERVICE_BIT ; GOTO _UB_Check_R_Serve ; BTFSC PORTA, LBUTT_BIT ; GOTO _UB_Check_L_Unpressed ; BTFSC System_Status, P1_PRESSED_BIT ; GOTO _UB_Check_R_Serve ; BSF System_Status, P1_PRESSED_BIT ; BCF System_Status, P1_SERVICE_BIT ; BCF System_Status, P2_SERVICE_BIT ; MOVLW 1 ; MOVWF Ball_Dir_X ; MOVFW Paddle_1_Y ; ADDLW PADDLE_HEIGHT / 2 ; SUBLW NUM_LINES / 2 ; MOVLW -2 ; BTFSC STATUS, C ; MOVLW 1 ; MOVWF Ball_Dir_Y ; MOVLW 2 ; MOVWF Ball_X ; MOVFW Paddle_1_Y ; ADDLW PADDLE_HEIGHT / 2 ; MOVWF Ball_Y ; GOTO _UB_Service ; _UB_Check_L_Unpressed: ; BCF System_Status, P1_PRESSED_BIT ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Check if right player pushed button to serve ; ;-----------------------------------------------; _UB_Check_R_Serve: ; BTFSS System_Status, P2_SERVICE_BIT ; GOTO _UB_Exit ; BTFSC System_Status, BUZZ_BIT ; GOTO _UB_Exit ; BANKSEL TRISA ; BSF TRISA, RBUTT_BIT ; BANKSEL PORTA ; BTFSC PORTA, RBUTT_BIT ; GOTO _UB_Check_R_Unpressed ; BTFSC System_Status, P2_PRESSED_BIT ; GOTO _UB_Exit ; BANKSEL TRISA ; BCF TRISA, RBUTT_BIT ; BANKSEL PORTA ; BSF System_Status, P2_PRESSED_BIT ; BCF System_Status, P1_SERVICE_BIT ; BCF System_Status, P2_SERVICE_BIT ; MOVLW -1 ; MOVWF Ball_Dir_X ; MOVFW Paddle_2_Y ; ADDLW PADDLE_HEIGHT / 2 ; SUBLW NUM_LINES / 2 ; MOVLW -1 ; BTFSC STATUS, C ; MOVLW 2 ; MOVWF Ball_Dir_Y ; MOVLW 29 ; MOVWF Ball_X ; MOVFW Paddle_2_Y ; ADDLW PADDLE_HEIGHT / 2 ; MOVWF Ball_Y ; GOTO _UB_Service ; _UB_Check_R_Unpressed: ; BCF System_Status, P2_PRESSED_BIT ; GOTO _UB_Exit ; ;-----------------------------------------------; ; ;-----------------------------------------------; ;-----------------------------------------------; _UB_Service: ; MOVLW H'11' ; XORWF Score_1, W ; BTFSC STATUS, Z ; GOTO $+5 ; MOVLW H'11' ; XORWF Score_2, W ; BTFSS STATUS, Z ; GOTO _UB_Exit ; CLRF Score_1 ; CLRF Score_2 ; GOTO _UB_Exit ; ;-----------------------------------------------; ; ;-----------------------------------------------; ;-----------------------------------------------; _UB_Update_Ball_X: ; MOVFW Ball_Dir_X ; Update Ball X Position ADDWF Ball_X, F ; ; _UB_Update_Ball_X_Min: ; MOVLW 0 ; XORWF Ball_X, W ; BTFSS STATUS, Z ; GOTO _UB_Update_Ball_X_Max ; MOVLW 1 ; MOVWF Ball_Dir_X ; ; INCF Score_2, F ; PLAY_SOUND 20, H'017F' ; Frequency, Duration BCF System_Status, P1_SERVICE_BIT ; BSF System_Status, P2_SERVICE_BIT ; MOVLW 0 ; MOVWF Ball_Dir_X ; MOVWF Ball_Dir_Y ; MOVLW 15 ; MOVWF Ball_X ; MOVLW 27 ; MOVWF Ball_Y ; MOVFW Score_2 ; ANDLW H'0F' ; XORLW H'0A' ; BTFSS STATUS, Z ; GOTO _UB_BXMin_Exit ; MOVFW Score_2 ; ANDLW H'F0' ; ADDLW H'10' ; MOVWF Score_2 ; MOVLW H'A0' ; XORWF Score_2, W ; BTFSC STATUS, Z ; CLRF Score_2 ; _UB_BXMin_Exit: ; MOVLW H'11' ; XORWF Score_2, W ; BTFSS STATUS, Z ; GOTO _UB_Exit ; BSF System_Status, P1_SERVICE_BIT ; BSF System_Status, P2_SERVICE_BIT ; GOTO _UB_Exit ; ; _UB_Update_Ball_X_Max: ; MOVLW 31 ; XORWF Ball_X, W ; BTFSS STATUS, Z ; GOTO _UB_Update_Ball_Y ; MOVLW -1 ; MOVWF Ball_Dir_X ; ; INCF Score_1, F ; PLAY_SOUND 20, H'017F' ; Frequency, Duration BSF System_Status, P1_SERVICE_BIT ; BCF System_Status, P2_SERVICE_BIT ; MOVLW 0 ; MOVWF Ball_Dir_X ; MOVWF Ball_Dir_Y ; MOVLW 15 ; MOVWF Ball_X ; MOVLW 27 ; MOVWF Ball_Y ; MOVFW Score_1 ; ANDLW H'0F' ; XORLW H'0A' ; BTFSS STATUS, Z ; GOTO _UB_BXMax_Exit ; MOVFW Score_1 ; ANDLW H'F0' ; ADDLW H'10' ; MOVWF Score_1 ; MOVLW H'A0' ; XORWF Score_1, W ; BTFSC STATUS, Z ; CLRF Score_1 ; _UB_BXMax_Exit: ; MOVLW H'11' ; XORWF Score_1, W ; BTFSS STATUS, Z ; GOTO _UB_Exit ; BSF System_Status, P1_SERVICE_BIT ; BSF System_Status, P2_SERVICE_BIT ; GOTO _UB_Exit ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Update Ball_Y position ; ;-----------------------------------------------; _UB_Update_Ball_Y: ; MOVFW Ball_Dir_Y ; ADDWF Ball_Y, F ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Check for collision with upper sideline ; ;-----------------------------------------------; _UB_Update_Ball_Y_Min: ; BTFSS Ball_Y, MSB ; GOTO _UB_Update_Ball_Y_Max ; COMF Ball_Y, F ; COMF Ball_Dir_Y, F ; INCF Ball_Dir_Y, F ; ;-----------------------------------------------; ; Play the 'Ball Hit Sideline' sound ; ;-----------------------------------------------; PLAY_SOUND 13, H'013F' ; Frequency, Duration GOTO _UB_Paddle_Detect_Left ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Check for collision with lower sideline ; ;-----------------------------------------------; _UB_Update_Ball_Y_Max: ; MOVLW NUM_LINES - 2 ; SUBWF Ball_Y, W ; BTFSS STATUS, C ; GOTO _UB_Paddle_Detect_Left ; MOVLW NUM_LINES - 2 ; MOVWF Ball_Y ; COMF Ball_Dir_Y, F ; INCF Ball_Dir_Y, F ; ;-----------------------------------------------; ; Play the 'Ball Hit Wall' sound ; ;-----------------------------------------------; PLAY_SOUND 13, H'013F' ; Frequency, Duration ;-----------------------------------------------; ; ;-----------------------------------------------; ; Check for collision with left paddle ; ;-----------------------------------------------; _UB_Paddle_Detect_Left: ; ;-----------------------------------------------; ; On the same vertical line as the left paddle? ; ;-----------------------------------------------; MOVLW 1 ; XORWF Ball_X, W ; BTFSS STATUS, Z ; GOTO _UB_Paddle_Detect_Right ; ; MOVFW Paddle_1_Y ; MOVWF Temp1 ; GOTO _UB_PD_Check_Hit ; ; ;-----------------------------------------------; ; Check for collision with right paddle ; ;-----------------------------------------------; _UB_Paddle_Detect_Right: ; ;-----------------------------------------------; ; On the same vertical line as the right paddle?; ;-----------------------------------------------; MOVLW 30 ; XORWF Ball_X, W ; BTFSS STATUS, Z ; GOTO _UB_Exit ; MOVFW Paddle_2_Y ; MOVWF Temp1 ; ;-----------------------------------------------; ; _UB_PD_Check_Hit: ; ;-----------------------------------------------; ; Are we on the save horizontal plane as the ; ; paddle? ; ;-----------------------------------------------; MOVFW Ball_Y ; ADDLW BALL_HEIGHT ; SUBWF Temp1, W ; BTFSC STATUS, C ; GOTO _UB_Exit ; ; MOVFW Temp1 ; ADDLW PADDLE_HEIGHT - 1 ; MOVWF Temp2 ; MOVFW Ball_Y ; SUBWF Temp2, W ; BTFSS STATUS, C ; GOTO _UB_Exit ; ; _UB_PD_Its_A_Hit: ; ;-----------------------------------------------; ; Reverse the ball 'X' direction ; ;-----------------------------------------------; COMF Ball_Dir_X, F ; INCF Ball_Dir_X, F ; ;-----------------------------------------------; ; Adjust the ball 'X' position ; ;-----------------------------------------------; MOVFW Ball_Dir_X ; ADDWF Ball_X, F ; ;-----------------------------------------------; ; Play the 'Ball Hit Paddle' sound ; ;-----------------------------------------------; PLAY_SOUND 15, H'013F' ; Frequency, Duration ;-----------------------------------------------; ; ;-----------------------------------------------; ; Ball update done. Restore RBUTT as an output ; ; for sound and wait for 60us to pass. ; ;-----------------------------------------------; _UB_Exit: ; BANKSEL TRISA ; BSF TRISA, RBUTT_BIT ; BANKSEL PORTA ; ; ;-----------------------------------------------; ; Wait for this line to complete ; ;-----------------------------------------------; WAIT_FOR_LINE_DONE 2 ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Blank_60us_Line: ; ;---------------------------------------------------; ;-----------------------------------------------; ; 60us Black Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 10 ; WAIT_FOR_LINE_DONE 0 ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Data_Lines: ; ;---------------------------------------------------; ; Note: This will generate 1 60us blank line, then ; ; 224 60us data lines, and finally a 60us blank line; ;---------------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 60us WHITE Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_WHITE, 60, 6 ; WAIT_FOR_LINE_DONE 1 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 60us WHITE Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_WHITE, 60, 7 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Set up of video buffer pointer and line count ; ;-----------------------------------------------; MOVLW LOW VIDEO_BUFFER_START ; MOVWF FSR1L ; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; ; MOVLW NUM_LINES ; MOVWF DL_Count ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Wait for this line to complete ; ;-----------------------------------------------; WAIT_FOR_LINE_DONE 1 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; We repeat each line 4 times, since we don't ; ; have a big enough video buffer for 192 lines ; ;-----------------------------------------------; _DL_Next_Line: ; MOVLW 4 ; MOVWF Repeat_Count ; _DL_Repeat_Line: ; ;-----------------------------------------------; ; 60us Line Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 12 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Front porch - shifts the data to the right ; ; and hopefully centers it on the screen ; ; --------------------------------------------- ; DELAY 14 ; ;-----------------------------------------------; ; MOVLW H'FC' ; ANDWF FSR1L, F ; MOVLW 4 ; MOVWF Byte_Count ; _DL_Next_Byte: ; ;-----------------------------------------------; ; This is where the 32 bits of data are actually; ; send out over the video signal ; ;-----------------------------------------------; DO_BIT 7, 8 ; DO_BIT 6, 8 ; DO_BIT 5, 8 ; DO_BIT 4, 8 ; DO_BIT 3, 8 ; DO_BIT 2, 8 ; DO_BIT 1, 8 ; DO_BIT 0, 1 ; ; ADDFSR FSR1, 1 ; ; _DL_Center_Line: ; MOVLW 3 ; XORWF Byte_Count, W ; BTFSS STATUS, Z ; GOTO _DL_Center_Line_Done ; NOP ; NOP ; NOP ; BCF PORTA, VIDEO_0_BIT ; NOP ; NOP ; NOP ; NOP ; BSF PORTA, VIDEO_0_BIT ; NOP ; BCF PORTA, VIDEO_0_BIT ; _DL_Center_Line_Done: ; ; DECFSZ Byte_Count, F ; GOTO _DL_Next_Byte ; DECF FSR1L, F ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Back porch - between this and the front porch,; ; this 'frames' the video on your TV (hopefully); ; --------------------------------------------- ; ; NOTE: this DELAY and NOPs fleshes out the data; ; line to 60us ; ;-----------------------------------------------; SET_DAC2BIT COLOR_BLACK ; WAIT_FOR_LINE_DONE 1 ; ;-----------------------------------------------; ; DECFSZ Repeat_Count, F ; GOTO $+2 ; GOTO _DL_Next_Data ; DELAY 1 ; NOP ; NOP ; GOTO _DL_Repeat_Line ; ; ;-----------------------------------------------; ; 224 lines of information to transmit ; ; so the screen size is 32x224. But we transmit ; ; each line 4 times, so it's actually 32x56 ; ;-----------------------------------------------; _DL_Next_Data: ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; ;-----------------------------------------------; ADDFSR FSR1, 1 ; DECFSZ DL_Count, F ; GOTO _DL_Next_Line ; ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 60us WHITE Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_WHITE, 60, 6 ; WAIT_FOR_LINE_DONE 0 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 60us WHITE Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_WHITE, 60, 6 ; WAIT_FOR_LINE_DONE 0 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 60us BLACK Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 13 ; WAIT_FOR_LINE_DONE 1 ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; USER_CODE_2 CODE H'800' ; ;---------------------------------------------------; _Copyright: ; ;---------------------------------------------------; ; Note: This is a 60us line routine. It will ; ; generate 8 60us data lines. ; ;---------------------------------------------------; ;-----------------------------------------------; ; Setup ; ;-----------------------------------------------; MOVLW LOW COPYRIGHT_TABLE ; MOVWF FSR1L ; MOVLW HIGH COPYRIGHT_TABLE ; MOVWF FSR1H ; MOVLW 8 ; MOVWF Temp1 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 8 60us Data Lines Generation ; ;-----------------------------------------------; _CR_Next_Line: ; ;-----------------------------------------------; ; 60us Line Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 12 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Xus Back Porch (Black Signal) Generation ; ;-----------------------------------------------; DELAY 16 ; NOP ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Data Generation ; ;-----------------------------------------------; DO_BIT 7, 0 ; DO_BIT 6, 0 ; DO_BIT 5, 0 ; DO_BIT 4, 0 ; DO_BIT 3, 0 ; DO_BIT 2, 0 ; DO_BIT 1, 0 ; DO_BIT 0, 0 ; ADDFSR FSR1, 1 ; DO_BIT 7, 0 ; DO_BIT 6, 0 ; DO_BIT 5, 0 ; DO_BIT 4, 0 ; DO_BIT 3, 0 ; DO_BIT 2, 0 ; DO_BIT 1, 0 ; DO_BIT 0, 0 ; ADDFSR FSR1, 1 ; DO_BIT 7, 0 ; DO_BIT 6, 0 ; DO_BIT 5, 0 ; DO_BIT 4, 0 ; DO_BIT 3, 0 ; DO_BIT 2, 0 ; DO_BIT 1, 0 ; DO_BIT 0, 0 ; ADDFSR FSR1, 1 ; DO_BIT 7, 0 ; DO_BIT 6, 0 ; DO_BIT 5, 0 ; DO_BIT 4, 0 ; DO_BIT 3, 0 ; DO_BIT 2, 0 ; DO_BIT 1, 0 ; DO_BIT 0, 0 ; ADDFSR FSR1, 1 ; DO_BIT 7, 0 ; DO_BIT 6, 0 ; DO_BIT 5, 0 ; DO_BIT 4, 0 ; DO_BIT 3, 0 ; DO_BIT 2, 0 ; DO_BIT 1, 0 ; DO_BIT 0, 0 ; ADDFSR FSR1, 1 ; DO_BIT 7, 0 ; DO_BIT 6, 0 ; DO_BIT 5, 0 ; DO_BIT 4, 0 ; DO_BIT 3, 0 ; DO_BIT 2, 0 ; DO_BIT 1, 0 ; DO_BIT 0, 0 ; ADDFSR FSR1, 1 ; DO_BIT 7, 0 ; DO_BIT 6, 0 ; DO_BIT 5, 0 ; DO_BIT 4, 0 ; DO_BIT 3, 0 ; DO_BIT 2, 0 ; DO_BIT 1, 0 ; DO_BIT 0, 0 ; ADDFSR FSR1, 1 ; DO_BIT 7, 0 ; DO_BIT 6, 0 ; DO_BIT 5, 0 ; DO_BIT 4, 0 ; DO_BIT 3, 0 ; DO_BIT 2, 0 ; DO_BIT 1, 0 ; DO_BIT 0, 0 ; ADDFSR FSR1, 1 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Xus Front Porch (Black Signal) Generation ; ;-----------------------------------------------; SET_DAC2BIT COLOR_BLACK ; WAIT_FOR_LINE_DONE 1 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; All of this nonsense is just to get the timing; ; right between doing the next copyright line or; ; starting the series of blank lines. ; ;-----------------------------------------------; DECFSZ Temp1, F ; GOTO $+4 ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; ;-----------------------------------------------; RETURN ; DELAY 1 ; ;-----------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; NOP ; NOP ; ;-----------------------------------------------; GOTO _CR_Next_Line ; ;---------------------------------------------------; ;---------------------------------------------------; _White_60us_Line: ; ;---------------------------------------------------; ; 60us WHITE Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_WHITE, 60, 10 ; WAIT_FOR_LINE_DONE 1 ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Draw_Items: ; ;---------------------------------------------------; ;-----------------------------------------------; ; 60us Black Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 6 ; ;-----------------------------------------------; ; _DI_Draw_Service_Player_1: ; MOVLW LOW VIDEO_BUFFER_START + SERVICE_1_START; MOVWF FSR1L ; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; MOVLW LOW SERVICE_TABLE ; MOVWF FSR0L ; MOVLW HIGH SERVICE_TABLE ; MOVWF FSR0H ; MOVLW (SERVICE_TABLE_END - SERVICE_TABLE_START) / 2 MOVWF Temp1 ; _DI_DSP1_Next_Byte: ; MOVFW INDF0 ; BTFSS System_Status, P1_SERVICE_BIT ; CLRW ; BTFSC System_Status, P2_SERVICE_BIT ; CLRW ; MOVWF INDF1 ; ADDFSR FSR0, 1 ; ADDFSR FSR1, 4 ; DECFSZ Temp1, F ; GOTO _DI_DSP1_Next_Byte ; ; _DI_Draw_Service_Player_2: ; MOVLW LOW VIDEO_BUFFER_START + SERVICE_2_START; MOVWF FSR1L ; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; MOVLW LOW SERVICE_TABLE ; MOVWF FSR0L ; MOVLW HIGH SERVICE_TABLE ; MOVWF FSR0H ; MOVLW (SERVICE_TABLE_END - SERVICE_TABLE_START) / 2 MOVWF Temp1 ; ADDWF FSR0L, F ; _DI_DSP2_Next_Byte: ; MOVFW INDF0 ; BTFSS System_Status, P2_SERVICE_BIT ; CLRW ; BTFSC System_Status, P1_SERVICE_BIT ; CLRW ; MOVWF INDF1 ; ADDFSR FSR0, 1 ; ADDFSR FSR1, 4 ; DECFSZ Temp1, F ; GOTO _DI_DSP2_Next_Byte ; ; _DI_Draw_Score1: ; _DI_DS1_Draw_Left_Char: ; SWAPF Score_1, W ; ANDLW H'0F' ; MOVWF Temp1 ; ; MOVLW LOW VIDEO_BUFFER_START + LEFT_SCORE_START; MOVWF FSR1L ; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; ; MOVLW HIGH CHARACTER_TABLE ; MOVWF FSR0H ; MOVLW LOW CHARACTER_TABLE ; ADDWF Temp1, W ; BTFSC STATUS, C ; INCF FSR0H, F ; MOVWF FSR0L ; ; MOVLW 5 ; MOVWF Temp1 ; _DI_DS1_DLC_Next_Line: ; MOVFW INDF0 ; MOVWF DTemp ; RRF DTemp, W ; ANDLW H'70' ; MOVWF INDF1 ; ADDFSR FSR0, 10 ; ADDFSR FSR1, 4 ; DECFSZ Temp1, F ; GOTO _DI_DS1_DLC_Next_Line ; ; _DI_DS1_Draw_Right_Char: ; MOVFW Score_1 ; ANDLW H'0F' ; MOVWF Temp1 ; ; MOVLW LOW VIDEO_BUFFER_START + LEFT_SCORE_START; MOVWF FSR1L ; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; ; MOVLW HIGH CHARACTER_TABLE ; MOVWF FSR0H ; MOVLW LOW CHARACTER_TABLE ; ADDWF Temp1, W ; BTFSC STATUS, C ; INCF FSR0H, F ; MOVWF FSR0L ; ; MOVLW 5 ; MOVWF Temp1 ; _DI_DS1_DRC_Next_Line: ; MOVFW INDF0 ; MOVWF DTemp ; RRF DTemp, W ; ANDLW H'07' ; MOVWF DTemp ; MOVFW INDF1 ; IORWF DTemp, W ; MOVWF INDF1 ; ADDFSR FSR0, 10 ; ADDFSR FSR1, 4 ; DECFSZ Temp1, F ; GOTO _DI_DS1_DRC_Next_Line ; ; _DI_Draw_Score2: ; _DI_DS2_Draw_Left_Char: ; SWAPF Score_2, W ; ANDLW H'0F' ; MOVWF Temp1 ; ; MOVLW LOW VIDEO_BUFFER_START + RIGHT_SCORE_START; MOVWF FSR1L ; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; ; MOVLW HIGH CHARACTER_TABLE ; MOVWF FSR0H ; MOVLW LOW CHARACTER_TABLE ; ADDWF Temp1, W ; BTFSC STATUS, C ; INCF FSR0H, F ; MOVWF FSR0L ; ; MOVLW 5 ; MOVWF Temp1 ; _DI_DS2_DLC_Next_Line: ; MOVFW INDF0 ; ANDLW H'E0' ; MOVWF INDF1 ; ADDFSR FSR0, 10 ; ADDFSR FSR1, 4 ; DECFSZ Temp1, F ; GOTO _DI_DS2_DLC_Next_Line ; ; _DI_DS2_Draw_Right_Char: ; MOVFW Score_2 ; ANDLW H'0F' ; MOVWF Temp1 ; ; MOVLW LOW VIDEO_BUFFER_START + RIGHT_SCORE_START; MOVWF FSR1L ; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; ; MOVLW HIGH CHARACTER_TABLE ; MOVWF FSR0H ; MOVLW LOW CHARACTER_TABLE ; ADDWF Temp1, W ; BTFSC STATUS, C ; INCF FSR0H, F ; MOVWF FSR0L ; MOVLW 5 ; MOVWF Temp1 ; _DI_DS2_DRC_Next_Line: ; MOVFW INDF0 ; ANDLW H'0E' ; MOVWF DTemp ; MOVFW INDF1 ; IORWF DTemp, W ; MOVWF INDF1 ; ADDFSR FSR0, 10 ; ADDFSR FSR1, 4 ; DECFSZ Temp1, F ; GOTO _DI_DS2_DRC_Next_Line ; ; ;-----------------------------------------------; ; Wait for this line to complete ; ;-----------------------------------------------; WAIT_FOR_LINE_DONE 0 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 60us Black Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 12 ; ;-----------------------------------------------; ; _DI_Draw_Paddle_1: ; MOVFW Paddle_1_Y ; ADDWF Paddle_1_Y, W ; ADDWF Paddle_1_Y, W ; ADDWF Paddle_1_Y, W ; ADDLW LOW VIDEO_BUFFER_START + LEFT_PADDLE_START; MOVWF FSR1L ; MOVLW HIGH VIDEO_BUFFER_START ; MOVLW PADDLE_HEIGHT ; MOVWF Temp1 ; _DI_DP1_Next_Bit: ; MOVFW INDF1 ; IORLW LEFT_PADDLE_BIT ; MOVWF INDF1 ; ADDFSR FSR1, 4 ; DECFSZ Temp1, F ; GOTO _DI_DP1_Next_Bit ; ; _DI_Draw_Paddle_2: ; MOVFW Paddle_2_Y ; ADDWF Paddle_2_Y, W ; ADDWF Paddle_2_Y, W ; ADDWF Paddle_2_Y, W ; ADDLW LOW VIDEO_BUFFER_START + RIGHT_PADDLE_START; MOVWF FSR1L ; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; MOVLW PADDLE_HEIGHT ; MOVWF Temp1 ; _DI_DP2_Next_Bit: ; MOVFW INDF1 ; IORLW RIGHT_PADDLE_BIT ; MOVWF INDF1 ; ADDFSR FSR1, 4 ; DECFSZ Temp1, F ; GOTO _DI_DP2_Next_Bit ; ; _DI_Draw_Ball: ; ;-----------------------------------------------; ; Check to see if the ball has any movement. If ; ; not, we are either at the end of a game or ; ; waiting for service. In that case, don't draw ; ; the ball. ; ;-----------------------------------------------; CLRW ; XORWF Ball_Dir_X, W ; BTFSS STATUS, Z ; GOTO _DI_DB_Draw ; CLRW ; XORWF Ball_Dir_Y, W ; BTFSC STATUS, Z ; GOTO _DI_Exit ; MOVLW 1 ; XORWF Ball_Wait, W ; BTFSS STATUS, Z ; GOTO _DI_Exit ; ; _DI_DB_Draw: ; ;-----------------------------------------------; ; This is where we actually 'draw' the ball. ; ;-----------------------------------------------; MOVFW Ball_Y ; ADDWF Ball_Y, W ; ADDWF Ball_Y, W ; ADDWF Ball_Y, W ; ADDLW LOW VIDEO_BUFFER_START ; MOVWF FSR1L ; RRF Ball_X, W ; MOVWF Temp1 ; RRF Temp1, F ; RRF Temp1, W ; ANDLW H'1F' ; ADDWF FSR1L, F ; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; ; MOVFW Ball_X ; ANDLW H'07' ; MOVWF Temp1 ; MOVLW H'80' ; MOVWF DTemp ; MOVLW 0 ; ; XORWF Temp1, W ; BTFSC STATUS, Z ; GOTO $+5 ; DECF Temp1, F ; RRF DTemp, F ; BCF DTemp, MSB ; GOTO $-7 ; ; MOVLW BALL_HEIGHT ; MOVWF Temp1 ; MOVFW DTemp ; _DI_DB_D_Next_Pixel: ; XORWF INDF1, F ; ADDFSR FSR1, 4 ; DECFSZ Temp1, F ; GOTO _DI_DB_D_Next_Pixel ; ; _DI_Exit: ; ;-----------------------------------------------; ; Wait for this line to complete ; ;-----------------------------------------------; WAIT_FOR_LINE_DONE 2 ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; _Clear_Screen: ; ;---------------------------------------------------; ; This is a 2 60us BLANK lines routine ; ;---------------------------------------------------; ; Timing Fudge ; ;-----------------------------------------------; NOP ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 60us Black Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 6 ; ;-----------------------------------------------; ; _CS_Top: ; ;-----------------------------------------------; ; Set up the pointer to the video buffer ; ;-----------------------------------------------; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; MOVLW LOW VIDEO_BUFFER_START ; MOVWF FSR1L ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Set up the pointer to the title table ; ;-----------------------------------------------; MOVLW HIGH TITLE_TABLE ; MOVWF FSR0H ; MOVLW LOW TITLE_TABLE ; MOVWF FSR0L ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Set up the number of bytes to transfer ; ;-----------------------------------------------; MOVLW ((NUM_LINES * 4) /2) / 8 ; MOVWF Temp1 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Transfer the data from the title table to the ; ; video buffer, 8 bytes at a time. Doing it in ; ; groups of 8 in a loop, instead of 1 byte at a ; ; time in a loop, speeds up the transfer as it ; ; cuts out a lot of the instruction cycles for ; ; the looping mechanism. ; ;-----------------------------------------------; _CS_T_Next_8_Bytes: ; MOVIW 0[INDF0] ; MOVWI 0[INDF1] ; MOVIW 1[INDF0] ; MOVWI 1[INDF1] ; MOVIW 2[INDF0] ; MOVWI 2[INDF1] ; MOVIW 3[INDF0] ; MOVWI 3[INDF1] ; MOVIW 4[INDF0] ; MOVWI 4[INDF1] ; MOVIW 5[INDF0] ; MOVWI 5[INDF1] ; MOVIW 6[INDF0] ; MOVWI 6[INDF1] ; MOVIW 7[INDF0] ; MOVWI 7[INDF1] ; _CS_T_Check_For_Title: ; BTFSC System_Status, P1_SERVICE_BIT ; If SERVICE is clear for both BTFSS System_Status, P2_SERVICE_BIT ; players, then it's the start GOTO $+2 ; of a game. Draw the title. ADDFSR FSR0, 8 ; ADDFSR FSR1, 8 ; DECFSZ Temp1, F ; GOTO _CS_T_Next_8_Bytes ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Wait for this line to complete ; ;-----------------------------------------------; WAIT_FOR_LINE_DONE 0 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; 60us Black Signal Generation ; ;-----------------------------------------------; NEG_SYNC_4US ; START_LINE COLOR_BLACK, 60, 9 ; ;-----------------------------------------------; ; _CS_Bottom: ; ;-----------------------------------------------; ; Set up the pointer to the video buffer ; ;-----------------------------------------------; MOVLW HIGH VIDEO_BUFFER_START ; MOVWF FSR1H ; MOVLW LOW VIDEO_BUFFER_START ; ADDLW (NUM_LINES * 4) / 2 ; MOVWF FSR1L ; BTFSC STATUS, C ; INCF FSR1H, F ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Set up the pointer to the title table ; ;-----------------------------------------------; MOVLW HIGH TITLE_TABLE ; MOVWF FSR0H ; MOVLW LOW TITLE_TABLE ; _CS_B_Check_For_Title1: ; BTFSC System_Status, P1_SERVICE_BIT ; If SERVICE is clear for both BTFSS System_Status, P2_SERVICE_BIT ; players, then it's the start GOTO $+2 ; of a game. Draw the title. ADDLW (NUM_LINES * 4) / 2 ; MOVWF FSR0L ; BTFSC STATUS, C ; INCF FSR0H, F ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Set up the number of bytes to transfer ; ;-----------------------------------------------; MOVLW ((NUM_LINES * 4) /2) / 8 ; MOVWF Temp1 ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Transfer the data from the title table to the ; ; video buffer, 8 bytes at a time. Doing it in ; ; groups of 8 in a loop, instead of 1 byte at a ; ; time in a loop, speeds up the transfer as it ; ; cuts out a lot of the instruction cycles for ; ; the looping mechanism. ; ;-----------------------------------------------; _CS_B_Next_8_Bytes: ; MOVIW 0[INDF0] ; MOVWI 0[INDF1] ; MOVIW 1[INDF0] ; MOVWI 1[INDF1] ; MOVIW 2[INDF0] ; MOVWI 2[INDF1] ; MOVIW 3[INDF0] ; MOVWI 3[INDF1] ; MOVIW 4[INDF0] ; MOVWI 4[INDF1] ; MOVIW 5[INDF0] ; MOVWI 5[INDF1] ; MOVIW 6[INDF0] ; MOVWI 6[INDF1] ; MOVIW 7[INDF0] ; MOVWI 7[INDF1] ; _CS_B_Check_For_Title2: ; BTFSC System_Status, P1_SERVICE_BIT ; If SERVICE is clear for both BTFSS System_Status, P2_SERVICE_BIT ; players, then it's the start GOTO $+2 ; of a game. Draw the title. ADDFSR FSR0, 8 ; ADDFSR FSR1, 8 ; DECFSZ Temp1, F ; GOTO _CS_B_Next_8_Bytes ; ;-----------------------------------------------; ; ;-----------------------------------------------; ; Wait for this line to complete ; ;-----------------------------------------------; WAIT_FOR_LINE_DONE 0 ; ;-----------------------------------------------; ; RETURN ; ;---------------------------------------------------; ;---------------------------------------------------; ; Numeric Characters (0-9) Scan Line Data ; ;---------------------------------------------------; CHARACTER_TABLE: ; ;---------------------------------------------------; ; These are the bitmaps for the score characters; ; 0-9, 4x5 pixels ; ;-----------------------------------------------; DT B'11101110', B'01000100', B'11101110', B'11101110', B'10101010', B'11101110', B'11101110', B'11101110', B'11101110', B'11101110' DT B'10101010', B'11001100', B'00100010', B'00100010', B'10101010', B'10001000', B'10001000', B'00100010', B'10101010', B'10101010' DT B'10101010', B'01000100', B'11101110', B'11101110', B'11101110', B'11101110', B'11101110', B'00100010', B'11101110', B'11101110' DT B'10101010', B'01000100', B'10001000', B'00100010', B'00100010', B'00100010', B'10101010', B'00100010', B'10101010', B'00100010' DT B'11101110', B'01000100', B'11101110', B'11101110', B'00100010', B'11101110', B'11101110', B'00100010', B'11101110', B'00100010' ;---------------------------------------------------; ;---------------------------------------------------; SERVICE_TABLE: ; ;---------------------------------------------------; ; These are the bitmaps for the 'SERVICE' arrow ; ; that shows up next to a score. ; ;-----------------------------------------------; SERVICE_TABLE_START: ; DT B'00000100' ; DT B'00000010' ; DT B'00000001' ; DT B'00000010' ; DT B'00000100' ; DT B'00100000' ; DT B'01000000' ; DT B'10000000' ; DT B'01000000' ; DT B'00100000' ; SERVICE_TABLE_END: ; ;---------------------------------------------------; ;---------------------------------------------------; ; Title Title Scan Line Data ; ;---------------------------------------------------; TITLE_TABLE: ; ;---------------------------------------------------; TITLE_TABLE_START: ; ;-----------------------------------------------; ; The first 6x4 lines should be 0 so that the ; ; title graphic does not merge with the scores, ; ; and for the screen to clear the title properly; ;-----------------------------------------------; DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' ;-----------------------------------------------; ; The next 41x4 lines contain the title graphic ; ;-----------------------------------------------; DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000111', B'10000000', B'01110000', B'00000000' DT B'00000111', B'11000000', B'11111000', B'00000000' DT B'00000100', B'01000000', B'10001000', B'00000000' DT B'00000100', B'01001110', B'10001001', B'11000000' DT B'00000111', B'11011111', B'10001011', B'11100000' DT B'00000111', B'10010001', B'10001010', B'00100000' DT B'00000100', B'00010001', B'10001010', B'00000000' DT B'00000100', B'00010001', B'10001010', B'01100000' DT B'00000100', B'00010001', B'10001010', B'01100000' DT B'00000100', B'00010001', B'10001010', B'00100000' DT B'00000000', B'00010001', B'00000010', B'00100000' DT B'00000000', B'00011111', B'00000011', B'11100000' DT B'00000000', B'00001110', B'00000001', B'11000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00001110', B'11101110', B'01110101', B'01110000' DT B'00001110', B'11101110', B'01110101', B'01110000' DT B'00001000', B'10101010', B'00100101', B'01000000' DT B'00001100', B'10101100', B'00100111', B'01100000' DT B'00001000', B'10101010', B'00100101', B'01000000' DT B'00001000', B'11101010', B'00100101', B'01110000' DT B'00001000', B'11101010', B'00100101', B'01110000' DT B'00000000', B'00000000', B'00000000', B'00000000' DT B'00000101', B'11011101', B'11101010', B'11100000' DT B'00000101', B'11011101', B'11101010', B'11100000' DT B'00000100', B'01010001', B'10101010', B'10100000' DT B'00000101', B'11011001', B'11101110', B'10100000' DT B'00000101', B'00010001', B'10100010', B'10100000' DT B'00000101', B'11010001', B'11100010', B'11100000' DT B'00000101', B'11010001', B'11100010', B'11100000' ;-----------------------------------------------; ; This last 1x4 line should be 0 so that the ; ; title graphic does bump into the sideline ; ;-----------------------------------------------; DT B'00000000', B'00000000', B'00000000', B'00000000' TITLE_TABLE_END: ; ;---------------------------------------------------; ;---------------------------------------------------; ; COPYRIGHT Scan Line Data ; ;---------------------------------------------------; COPYRIGHT_TABLE: ; ;---------------------------------------------------; ; this is the bitmap for the COPYRIGHT line ; ; 64x8 pixels ; ;-----------------------------------------------; DT B'00110011', B'10111000', B'10010010', B'00111001', B'00010111', B'00000101', B'01110000', B'10011100' DT B'00111011', B'10111001', B'00111001', B'00111011', B'10110111', B'00000101', B'01110001', B'11011100' DT B'10101001', B'00010001', B'00101001', B'00001010', B'10010001', B'01010101', B'00010001', B'01000101' DT B'10101001', B'00010001', B'00100001', B'00111010', B'10010111', B'01010101', B'00110001', B'01000101' DT B'10101001', B'00010001', B'00100001', B'00111010', B'10010111', B'01010101', B'00110001', B'01001001' DT B'10101001', B'00010001', B'00101001', B'00100010', B'10010100', B'01010101', B'00010001', B'01010001' DT B'00111001', B'00111001', B'00111001', B'00111011', B'10010111', B'00000101', B'01110101', B'11010000' DT B'00110001', B'00111000', B'10010010', B'00111001', B'00010111', B'00000010', B'01110100', B'10010000' ;---------------------------------------------------; ;---------------------------------------------------; ;---------------------------------------------------; END ; ;---------------------------------------------------; ;---------------------------------------------------;