AvaSmith-CodingSamples / Assembly / BatterySimulationProject - Assembly / batt_update_asm.s
batt_update_asm.s
Raw
.text
.global  set_batt_from_ports
        
# # ENTRY POINT FOR REQUIRED FUNCTION
  # # a useful technique for this problem
        # movX    SOME_GLOBAL_VAR(%rip), %reg
        # load global variable into register
        # Check the C type of the variable
        #    char / short / int / long
        # and use one of
        #    movb / movw / movl / movq 
        # and appropriately sized destination register    
set_batt_from_ports:
        

        # checks for positive voltage
        cmpw    $0, BATT_VOLTAGE_PORT(%rip)  # compares volts with zero
        jl      return_one                   # if negative, returns 1, fail 

        # calculating mvolts
        movq    $0, %rdx                     # clears register                    
        movw    BATT_VOLTAGE_PORT(%rip), %dx # moves batt voltage port into rdx register
        sarw    $1, %dx                     # conversion to mvolts

        movw    %dx, 0(%rdi)                # sets mvolts

        # mvolts bounds checking
        cmpw    $3000, %dx                  # comparing mvolts with 3000    
        jle     line_37_check               # if mvolts less than 3000, jmps to set percent to zero
    
       # calculating batt percent 
       # batt->percent = (batt->mlvolts - 3000) >> 3;
        subw    $3000, %dx                  # subtracting 3000 from mvolts
        sarw    $3, %dx                     # shifting ^^ to the right by 3
        andw    $0xFF, %dx
        
        movb    %dl, 2(%rdi)                # sets percent


jmp_back_37: # after setting percent above, jump here after setting percent to zero to continue

        # bounds checking
        movb    2(%rdi), %sil               # gets percent and moves it into sil    
        cmpb    $100, %sil                  # compares with one hundred
        jg      line_38_check               # jumps if greater than 100 to set to 100 (cap)    

jmp_back_38:                                # jumps back after setting percent to 100    
        # creates mask for checking bit
        movb    $1, %cl                     # sets cl to one
        salb    $4, %cl                     # moves left by four since bit we want to check is in fourth position    

        # tests to see if desired bit is one
        testb   %cl, BATT_STATUS_PORT(%rip) # tests to see if the fourth bit is one
        
        jz      line_41_else                # jumps if the fourth bit is not one, percent mode, sets mode to two    
        movb    $1, 3(%rdi)                 # if the bit is one (volt) mode is set to 1


        movq    $0x00, %rax                 # returns 0, sucsess
        ret
  
# set_bat_from_ports helpers
return_one:   # base case returns one    
        movq $0, %rax                       # clears register    
        movl $1, %eax                       # sets that register to one    
        ret                                 # returns one                                    

line_37_check: # sets percent to zero when volts are too low
        movb     $0, 2(%rdi)                # rdi (batt) percent field set to 0     
        jmp     jmp_back_37                 # jump to continue initializing batt    

line_38_check: # sets percent to 100 if volts too high
        movb    $100, 2(%rdi)               # rdi (batt) percent field capped to 100     
        jmp     jmp_back_38                 # jumps back to continue intializing batt    
line_41_else:   # sets mode to two and returns zero
        movb   $2, 3(%rdi)                  # sets rdi (batt)  mode field to be 2 for percent   

        movq    $0x00, %rax                 # returns 0 since sucsess, end of method
        ret




# ## Change to definint semi-global variables used with the next function 
# ## via the '.data' directive
# You can make your own data and then use it in function

.data
	
my_int:                         # declare location an single integer named 'my_int'
        .int 1234               # value 1234

other_int:                      # declare another int accessible via name 'other_int'
        .int 0b0101             # binary value as per C

my_array:                       # declare multiple ints sequentially starting at location
        .int 10                 # 'my_array' for an array. Each are spaced 4 bytes from the
        .int 0x00014            # next and can be given values using the same prefixes as 
        .int 0b11110 
        
# used for set_display_from_batt:, accsess to get number bit patterns for display
mask_array:
        .int 0b0111111
        .int 0b0000110
        .int 0b1011011
        .int 0b1001111
        .int 0b1100110
        .int 0b1101101
        .int 0b1111101
        .int 0b0000111
        .int 0b1111111
        .int 0b1101111

        


# # WARNING: Don't forget to switch back to .text as below
# # Otherwise you may get weird permission errors when executing 
.text
.global  set_display_from_batt

## ENTRY POINT FOR REQUIRED FUNCTION
	
set_display_from_batt:  
       
        # set up and determining mode
        movl $0, (%rsi)          # sets display to zero for start, line 73
        movq $0, %rax            # clears register          
        movq $0, %rcx            # clears register     
        movq $0, %rdx            # clears register     
        movl %edi, %ecx          # gets batt puts into ecx to extract mode
        sarl $24, %ecx           # shifts to the mode 
        
       # determines mode
        cmpl $2, %ecx            # compares the mode to 2 
        jne mode_1_percent       # if mode is not 2, it must be 1 so jump to percent

        # start of volts calculation when mode is 2
        movq $0, %r12            # clears register 
        movl $0b110, %r12d       # bit pattern for deciman and display 'v'
        orl %r12d, (%rsi)        # adds the bit pattern to the display
        # rcx = batt_mvolts

        

        movw %di, %cx           # moves mvolts (2bytes) into cx



       # gets rid of last digit and check if rounding is needed
        movq $0, %rax           # clears rax register
        movw %cx, %ax           # puts mvolts into rax
        movq $0, %r12           # clears register
        movw $10, %r12w         # moves ten in to be denomenator
        idivw %r12w             # divides mvolts by ten
        movw %ax, %cx           # moves remainder into cx

        cmpw $5, %dx            # check for rounding
        jge add_one             # if you need to add one jump to do so


         
        
round_return: # after rounding jump back for volts calculation
              # or if no rounding, continue for volts calculation

        # division division division to calculate volts
        # VVVV REGISTER KEY VVVVVVV
        # ecx is mvolts
        # eax gets rid of last digit when set back to rcx
        # rdx has the modulo number to set value
        # r12 holds the number 10
        # r13 hold pointer to mask array
        # r14 holds the binary that is being transfered to the display

        # setting up calculation
        movq $0, %r14                 # clear register
        movq $0, %r13                 # clear register  


        # set up continue
        leaq mask_array(%rip),%r13    # gets the array of the bit patterns for numbers
        movw %cx, %ax                 # puts the volts (without last digit) in ax register for division  
        movw $10, %r12w               # puts 10 into r12 register to be denominator  
        
        # calculating digit 1
        movq $0, %rdx                 # initialize remainder variable  
        idivw %r12w                   # divide/modulo volts by 10  

        movl (%r13, %rdx, 4), %r14d   # gets the bit pattern based on remainder  
        sall $3, %r14d                # shift to get into position to or  
        orl  %r14d, (%rsi)            # adds new number bit pattern to display  

        # calculate digit 2
        movw $10, %r12w               # puts 10 into r12 register to be denominator   
        movq $0, %rdx                 # initialize remainder variable 
        idivw %r12w                   # divide/modulo leftover of volts by 10               
        movl (%r13,%rdx,4), %r14d     # gets the bit pattern based on remainder   
        sall $10, %r14d               # shift to get into position to or    
        orl %r14d, (%rsi)             # adds new number bit pattern to display    

        # calculate digit 3
        movw $10, %r12w               # puts 10 into r12 register to be denominator  
        movq $0, %rdx                 # initialize remainder variable   
        idivw %r12w                   # divide/modulo leftover of volts by 10           
        movl (%r13,%rdx,4), %r14d     # gets the bit pattern based on remainder  
        sall $17, %r14d               # shift to get into position to or    
        orl %r14d, (%rsi)             # adds new number bit pattern to display  

        

percent_return: # both the percent version and volts version needs a battery update
# so if percent, jumps back here, or continues on if volts

        # battery manager, getting percent
        movq $0, %r15                 # clears register used to hold battery percent  
        movl %edi, %r15d              # moves batt to be turned into battery percent  
        sarl $16, %r15d               # r15b now has battpercent in it  

        # comparing percent to know how many bars to add
        cmpb $90, %r15b               # if above 90, jumps to set correct bit pattern   
        jge percent90

        cmpb $70, %r15b               # if above 70, jumps to set correct bit pattern   
        jge percent70

        cmpb $50, %r15b               # if above 50, jumps to set correct bit pattern   
        jge percent50

        cmpb $30, %r15b               # if above 30, jumps to set correct bit pattern   
        jge percent30

        cmpb $5, %r15b                # if above 5, jumps to set correct bit pattern   
        jge percent5

                                
 # if no bars of battery V end method return 0, sucsses       
return_0: # returns 0
        movq $0, %rax
        ret
percent5: # if battery is at one bar
        movq $0, %r12                # clear register   
        movl $0b00001, %r12d         # moves one bar bit pattern into register     
        sall $24, %r12d              # shifts it to correct position   
        orl %r12d, (%rsi)            # adds to display   
        jmp return_0                 # end method, sucsses   

