Aidan Mala

IT professional

Tag: ARM

  • Applied ARM-Assembly Software Engineering: A Pure Arm Implementation of Pong on Micro:bit

    Applied ARM-Assembly Software Engineering: A Pure Arm Implementation of Pong on Micro:bit

    This was written 100% by hand without any assistance from our silicon based overlords.

    Initialisation

    .syntax unified
    .global main
    
    .type main, %function
    main:
      
      initialise:
        @ Set all pins on microbit to output
        bl initialise_output_pins
        
        @ start animation on death and startup
        game_start:
        @ print heart on
        ldr r1, =heart_on
        ldr r0, [r1]
        ldr r1, =game_state
        str r0, [r1]
        mov r0, 0xfff
    
        pi_1:
          cmp r0, 0
          beq exit_pi_1
          bl print_game
          sub r0, 1
          b pi_1
        exit_pi_1:
    
        @ print heart off
        ldr r1, =heart_off
        ldr r0, [r1]
        ldr r1, =game_state
        str r0, [r1]
        mov r0, 0xfff
    
        pi_2: 
          cmp r0, 0
          beq exit_pi_2
          bl print_game
          sub r0, 1
          b pi_2
        exit_pi_2:
    
        @ set the game state to intended initial gamestate
        ldr r1, =reset_game_state
        ldr r0, [r1]
        ldr r2, =game_state
        str r0, [r2]
    
        mov r4, 4 @ Direction for ball  between 0 and 5 inclusive
        mov r5, 6 @ Position for ball between 0 and 24 inclusive
        mov r6, 2 @ Direction for paddle between 0 and 1 inclusive
        mov r7, 1 @ Position for paddle between 0 and 4 inclusive
          @ note: that the position of the paddle is of the left pixel
          @       so the other part of the paddle will always be one
          @       to the right.
        
        push {r4-r7} @ Store values
    
    

    Game loop

      play_game:
    
        mov r0, 0x2000 @ good pause amount
    
        pause_g: @pause and print the game
          cmp r0, 0
          beq exit_g
          bl print_game
          sub r0, 1
          b pause_g
        exit_g:
    
    
        bl step_game @ step the entire game
        
        @ checks if game hase been lost, if it has restart
        cmp r5, 4
        ble game_start
    
        @ else:
        b play_game
    

    Update the game state

    step_game:
      @ steps the entire game to its next logical state
    
        pop {r4-r7} @ get position and direction values
        push {lr}
       
        step_ball:
        @ Move ball according to the direction register
    
          .type move_ball, %function
          @ args:
          @   r4: direction of ball
          @   r5: position of ball
          @   r6: direction of paddle
          @   r7: position of paddle
          move_ball:
    
            bl check_game
    
            cmp r4, 0
            beq move_up_left
            cmp r4, 1
            beq move_up
            cmp r4, 2
            beq move_up_right
            cmp r4, 3
            beq move_down_left
            cmp r4, 4
            beq move_down
            cmp r4, 5
            beq move_down_right
    
            move_up_left:
              mov r3, 6
              b change_gamestate_b
    
            move_up:
              mov r3, 5
              b change_gamestate_b
            
            move_up_right:
              mov r3, 4
              b change_gamestate_b
    
            move_down_left:
              mov r3, -4
              b change_gamestate_b
    
            move_down:
              mov r3, -5
              b change_gamestate_b
            
            move_down_right:
              mov r3, -6
              b change_gamestate_b
    
            .type change_gamestate_b, %function
            @ args:
            @   r3: how much to change ball position by
            change_gamestate_b:
              
    
              ldr r1, =game_state
              ldr r2, [r1]
              push {r1}
            
              @ make a variable to remove position of last ball
              mov r0, 0b1
              mov r1, 24
              sub r1, r5
              lsl r0, r1
    
              eor r2, r0 @ remove last position of ball in game state
    
              add r5, r3 @ changes the position of the ball
    
              @ add new position of ball to game state
              mov r0, 0b1
              mov r1, 24
              sub r1, r5
              lsl r0, r1
              orr r2, r0
    
              pop {r1}
              str r2, [r1] @ store the game back into memory
    
    

    Update the paddle

        step_paddle:
        @ If paddle can move:
        @   move paddle
        @ Else:
        @   step timer
          cmp r6, 0
          beq move_left_p
          cmp r6, 1
          beq move_right_p
          cmp r6, 2
          beq no_move_p
          
          move_left_p:
            ldr r1, =game_state
            ldr r2, [r1]
            push {r1}
          
            @ makes a copy of r7 to alter
            mov r3, r7
            sub r3, 1
    
            @ removes the right side of the paddle from game state
            mov r0, 0b1
            mov r1, 24
            sub r1, r3
            lsl r0, r1
            eor r2, r0
    
            @ adds pixel to the left
            sub r1, 2
            mov r0, 0b1
            lsl r0, r1
            orr r2, r0
    
            add r7, 1 @ changes location of the paddle
    
            pop {r1}
            str r2, [r1]
    
            pop {lr}
            push {r4-r7}
            bx lr
          
           move_right_p:
            ldr r1, =game_state
            ldr r2, [r1]
            push {r1}
            @ makes a copy of r7 to alter
            mov r3, r7
    
            @ removes the left side of the paddle from game state
            mov r0, 0b1
            mov r1, 24
            sub r1, r3
            lsl r0, r1
            eor r2, r0
    
            @ adds pixel to the right
            add r1, 2
            mov r0, 0b1
            lsl r0, r1
            orr r2, r0
    
            sub r7, 1 @ changes location of the paddle
    
            pop {r1}
            str r2, [r1] @ store result back
    
            pop {lr}
            push {r4 - r7}
            bx lr
    
          no_move_p:
            pop {lr}
            push {r4-r7}
            bx lr
    

    Handle the ball rebounding off wall/paddle

    Rebounding off the walls

      check_game:
        @ checks if ball is on bound or paddle and changes direction accordingly
    
    
        .type check_ball, %function
        @ args:
        @   r5: position of ball
        @ returns:
        @   r4: adjested direction
        check_ball:
        @ Checks if the ball is on any bound
          
        @ Checks if ball is in top corner
        cmp r5, 20
        beq corner_rebound
        cmp r5, 24
        beq corner_rebound
    
        @ Checks if ball on roof
        cmp r5, 20
        bgt roof_rebound
    
        push {lr}
        @ Checks if ball is on right wall
        cmp r5, 5
        beq right_wall_rebound
    
        cmp r5, 10
        beq right_wall_rebound
        
        cmp r5, 15
        beq right_wall_rebound
    
        @ Checks if ball is on left wall
        cmp r5, 9
        beq left_wall_rebound
    
        cmp r5, 14
        beq left_wall_rebound
    
        cmp r5, 19
        beq left_wall_rebound
    
        @ if not on the edge, check if ball is on paddle
        b check_paddle 
    
        corner_rebound:
          push {lr}
          bl random_number @ Generate random number
          pop {lr}
          @ See if random number is odd
          mov r1, 0b1
          tst r0, r1
          bne set_down
          b set_opp
    
          set_down:
            @ set direction of ball to down
            
            mov r4, 0x4
            b check_paddle_pos @ returns to step ball
          
          set_opp:
            @ if direction up right, set direction down left
            cmp r4, 2
            beq set_down_left 
            
            @ else set the direction to down right
            mov r4, 5
            b check_paddle_pos @ returns to step ball
    
            set_down_left:
            mov r4, 3
            b check_paddle_pos @ returns to step ball
        
        roof_rebound:
          add r4, 3 @ changes direction of ball to the downwards (in same direction)
          b check_paddle_pos @ returns to step ball
    
        left_wall_rebound:
        @ makes sure when rebounding off wall it flips with direction
          pop {lr} @ needs to pop this as was not used (so later on can recall to main thred)
    
          cmp r4, 3
          blt lw_rebound_up @ sees if the ball is going up or down
    
          @ if it is going down, set to down rebound
          cmp r4, 4
          beq check_paddle_pos @ if ball going down directly, don't rebound
    
          mov r4, 5
          b check_paddle_pos 
    
            @ else set to up rebound
            lw_rebound_up:
    
              cmp r4, 1
              beq check_paddle_pos @ if ball going up directly, don't rebound
    
              mov r4, 2
              b check_paddle_pos
    
        
        right_wall_rebound:
        @ makes sure when rebounding off wall it flips with direction
          pop {lr} @ needs to pop this as was not used (so later on can recall to main thred)
    
          cmp r4, 3
          blt rw_rebound_up @ sees if the ball is going up or down
    
          @ if it is going down, set to down rebound
          cmp r4, 4
          beq check_paddle_pos @ if ball going down directly, don't rebound
    
          mov r4, 3
          b check_paddle_pos 
    
            @ else set to up rebound
            rw_rebound_up:
              cmp r4, 1
              beq check_paddle_pos @ if ball going up directly, don't rebound
    
              mov r4, 0
              b check_paddle_pos
    
    

    Rebounding off the paddle

    
    
        check_paddle:
        @ Checks if the ball is on the paddle
        @ If it is:
        @   go direction according to which pixel the ball hits on the paddle and if the paddle is moving
        
          mov r1, r7 @ coppies pos of paddle to scratch register
    
          add r1, 4 @ changing value of r1 to compair it to pssilble row
          cmp r1, r5 @ checks if ball is on paddle, left side
          IT eq
          bleq paddle_rebound
    
          add r1, 1
          cmp r1, r5 @ checks if ball is on paddle, right side
          IT eq
          bleq paddle_rebound
    
          bl check_paddle_pos
    
          pop {lr} @ return to step ball
    
          bx lr
    
          paddle_rebound:
            @ ball rebound from paddle
            @ changes direction of ball to something random
            push {lr}
            bl random_number @ Generate random number
            pop {lr}
            @ See if random number is odd
            mov r1, 0b1
            tst r0, r1
            bne set_up_p @ change the direction of the ball to directly up
            b set_away_p @ set the direction of the ball to logically opposite
    
            set_up_p:
              mov r4, 1
              bx lr
            
            set_away_p:
              @ checks if ball is heading down
              cmp r4, 4
              beq mix_dir @ if it is make sure it doesn't head straight up
    
              sub r4, 3 @ else make it go opposite direction
              bx lr
              
              mix_dir:
                @ set ball going left
                mov r4, 0
                bx lr
    
    

    Paddle AI

          check_paddle_pos:
            push {lr}
    
            bl ai_dir
    
            @ checks if paddle will try and go into the right wall
            cmp r7, 1
            IT eq
            bleq check_paddle_dir_right
    
            @ checks if paddle will try and go into the left wall
            cmp r7, 4
            IT eq
            bleq check_paddle_dir_left
    
            pop {lr}
            bx lr
    
            check_paddle_dir_right:
              cmp r6, 1
              IT ne
              bxne lr @ return if it is not
    
              @ else set direction to left 
              mov r6, 0
              bx lr
            
            check_paddle_dir_left:
              cmp r6, 0
              IT ne
              bxne lr @ returns if not trying to go into wall
    
              @ else set direction to right
              mov r6, 1
              bx lr
            
            ai_dir:
            @ change direction based on random number gen
              push {lr}
              bl random_number
              pop {lr}
    
              mov r1, 0b1
              tst r0, r1
              bne change_paddle_left
    
              mov r6, 1 @ change paddle direction right (ev)
              bx lr
    
              change_paddle_left:
              mov r6, 0 @ change paddle direction left
              bx lr
    
    

    Random Number Generator

      .type random_number, %function
      @ returns:
      @      r0: randomly generated number
    
      random_number:
        ldr r1, =0x4000D000 @ Base address to RNG
        mov r0, 0b1
        str r0, [r1] @ starts random number genorator
        mov r0, 0xffff
        pause_r:
          cmp r0, 0
          beq exit_r
          sub r0, 1
          b pause_r
    
        exit_r:
        @ stops rRNG
        mov r0, 0b1 
        str r0, [r1, 0x4]
        ldr r0, [r1, 0x508] @ stores result of RNG to output
        bx lr
    

    Static Variables

    .data
    game_state:
      .word  0b1100001000000000000000000
    reset_game_state:
      .word  0b1100001000000000000000000
    
    heart_on:
      .word 0b0010001110111111111101010 
    
    heart_off:
      .word 0b0010001010100011010101010