- // ============================ //
- // Do not edit this part!!!! //
- // ============================ //
- // 0x300001 - CONFIG1H
- #pragma config OSC = HSPLL // Oscillator Selection bits (HS oscillator,
- // PLL enabled (Clock Frequency = 4 x FOSC1))
- #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit
- // (Fail-Safe Clock Monitor disabled)
- #pragma config IESO = OFF // Internal/External Oscillator Switchover bit
- // (Oscillator Switchover mode disabled)
- // 0x300002 - CONFIG2L
- #pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)
- #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out
- // Reset disabled in hardware and software)
- // 0x300003 - CONFIG1H
- #pragma config WDT = OFF // Watchdog Timer Enable bit
- // (WDT disabled (control is placed on the SWDTEN bit))
- // 0x300004 - CONFIG3L
- // 0x300005 - CONFIG3H
- #pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit
- // (Timer1 configured for higher power operation)
- #pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled;
- // RE3 input pin disabled)
- // 0x300006 - CONFIG4L
- #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply
- // ICSP disabled)
- #pragma config XINST = OFF // Extended Instruction Set Enable bit
- // (Instruction set extension and Indexed
- // Addressing mode disabled (Legacy mode))
- #pragma config DEBUG = OFF // Disable In-Circuit Debugger
- #define KHZ 1000UL
- #define MHZ (KHZ * KHZ)
- #define _XTAL_FREQ (40UL * MHZ)
- // ============================ //
- // End //
- // ============================ //
- #include <xc.h>
- #include <stdint.h>
- #include <math.h>
- #define T_PRELOAD_LOW 0x6A // BLINK 250MS
- #define T_PRELOAD_HIGH 0x67
- // Add a structure for pieces
- struct current_piece
- {
- uint8_t horizontal_port; // 0.C, 1.D, 2.E, 3.F
- uint8_t vertical_port; // A binary number to represent the vertical port e.g 10000000
- uint8_t type; // 0.dot, 1.square, 2.l_piece
- };
- // ============================ //
- // Global variables //
- // ============================ //
- // Assign initial piece as a dot:
- struct current_piece current_piece = {2, 0b00010000, 0};
- struct current_piece anti_piece = {0, 0b00000010, 0};
- // Needed for interrupt on PORTB to work
- volatile uint8_t prevB;
- // Anti piece rotate state:
- // XX -> 0, OX -> 1, XO -> 2, XX -> 3
- // OX XX XX XO
- // Represents the empty block position for the current piece if it is an l-piece:
- uint8_t rotate_state = 0;
- // Submitted lanes for pieces:
- uint8_t c_lane = 0b00000000;
- uint8_t d_lane = 0b00000000;
- uint8_t e_lane = 0b00000000;
- uint8_t f_lane = 0b00000000;
- // Flags for buttons:
- uint8_t right_button = 0;
- uint8_t up_button = 0;
- uint8_t down_button = 0;
- uint8_t left_button = 0;
- // Temp
- uint8_t x;
- uint8_t y;
- uint8_t z;
- uint8_t t;
- // ============================ //
- // Initialize the system //
- // ============================ //
- void init()
- {
- // 2.2 INPUTS
- // Port G is set as input:
- // RA0: Right
- // RA1: Up
- // RA2: Down
- // RA3: Left
- ADCON1 = 0b00001111;
- LATG = 0x00;
- PORTG = 0x00;
- TRISG = 0x0F;
- LATG = 0x00;
- PORTG = 0x00;
- // Port B is also set as input:
- // RB5: Rotate
- // RB6: Submit
- LATB = 0x00;
- PORTB = 0x00;
- TRISB = 0x60;
- // 2.3 OUTPUTS
- // C TO F FOR GAME AREA
- // C
- LATC = 0x00;
- PORTC = 0x00;
- TRISC = 0x00;
- // D
- LATD = 0x00;
- PORTD = 0x00;
- TRISD = 0x00;
- // E
- LATE = 0x00;
- PORTE = 0x00;
- TRISE = 0x00;
- // F
- LATF = 0x00;
- PORTF = 0x00;
- TRISF = 0x00;
- // H AND J ? S-10
- // Initialize the 7-segment display ports
- TRISJ = 0x00; // Set PORTJ to output
- LATJ = 0x00; // Clear segments (assumes common cathode display)
- TRISH = 0x00; // Set PORTH to output
- LATH = 0x00; // Disable all 7-segment displays
- // Enable the first 7-segment display and set it to show '0'
- LATJ = 0x3F; // '0' on a common cathode 7-segment display
- }
- void initialize_timer_and_interrupts()
- {
- // Enable pre-scalar
- // Full pre-scale
- // we also need to do in-code scaling
- T0CON = 0x00;
- T0CONbits.TMR0ON = 1;
- T0CONbits.T0PS2 = 1;
- T0CONbits.T0PS1 = 0;
- T0CONbits.T0PS0 = 1;
- // Pre-load the value
- TMR0H = T_PRELOAD_HIGH;
- TMR0L = T_PRELOAD_LOW;
- RCONbits.IPEN = 0;
- INTCON = 0x00;
- INTCONbits.TMR0IE = 1;
- INTCONbits.RBIE = 1;
- INTCONbits.GIE = 1;
- INTCONbits.PEIE = 1;
- }
- // ============================ //
- // Piece related functions //
- // ============================ //
- void create_piece()
- {
- if (current_piece.type == 0)
- {
- // Last piece was a dot.
- // Create a square and assign it to alive_piece:
- current_piece.horizontal_port = 0;
- current_piece.vertical_port = 0b00000011;
- current_piece.type = 1;
- }
- else if (current_piece.type == 1)
- {
- // Last piece was a square.
- // Create an l-piece and assign it to alive_piece:
- current_piece.horizontal_port = 0;
- current_piece.vertical_port = 0b00000011; // Same as square, we already add anti_piece
- current_piece.type = 2;
- anti_piece.horizontal_port = 0;
- anti_piece.vertical_port = 0b00000010;
- anti_piece.type = 0;
- rotate_state = 0;
- }
- else if (current_piece.type == 2)
- {
- // Last piece was an l-piece.
- // Create a dot and assign it to alive_piece:
- current_piece.horizontal_port = 0;
- current_piece.vertical_port = 0b00000001;
- current_piece.type = 0;
- }
- }
- void submit_piece()
- {
- // TODO: Add square and l-piece cases
- switch (current_piece.horizontal_port)
- {
- case 0:
- if (!(c_lane & current_piece.vertical_port))
- {
- c_lane = c_lane | current_piece.vertical_port;
- }
- break;
- case 1:
- if (!(d_lane & current_piece.vertical_port))
- {
- d_lane = d_lane | current_piece.vertical_port;
- }
- break;
- case 2:
- if (!(e_lane & current_piece.vertical_port))
- {
- e_lane = e_lane | current_piece.vertical_port;
- }
- break;
- case 3:
- if (!(f_lane & current_piece.vertical_port))
- {
- f_lane = f_lane | current_piece.vertical_port;
- }
- break;
- default:
- break;
- }
- }
- // ============================ //
- // Interrupt related functions //
- // ============================ //
- __interrupt(high_priority) void handle_interrupt()
- {
- if (INTCONbits.RBIF)
- {
- // Read the value to satisfy the interrupt
- prevB = PORTB;
- // Submit current piece and create a new one
- submit_piece();
- create_piece();
- INTCONbits.RBIF = 0;
- }
- INTCONbits.GIE = 1;
- }
- // ============================ //
- // Button related functions //
- // ============================ //
- void move_current_piece_left()
- {
- if (current_piece.horizontal_port > 0)
- {
- current_piece.horizontal_port--;
- // Move the anti_piece as well, regardless of the type of the current piece
- anti_piece.horizontal_port--;
- }
- }
- void move_current_piece_right()
- {
- if (current_piece.type == 0)
- {
- if (current_piece.horizontal_port < 3)
- {
- current_piece.horizontal_port++;
- }
- }
- else
- {
- if (current_piece.horizontal_port < 2)
- {
- current_piece.horizontal_port++;
- anti_piece.horizontal_port++;
- }
- }
- }
- void move_current_piece_down()
- {
- if (current_piece.type == 0)
- {
- if (current_piece.vertical_port < 64)
- {
- // If 7th bit is not 1, then move down
- current_piece.vertical_port = current_piece.vertical_port << 1;
- }
- }
- else
- {
- // If 7th and 6th bits are not 1, then move down
- if (!(current_piece.vertical_port & 0b11000000))
- {
- current_piece.vertical_port = current_piece.vertical_port << 1;
- anti_piece.vertical_port = anti_piece.vertical_port << 1;
- }
- }
- }
- void move_current_piece_up()
- {
- if (current_piece.type == 0)
- {
- if (current_piece.vertical_port > 1)
- {
- // If 0th bit is not 1, then move up
- current_piece.vertical_port = current_piece.vertical_port >> 1;
- }
- }
- else
- {
- // If 0th and 1st bits are not 1, then move up
- if (!(current_piece.vertical_port & 0b00000011))
- {
- current_piece.vertical_port = current_piece.vertical_port >> 1;
- anti_piece.vertical_port = anti_piece.vertical_port >> 1;
- }
- }
- }
- // ============================ //
- // Polling functions //
- // ============================ //
- void right_button_task()
- {
- if (PORTGbits.RG0 == 1)
- {
- right_button = 1;
- }
- else
- {
- if (right_button == 1)
- {
- move_current_piece_right();
- right_button = 0;
- }
- }
- }
- void up_button_task()
- {
- if (PORTGbits.RG1 == 1)
- {
- up_button = 1;
- }
- else
- {
- if (up_button == 1)
- {
- move_current_piece_up();
- up_button = 0;
- }
- }
- }
- void down_button_task()
- {
- if (PORTGbits.RG2 == 1)
- {
- down_button = 1;
- }
- else
- {
- if (down_button == 1)
- {
- move_current_piece_down();
- down_button = 0;
- }
- }
- }
- void left_button_task()
- {
- if (PORTGbits.RG3 == 1)
- {
- left_button = 1;
- }
- else
- {
- if (left_button == 1)
- {
- move_current_piece_left();
- submit_piece();
- left_button = 0;
- }
- }
- }
- // ============================ //
- // Rendering functions //
- // ============================ //
- void render()
- {
- if (current_piece.horizontal_port == 0)
- {
- LATC = c_lane | current_piece.vertical_port;
- if (current_piece.type != 0)
- {
- // Whether it is square or l-piece, we need to render right lane as well
- LATD = d_lane | current_piece.vertical_port;
- }
- if (current_piece.type == 2)
- {
- // XX -> 0, OX -> 1, XO -> 2, XX -> 3
- // OX XX XX XO
- // Depending on anti_piece position, remove the anti_piece block by subtracting it from the lane
- switch (rotate_state)
- {
- case 0:
- LATC = LATC - anti_piece.vertical_port;
- break;
- case 1:
- LATC = LATC - anti_piece.vertical_port;
- break;
- case 2:
- LATD = LATD - anti_piece.vertical_port;
- break;
- case 3:
- LATD = LATD - anti_piece.vertical_port;
- break;
- default:
- break;
- }
- }
- }
- else if (current_piece.horizontal_port == 1)
- {
- LATD = d_lane | current_piece.vertical_port;
- if (current_piece.type != 0)
- {
- // Whether it is square or l-piece, we need to render right lane as well
- LATE = e_lane | current_piece.vertical_port;
- }
- if (current_piece.type == 2)
- {
- // XX -> 0, OX -> 1, XO -> 2, XX -> 3
- // OX XX XX XO
- // Depending on anti_piece position, remove the anti_piece block by subtracting it from the lane
- switch (rotate_state)
- {
- case 0:
- LATD = LATD - anti_piece.vertical_port;
- break;
- case 1:
- LATD = LATD - anti_piece.vertical_port;
- break;
- case 2:
- LATE = LATE - anti_piece.vertical_port;
- break;
- case 3:
- LATE = LATE - anti_piece.vertical_port;
- break;
- default:
- break;
- }
- }
- }
- else if (current_piece.horizontal_port == 2)
- {
- LATE = e_lane | current_piece.vertical_port;
- if (current_piece.type != 0)
- {
- // Whether it is square or l-piece, we need to render right lane as well
- LATF = f_lane | current_piece.vertical_port;
- }
- if (current_piece.type == 2)
- {
- // XX -> 0, OX -> 1, XO -> 2, XX -> 3
- // OX XX XX XO
- // Depending on anti_piece position, remove the anti_piece block by subtracting it from the lane
- switch (rotate_state)
- {
- case 0:
- LATE = LATE - anti_piece.vertical_port;
- break;
- case 1:
- LATE = LATE - anti_piece.vertical_port;
- break;
- case 2:
- LATF = LATF - anti_piece.vertical_port;
- break;
- case 3:
- LATF = LATF - anti_piece.vertical_port;
- break;
- default:
- break;
- }
- }
- }
- else if (current_piece.horizontal_port == 3)
- {
- LATF = f_lane | current_piece.vertical_port;
- }
- }
- // ============================ //
- // Main function //
- // ============================ //
- void main()
- {
- init();
- initialize_timer_and_interrupts();
- prevB = PORTB;
- __delay_ms(100);
- while (1)
- {
- left_button_task();
- up_button_task();
- down_button_task();
- right_button_task();
- render();
- }
- }