percent30:
        movq $0, %r12                # clear register      
        movl $0b00011, %r12d         # moves two bar bit pattern into register     
        sall $24, %r12d              # shifts it to correct position     
        orl %r12d, (%rsi)            # adds to display
        jmp return_0                 # end method, sucsses 

percent50:
        movq $0, %r12                # clear register 
        movl $0b00111, %r12d         # moves three bar bit pattern into register 
        sall $24, %r12d              # shifts it to correct position
        orl %r12d, (%rsi)            # adds to display
        jmp return_0                 # end method, sucsses 

percent70:
        movq $0, %r12                # clear register 
        movl $0b01111, %r12d         # moves four bar bit pattern into register 
        sall $24, %r12d              # shifts it to correct position
        orl %r12d, (%rsi)            # adds to display
        jmp return_0                 # end method, succsses 

percent90:
        movq $0, %r12                # clear register 
        movl $0b11111, %r12d         # moves five bar bit pattern into register 
        sall $24, %r12d              # shifts it to correct position
        orl %r12d, (%rsi)            # adds to display
        jmp return_0                 # end method, sucsses 




       




mode_1_percent:

        # division division division to caulate the percent
        # VVVV REGISTER KEY VVVVVVVV
        # ecx is mvolts
        # eax gets rid of last digit when set back to rcx
        # rdx has the modulo number to set value
        # r12 holds the number 10
        # r13 hold pointer to mask array
        # r14 holds the binary that is being transfered to the display
        # setting 'p' and no decimal
        movq $0, %r12                   # clear register
        movl $0b001, %r12d              # bit pattern for percent sign and no decimal
        orl %r12d, (%rsi)               # adds the bit pattern to display

        # set up for calulation
        movl %edi, %ecx                 # moves batt into ecx to extract percent 
        sarl $16, %ecx                  # moves to percent bits
        movq $0, %r14                   # clears register
        movq $0, %r13                   # clears register

        leaq    mask_array(%rip),%r13   # get the bit array with number masks
       
       # calculation begins, digit one
        movq $0, %rax                   # clear register
        movb %cl, %al                   # moves percent into %rax

        movq $0, %r12                   # clear register
        movb $10, %r12b                 # moves ten into register to be denominator
        movq $0, %rdx                   # clear remainder register
        

        idivq %r12                      # divide/modulo by 10

        
        
        movl (%r13, %rdx, 4), %r14d     # gets mask based on remainder and stores in register r14
        sall $3, %r14d                  # moves the bit mask into position
        orl %r14d, (%rsi)               # adds it to display

        cmpb $0, %al                    # checks if we are at the last digit
        je percent_return               # if so returns to add battery bits

        # calculate digit two
        movb $10, %r12b                 # moves ten into register to be denominator

        movq $0, %rdx                   # clear remainder register
        idivq %r12                      # divide/modulo by 10

        movl (%r13, %rdx, 4), %r14d     # gets corresponding bit mask from remainder
        sall $10, %r14d                 # shifts bit mask into position
        orl %r14d, (%rsi)               # adds bits to display

        cmpb $0, %al                    # checks if we are at the last digit
        je percent_return               # if so returns to add battery bits

        # calculates third digit
        movq $0, %rdx                   # clear remainder register
        
        idivq %r12                      # divide/modulo by 10

        movl (%r13, %rdx, 4), %r14d     # get bit mask corresponding to remainder
        sall $17, %r14d                 # shifts bit mask into position
        orl %r14d, (%rsi)               # adds bit mask to display

        jmp percent_return              # no more possible digits, jumps to calculate battery digits


add_one:        # uesed when rounding for mvolts

        addl $1, %ecx           # adds one to ecx, which holds volt number
        jmp round_return        # returns back to continue volt calculation
# # ENTRY POINT FOR REQUIRED FUNCTION

.text
.global batt_update


batt_update:
	# # assembly instructions here 
        pushq $0 # create space for batt and aligns for call
        movq %rsp, %rdi # moves address of port into rdi

        call set_batt_from_ports # calls set batt from ports with rdi as input rax as output
        

        cmpq $1, %rax                   # error check
        je return_one_update            # is fails returns one

        leaq 4(%rsp), %rsi              # gets the adress for the diaply
        movl (%rdi), %edi               # moves the value of the batt into edi
        
        call set_display_from_batt
        movq (%rsi), %rsi               # gets the value of rsi back into rsi 
        movl %esi, BATT_DISPLAY_PORT(%rip) # puts the display into the global display value
        popq %rsi                       # free space from pushing


        

       # returns 0 for sucsess
        movq $0, %rax
        ret

    
return_one_update: # i f fails
        popq %rsi  # bring back stack from push
        movq $1, %rax   # returns one for failure
        ret