Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # syscall constants
- PRINT_STRING = 4
- PRINT_CHAR = 11
- PRINT_INT = 1
- # memory-mapped I/O
- VELOCITY = 0xffff0010
- ANGLE = 0xffff0014
- ANGLE_CONTROL = 0xffff0018
- BOT_X = 0xffff0020
- BOT_Y = 0xffff0024
- TIMER = 0xffff001c
- TILE_SCAN = 0xffff0024
- HARVEST_TILE = 0xffff0020
- GET_FIRE_LOC = 0xffff0028
- PUT_OUT_FIRE = 0xffff0040
- PRINT_INT_ADDR = 0xffff0080
- PRINT_FLOAT_ADDR = 0xffff0084
- PRINT_HEX_ADDR = 0xffff0088
- # interrupt constants
- BONK_MASK = 0x1000
- BONK_ACK = 0xffff0060
- TIMER_MASK = 0x8000
- TIMER_ACK = 0xffff006c
- ON_FIRE_MASK = 0x400
- ON_FIRE_ACK = 0xffff0050
- # a macro for a good velocity for the bot
- A_GOOD_SPEED = 10
- .data
- .align 2
- tile_data:
- .space 1600
- .text
- #------------------------------------------------------------------------START
- main:
- #Tell the bot to stop moving
- sw $0, VELOCITY
- #First initialize shared data structures (set up the queue)
- la $t0, fire_queue_head_idx
- sw $0, 0($t0) #head_idx= 0
- la $t0 fire_queue_tail_idx
- sw $0, 0($t0) #tail_idx = 0
- # Next enable fire interrupts
- li $t0, ON_FIRE_MASK
- or $t0, $t0, 1 #Global interrupt enable
- mtc0 $t0, $12
- #Now just poll the fire_queue and start putting out fires
- la $s0, fire_queue_x
- la $s1, fire_queue_y
- fire_loop:
- la $s2, fire_queue_head_idx
- lw $s3, 0($s2) #s2 = &head_idx
- la $s4, fire_queue_tail_idx
- lw $s4, 0($s4)
- bge $s3, $s4, fire_loop #If the queue is empty, keep waiting for a fire_interrupt
- #--- If the queue is non_empty pull the x and y coordinates at fire_queue_x[head_idx] and fire_queue_y[head_idx]----
- mul $t2, $s3, 4
- add $t0, $t2, $s0
- add $t1, $t2, $s1 #t0 = &target_x, t1 = &target_y
- #--- Save the $a registers and then load arguments for call to move_to_tile----
- sw $a0, -4($sp)
- sw $a1, -8($sp)
- sub $sp, $sp, 8
- lw $a0, 0($t1) #t0 = fire_queue_x[head_idx] (row)
- lw $a1, 0($t0) #t1 = fire_queue_y[head_idx](column)
- jal move_to_tile
- move $t2, $a0
- move $t3, $a1
- lw $a1, 0($sp)
- lw $a0, 4($sp)
- addi $sp, $sp, 8
- #----we're now on a tile that should be on fire, check if we can salvage the plant, if so put it out----
- la $t1, tile_data
- sw $t1, TILE_SCAN
- mul $t2, $t2, 10
- add $t2, $t2, $t3 #t2 has linear index of tile tile_data
- la $t3, tile_data
- mul $t2, $t2, 16
- add $t3, $t3, $t2 # t3 has the address of the Tile_info struct we want
- lw $t3, 0($t3) # t3 has the state of the current struct
- beq $t3, 0, ignore # if state is 0, it's too late to save the plant
- lw $t3, PUT_OUT_FIRE
- #----t2 contains whether attempt was a success or not if we want to requeue the fire -----
- ignore:
- addi $s3, $s3, 1
- sw $s3, 0($s2) #head_idx++
- j fire_loop #infinite fire seeking loop
- jr $ra
- #--------------------------------------------------------------------------END
- # void move_to_tile(int row, int column)-----------------------------------START
- move_to_tile:
- sw $s0, -4($sp)
- sw $s1, -8($sp)
- sw $s2, -12($sp)
- sw $s3, -16($sp)
- sub $sp, $sp, 16
- #-------------------
- # first get SPIMbot's current coordinates
- lw $s0, BOT_Y #s0 = curr_y
- lw $s1, BOT_X #s1 = curr_x
- #now load target coordinates
- move $s2,$a0
- mul $s2, $s2, 30
- addi $s2, $s2, 15 #s2 = target_y
- move $s3,$a1
- mul $s3, $s3, 30
- addi $s3, $s3, 15 #s3 = target_x
- #--------now move in the y direction until you hit target_y----
- # here we are moving up
- li $t0, -90
- #do a check for which direction we need to move
- bge $s0, $s2, set_velocity_y
- #turn SPIMbot to face down
- li $t0, 90
- set_velocity_y:
- sw $t0, ANGLE
- li $t1, 1
- sw $t1, ANGLE_CONTROL
- # spim bot is now facing in the required direction
- li $t0, A_GOOD_SPEED
- sw $t0, VELOCITY
- wait_till_target_y:
- lw $t0, BOT_Y
- bne $t0, $s2, wait_till_target_y
- sw $0, VELOCITY
- #------ Now move in the x direction until we get where we need to go
- #intialize SPIMbot to face -x
- li $t0, 180
- #do a check for which direction we need to move
- bge $s1, $s3, set_velocity_x
- #turn SPIMbot to face +x
- li $t0, 0
- set_velocity_x:
- sw $t0, ANGLE
- li $t1, 1
- sw $t1, ANGLE_CONTROL
- # spim bot is now facing in the required direction
- li $t0, A_GOOD_SPEED
- sw $t0, VELOCITY
- wait_till_target_x:
- lw $t0, BOT_X
- bne $t0, $s3, wait_till_target_x
- sw $0, VELOCITY
- #-------Spim bot is at the required place, now we just return ----
- lw $s3, 0($sp)
- lw $s2, 4($sp)
- lw $s1, 8($sp)
- lw $s0, 12($sp)
- addi $sp, $sp, 16
- jr $ra
- #------------------------------------------------------------------------END
- .data #this is data shared by the interrupt handler and the user program (driver??)
- fire_queue_head_idx: .space 4
- fire_queue_x:.space 400
- fire_queue_y:.space 400
- fire_queue_tail_idx: .space 4
- .kdata
- chunkIH: .space 16 # space here based on how many registers i need, because i need to save and restore all
- unhandled_str: .asciiz "Unhandled interrupt type\n"
- .ktext 0x80000180
- #------------------------------------------------------------------------START
- interrupt_handler:
- la $k0, chunkIH
- .set noat # this allows me to access $at directly
- sw $at, 0($k0)
- .set at
- sw $a0, 4($k0) #save a0 and a1
- sw $a1, 8($k0)
- sw $v0, 12($k0)
- #----we don't have any exceptions but if we did we would check for them here -----
- interrupt_dispatch:
- mfc0 $k0, $13 # move the cause register into k0
- beq $k0, $0, done # if the cause_register is 0, interrupts were handled and we're done
- #----otherwise we have several dispatch checks for every interrupt it could be ---
- and $a0, $k0, ON_FIRE_MASK
- bne $a0, $0, fire_interrupt #If a fire interrupt was triggered, handle it
- #----Put more interrupt checks above this --------------------------
- li $v0, PRINT_STRING
- la $a0, unhandled_str
- syscall
- j done
- fire_interrupt:
- lw $a0, GET_FIRE_LOC # get the location of fire as a 32-bit int
- sw $a1, ON_FIRE_ACK # acknowledge fire interrupt to allow more (send_eoi)
- # ----Get flaming tile coordinates -------
- srl $k0, $a0, 16 #shift out the y bits to get x index
- and $k1, $a0, 0xffff #mask the top 16 bits to get the y index
- # --- Now we have the row and column of the fire, put it on the fire_queue ---
- la $a0, fire_queue_tail_idx
- lw $v0, 0($a0) #a0 = tail_idx
- addi $a1, $v0, 1
- sw $a1, 0($a0) #tail_idx++
- mul $a0, $v0, 4
- la $a1, fire_queue_x
- add $a1, $a1, $a0
- sw $k0, 0($a1) #fire_queue_x[(old)tail_idx] = target_x
- la $a1, fire_queue_y
- add $a1, $a1, $a0
- sw $k1, 0($a1) #fire_queue_y[(old) tail_idx] = target_y
- j interrupt_dispatch
- timer_interrupt:
- #do nothing because we don't have timer interrupts
- done:
- la $k0, chunkIH
- lw $a0, 4($k0) # Restore saved registers
- lw $a1, 8($k0)
- lw $v0, 12($k0)
- .set noat
- lw $at, 0($k0) # Restore $at
- .set at
- eret
- #---------------------------------------------------------------------------END
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement