0

Hey guys, I wrote a program that reads a file and then displays its 8, 16 and 32 bit checksum as well as the XOR values. I've managed to do it and it works fine under windows(using qtspim) but on centos(using mars) I get the following errors:

Line 7 column five: "li": too many or incorrectly formatted operands. Expected li $t1, -100
Line 94 column 23: "$t0" : operand is of incorrect type
Line 97 column 23: "0xfffffffc" : operand is of incorrect type
Line 289 column 23: "$t1": operand is of incorrect type

I need to get it working in mars.I'd be grateful for your help.

and below source code: ( I marked the error lines on the left )

my code:

.text
main:

# extend data segment

    li      $v0, 9              # sbrk syscall
7 - li      $a0, 500000+4       # the the maximum data size (a multiple of 4) plus an extra word
    syscall
    bnez    $v0, store

    li      $v0, 4              # print error string
    la      $a0, memory_error
    syscall
    b       exit

store:
    sw      $v0, buffer         # store the file buffer address

# get input file name from user

get_filename:
    li      $v0, 4              # print prompt for input file
    la      $a0, prompt
    syscall

    li      $v0, 8              # read input filename
    la      $a0, filename
    li      $a1, 100
    syscall

# search for \n and replace it with terminating 0

    li      $t1, -1             # filename length (will be determined in the following loop)

search:
    lb      $t0, 0($a0)
    add     $a0, $a0, 1
    add     $t1, $t1, 1
    bne     $t0, 0x0a, search

    sb      $zero, -1($a0)

    beqz    $t1, exit           # exit if no filename was given

# open and read the file

    li      $v0, 13             # open file syscall
    la      $a0, filename
    li      $a1, 0              # flags
    li      $a2, 0              # mode (ignored)
    syscall
    bgez    $v0, read_file

    li      $v0, 4              # print error string
    la      $a0, open_error
    syscall
    b       exit

read_file:
    sw      $v0, descriptor

    li      $v0, 14             # read from file syscall
    lw      $a0, descriptor     # the file descriptor
    lw      $a1, buffer
    li      $a2, 500000         # max number of bytes to read
    syscall
    bgez    $v0, process

    li      $v0, 4              # print error string
    la      $a0, read_error
    syscall
    b       exit


process:
    srl     $s0, $v0, 1         # number of halfwords
    and     $t0, $v0, 0x1
    beqz    $t0, number_of_words
    add     $s0, $s0, 1         # round up (i.e. add 1) if the data size is not a multiple of 2

number_of_words:
    srl     $s1, $v0, 2         # number of words
    and     $t0, $v0, 0x3       # the remainder from division by 4 (number of effective data bytes in the last word)
    beqz    $t0, pad
    add     $s1, $s1, 1         # round up

# pad the data with 0s

pad:
    li      $t1, 4
    sub     $t0, $t1, $t0       # 4 minus the above remainder (specifies how many bytes to zero in a bit mask)
    sll     $t0, $t0, 3         # multiply by 8 to determine the number of zero bits to insert from the right 
    li      $t1, 0xffffffff     # initial value of the mask
94- srl     $t1, $t1, $t0       # insert zero bits and form actual bit mask (note: little endian order)

    add     $t2, $a1, $v0           # the address of the end of the data
97- and     $t2, $t2, 0xfffffffc    # the address (divisible by 4) that will be affected by the bit mask

    lw      $t0, ($t2)          # load the word that will contain the padding 0 bytes, note: this step can access (but not change) a whole extra word after the data when its size is a multiple of 4
    and     $t0, $t0, $t1       # zero the unused bytes (using the bit mask)
    sw      $t0, ($t2)          # store it

# modular sum

    # 8-bit checksum

    move    $t0, $v0            # number of bytes of the data (a counter)
    move    $t1, $a1            # the start address of the data
    li      $s2, 0              # clear the "accumulator"

sum8:
    lbu     $t2, ($t1)
    add     $t1, $t1, 1
    addu    $s2, $s2, $t2
    sub     $t0, $t0, 1
    bnez    $t0, sum8

    sll     $s2, $s2, 24        # sign extend byte to word (first align the sign bit of the byte to make use of arithmetic shifting)
    sra     $s2, $s2, 24        # insert the sign bit between bits 31-8

    # 16-bit checksum

    move    $t0, $s0
    move    $t1, $a1
    li      $s3, 0

sum16:
    lhu     $t2, ($t1)
    add     $t1, $t1, 2
    addu    $s3, $s3, $t2
    sub     $t0, $t0, 1
    bnez    $t0, sum16

    sll     $s3, $s3, 16        # sign extend halfword to word
    sra     $s3, $s3, 16

    # 32-bit checksum

    move    $t0, $s1
    move    $t1, $a1
    li      $s4, 0

sum32:
    lw      $t2, ($t1)
    add     $t1, $t1, 4
    addu    $s4, $s4, $t2
    sub     $t0, $t0, 1
    bnez    $t0, sum32

# parity check

    # 8-bit XOR value

    move    $t0, $v0
    move    $t1, $a1
    li      $s5, 0

xor8:
    lbu     $t2, ($t1)
    add     $t1, $t1, 1
    xor     $s5, $s5, $t2
    sub     $t0, $t0, 1
    bnez    $t0, xor8

    # 16-bit XOR value

    move    $t0, $s0
    move    $t1, $a1
    li      $s6, 0

xor16:
    lhu     $t2, ($t1)
    add     $t1, $t1, 2
    xor     $s6, $s6, $t2
    sub     $t0, $t0, 1
    bnez    $t0, xor16

    # 32-bit XOR value

    move    $t0, $s1
    move    $t1, $a1
    li      $s7, 0

xor32:
    lw      $t2, ($t1)
    add     $t1, $t1, 4
    xor     $s7, $s7, $t2
    sub     $t0, $t0, 1
    bnez    $t0, xor32


# report results to the user

    # 8-bit checksum

    li      $v0, 4              # print string
    la      $a0, checksum8
    syscall

    li      $v0, 1              # print int
    move    $a0, $s2
    syscall

    li      $v0, 4              # print string
    la      $a0, new_line
    syscall

    # 16-bit checksum

    li      $v0, 4              # print string
    la      $a0, checksum16
    syscall

    li      $v0, 1              # print int
    move    $a0, $s3
    syscall

    li      $v0, 4              # print string
    la      $a0, new_line
    syscall

    # 32-bit checksum

    li      $v0, 4              # print string
    la      $a0, checksum32
    syscall

    li      $v0, 1              # print int
    move    $a0, $s4
    syscall

    li      $v0, 4              # print string
    la      $a0, new_line
    syscall

    # 8-bit XOR value

    li      $v0, 4              # print string
    la      $a0, xor_value8
    syscall

    move    $a0, $s5            # the number to print
    li      $a1, 6              # start digit offset (6 implies a byte)
    jal     print_hex

    # 16-bit XOR value

    li      $v0, 4              # print string
    la      $a0, xor_value16
    syscall

    move    $a0, $s6            # the number to print
    li      $a1, 4              # type: halfword
    jal     print_hex

    # 32-bit XOR value

    li      $v0, 4              # print string
    la      $a0, xor_value32
    syscall

    move    $a0, $s7            # the number to print
    li      $a1, 0              # type: word
    jal     print_hex

close:
    li      $v0, 16             # close file syscall
    lw      $a0, descriptor     # the file descriptor
    syscall

    b       get_filename       # loop to process another file (or exit)

# exit the program

exit:
    li      $v0, 10
    syscall

# subroutine to print hexadecimal number

    # $a0 => number to print
    # $a1 => start digit: 0=word, 4=halfword, 6=byte

print_hex:
    la      $t0, hex            # address to store the string representation of a hexadecimal number
    li      $t1, 28             # shift count (to the right) of the most significant hexadecimal digit

hex_loop:
289 srl     $t2, $a0, $t1       # get a value of a hexadecimal digit
    and     $t2, $t2, 0xf       # mask unused bits
    bgtu    $t2, 9, letter

    add     $t2, $t2, 0x30      # a digit 0-9, add 0x30 to get actual ASCII code
    b       next_hex

letter:
    add     $t2, $t2, 0x57      # a letter a-f, add ('a'-10) to get actual ASCII code

next_hex:
    sb      $t2, ($t0)          # store the digit
    add     $t0, $t0, 1         # advance the pointer
    sub     $t1, $t1, 4         # update the shift count (to get another digit)
    bgez    $t1, hex_loop

    li      $v0, 4              # print string
    la      $a0, hex_prefix
    syscall

    li      $v0, 4              # print string
    la      $a0, hex
    add     $a0, $a0, $a1
    syscall

    jr      $ra


    .data
filename:       .space 16       # input filename

descriptor:     .word 0         # input file descriptor
buffer:         .word 0         # input file buffer address

prompt:         .asciiz "\nEnter the file name: "
memory_error:   .asciiz "Memory error (sbrk syscall failed)\n"
open_error:     .asciiz "Cannot open file\n"
read_error:     .asciiz "Cannot read file\n"

checksum8:      .asciiz "8-bit checksum:    "
checksum16:     .asciiz "16-bit checksum:   "
checksum32:     .asciiz "32-bit checksum:   "
xor_value8:     .asciiz "8-bit XOR value:   "
xor_value16:    .asciiz "16-bit XOR value:  "
xor_value32:    .asciiz "32-bit XOR value:  "
new_line:       .asciiz "\n"

hex_prefix:     .asciiz "0x"
hex:            .asciiz "????????\n"
2
Contributors
1
Reply
21
Views
3 Years
Discussion Span
Last Post by Schol-R-LEA
0

Sorry for the delay in getting to this, I missed it when it was on the front page earlier in the week.

For the first case (line 7), I am guessing that the problem is that the MARS assembler doesn't support adding two immediate sub-values. The simple solution is to do it as a single constant:

    li    $a0, 500004

For the two cases (lines 94 and 289) and where you are using SRL, you want to use SRLV instead; SRL works with an immediate value for the shift amount, whereas SRLV (Shift Right Logical Variable) takes a register value. I'm not sure why this worked on QtSPIM, as it isn't correct to begin with.

Conversely, on line 97, you are using an immediate value with AND, when it should be ANDI. Unfortunately, that shouldn't work either, as the value is too large for an immediate; you would need to do this:

    li    $t3, 0xfffffffc
    and   $t2, $t2, $t3

Unfortunately, since LI is actually a two-instruction macro, this means that it takes three instructions instead of one. Still, it's not too bad a cost. If you really need to save one cycle at that point, you could do this instead:

    addiu $t3, $zero, -3
    and   $t2, $t2, $t3

... but frankly, I wouldn't bother.

Edited by Schol-R-LEA

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.