• AVR Pong in Assembly

    Rijo Abraham03/12/2021 at 06:15 0 comments

    Wokwi Arduino Simulator


    #define __SFR_OFFSET 0
    
    #include "avr/io.h"
    
    .global main
    
    .data
    frame_segment_1: .space 8
    frame_segment_2: .space 8
    
    .text
    spi_transfer:
      out SPDR, r24
    1: 
      in r0, SPSR
      sbrs r0, SPIF
      rjmp 1b
      ret
    
    delay_ms:
      ldi r26, 4000 & 0xFF
      ldi r27, 4000 >> 8
    1:
      sbiw r26, 1
      brne 1b
      sbiw 24, 1
      brne delay_ms
      ret
    
    clear_frame:
      ldi ZL, lo8(frame_segment_1)
      ldi ZH, hi8(frame_segment_1)
      ldi YL, lo8(frame_segment_2)
      ldi YH, hi8(frame_segment_2)
      ldi r18, 8
      ldi r19, 0x00
    1:
      st Z+, r19
      st Y+, r19
      dec r18
      brne 1b
      
      ret
    
    draw_frame:
      ldi r18, 1
      ldi ZL, lo8(frame_segment_1)
      ldi ZH, hi8(frame_segment_1)
      ldi YL, lo8(frame_segment_2)
      ldi YH, hi8(frame_segment_2)
    1:
      ; Enable SPI CS
      ldi r19, 0x00
      out PORTB, r19
    
      mov r24, r18
      rcall spi_transfer
      ld r24, Z+
      rcall spi_transfer
      mov r24, r18
      rcall spi_transfer
      ld r24, Y+
      rcall spi_transfer
    
      ; Disable SPI CS
      ldi r19, 0x04
      out PORTB, r19
    
      inc r18
      cp r18, 8
      brne 1b
      ret
    
    update_player_paddle:
      sbis PIND, 7
      dec r4  ; Move up
      sbis PIND, 6
      inc r4  ; Move down
    
      ; if py < 1, py = 1
      mov r18, r4
      cpi r18, 1
      brsh 2f
      ldi r18, 1
      mov r4, r18
      brsh 1f
    2:
      ; if py >= 7, py = 6
      mov r18, r4
      cpi r18, 6
      brlo 1f
      ldi r18, 6
      mov r4, r18
    1:
      ret
    
    main:
      ; Initialize SPI
      ldi r18, 0x50
      out SPCR, r18
    
      ; Configure SPI CS pin (PB2)
      ldi r18, 0x04
      out DDRB, r18
      ldi r18, 0x04
      out PORTB, r18
    
      ; Configure pins PD6 and PD7
      ldi r18, 0x00
      out DDRD, r18
      ldi r18, 0xFF
      out PORTD, r18
    
      ; Initialize variable
      ldi r18, 1
      mov r2, r18  ; Ball x
      ldi r18, 3
      mov r3, r18  ; Ball y
      ldi r18, 3
      mov r4, r18  ; Player paddle (py)
      ldi r18, 3
      mov r5, r18  ; Computer paddle (cy)
      ldi r18, -1
      mov r6, r18  ; Ball velocity (dx)
      ldi r18, 1
      mov r7, r18  ; Ball velocity (dy)
    
    loop:
      ; if y == 1, dy = 1
      mov r18, r3
      cpi r18, 1
      brne 1f
      ldi r19, 1
      mov r7, r19
    1:
      ; if y == 8, dy = -1
      cpi r18, 8
      brne 2f
      ldi r19, -1
      mov r7, r19
    2:
    
      ; if x == 1, dx = 1
      mov r18, r2
      cpi r18, 1
      brne 1f
      ldi r19, 1
      mov r6, r19
    1:
      ; if x == 14, dx = -1
      cpi r18, 14
      brne 2f
      ldi r19, -1
      mov r6, r19
    2:
    
      ; y += dy
      add r3, r7
      ; x += dx
      add r2, r6
    
      ; Computer Paddle AI
      ; if x >= 8, cy = y
      mov r18, r2
      cpi r18, 8
      brlo 1f
      mov r5, r3 
      ; if cy < 1, cy = 1
      mov r18, r5
      cpi r18, 1
      brsh 2f
      ldi r18, 1
      mov r5, r18
      brsh 1f
    2:
      ; if cy >= 7, cy = 6
      mov r18, r5
      cpi r18, 6
      brlo 1f
      ldi r18, 6
      mov r5, r18
    1:
    
      call clear_frame
    
      ;; Ball
      mov r18, r2 
      cpi r18, 8
      brsh 1f
      ; frame_segment_1
      ldi ZL, lo8(frame_segment_1)
      ldi ZH, hi8(frame_segment_1)
      mov r19, r2
      inc r19
      ldi r20, 0x00
      bset 0
    3:
      rol r20
      bclr 0
      dec r19
      brne 3b
      jmp 2f
    1:
      ; frame_segment_2
      ldi ZL, lo8(frame_segment_2)
      ldi ZH, hi8(frame_segment_2)
      mov r19, r2
      subi r19, 7
      ldi r20, 0x00
      bset 0
    3:
      rol r20
      bclr 0
      dec r19
      brne 3b
    2:
      add ZL, r3
      adc ZH, r1
      st -Z, r20
    
      ;; Player Paddle
      ldi ZL, lo8(frame_segment_1)
      ldi ZH, hi8(frame_segment_1)
      add ZL, r4
      adc ZH, r1
      ld r20, -Z
      ori r20, 0x01
      st Z+, r20
      ld r20, Z
      ori r20, 0x01
      st Z+, r20
      ld r20, Z
      ori r20, 0x01
      st Z, r20
    
      ;; Computer Paddle
      ldi ZL, lo8(frame_segment_2)
      ldi ZH, hi8(frame_segment_2)
      add ZL, r5
      adc ZH, r1
      ld r20, -Z
      ori r20, 0x80
      st Z+, r20
      ld r20, Z
      ori r20, 0x80
      st Z+, r20
      ld r20, Z
      ori r20, 0x80
      st Z, r20
    
      call draw_frame
    
      call update_player_paddle
      ; Delay
      ldi r24, 100
      call delay_ms
    
      call update_player_paddle
      ; Delay
      ldi r24, 100
      call delay_ms
    
      ;; if (x == 1) and ((y < py) or (y >= py+3)), GAME OVER! 
      mov r18, r2
      cpi r18, 1
      brne 1f
      cp r3, r4
      brsh 2f
      jmp 3f
    2:
      mov r18, r4
      inc r18
      inc r18
      inc r18
      cp r3, r18 
      brlo 1f
    3:
      jmp 3b
    1:
      ;;
    
      jmp loop
      jmp main

  • AVR Pong in C/C++

    Rijo Abraham03/10/2021 at 17:51 0 comments

    Wokwi Arduino Simulator


    uint8_t frame[8][2];
    /* x : +ve right ; columns ; (0,15)
     * y : +ve down  ; rows    ; (1,8)*/
    int8_t x=1, y=3, py=3, cy=3, dx=-1, dy=1;
    
    void spi_transfer(uint8_t data)
    {
      SPDR = data;
      while(!bitRead(SPSR, SPIF));
    }
    
    void draw_frame() {
      for (int row=1; row<=8; row++)
      {
        /* Enable CS */
        bitClear(PORTB, 2);
        spi_transfer(row);
        spi_transfer(frame[row-1][0]);
        spi_transfer(row);
        spi_transfer(frame[row-1][1]);
        /* Disable CS */
        bitSet(PORTB, 2);
      }
    }
    
    void clear_frame() {
      for (int row=1; row<=8; row++)
      {
        frame[row-1][0] = frame[row-1][1] = 0x00; 
      }
    
      draw_frame();
    }
    
    void setup() {
      /* Initialize SPI */
      bitSet(SPCR, SPE); /* SPI Enable */
      bitSet(SPCR, MSTR); /* Master */
    
      /* Configure SPI CS pin (PB2) */
      bitSet(DDRB, 2);
      bitSet(PORTB, 2);
    
      /* Configure pin change interrupt on pins PD6 (PCINT22) and PD7 (PCINT23) */
      DDRD = 0x00; /* Configure pins as input */
      PORTD = 0xFF; /* Enable pull up  resistors */
      bitSet(PCICR, PCIE2); /* Enable PCINT[23:16] */
      bitSet(PCMSK2, PCINT22); /* Unmask pin change interrupt on PD6*/
      bitSet(PCMSK2, PCINT23); /* Unmask pin change interrupt on PD7 */
    
      /* Timer 1 Configuration */
      TCCR1A = 0x00; /* Normal operation */
      TCCR1B = 0x00; 
      /* f1 = f_clk/64 = 16M/64 */
      /* T1 = 64/16 us = 4 us */
      bitSet(TCCR1B, CS10); /* 64 prescaler */ 
      bitSet(TCCR1B, CS11);
    }
    
    void update_player_paddle() {
      if (!bitRead(PIND, 7)) /* Paddle up */ py -= 1;
      if (!bitRead(PIND, 6)) /* Paddle down */ py += 1;
    
      if (py < 1) py = 1;
      if (py > 6) py = 6;
    }
    
    ISR(PCINT2_vect) {
      /* Push button debouncing */
      /* 50 ms = 50,000 us, Count = 50,000/4 = 12,500 */
      TCNT1 = 53035; /* 65535 - 12,500 */
      bitSet(TIMSK1, TOIE1); /* Enable overflow interrupt */
    }
    
    ISR(TIMER1_OVF_vect) {
      update_player_paddle();
    
      bitClear(TIMSK1, TOIE1); /* Disable overflow interrupt */
    }
    
    uint8_t count = 0;
    
    void loop() {
      if (x==1) {
        if ((y < py) || (y > py+2)) {
          /* "GAME OVER!" */
          while(1);
        }
      }
    
      clear_frame();
      if (y==1) dy=1; else if (y==8) dy=-1;
      if (x==1) dx=1; else if (x==14) dx=-1;
    
      y = y + dy;
      x = x + dx;
    
      /* Computer Paddle AI */ 
      if (x > 7) cy = y;
      if (cy < 1) cy = 1;
      if (cy > 6) cy = 6;
    
      /* Ball */ 
      bitSet(frame[y-1][x/8], x%8); 
      /* Player Paddle */
      bitSet(frame[py-1][0], 0);
      bitSet(frame[py][0], 0);
      bitSet(frame[py+1][0], 0);
      /* Computer Paddle*/
      bitSet(frame[cy-1][1], 7);
      bitSet(frame[cy][1], 7);
      bitSet(frame[cy+1][1], 7);
    
      draw_frame(); 
    
      // update_player_paddle();
      delay(100);
      // update_player_paddle();
      delay(100);
    }