mnkyskilz 0 Newbie Poster

hi i am required to write a program in mips assembler where i am to create a checkerboard which is too be saved and written to a bmp file, compile this program it has a problem with writing the file because it jumps straight to my error message could someone please help me with this problem. Here is the code:

    .data
    .align 0
bmpheader:
    .ascii "BM" # 00>BITMAPFILEHEADER.bfType
    .word 0     # 02>BITMAPFILEHEADER.bfSize
    .half 0     # 06>BITMAPFILEHEADER.bfReserved1
    .half 0     # 08>BITMAPFILEHEADER.bfReserved2
    .word 62    # 10>BITMAPFILEHEADER.bfOffBits

    .word 40    # 14>BITMAPINFOHEADER.biSize
    .word 0     # 18>BITMAPINFOHEADER.biWidth
    .word 0     # 22>BITMAPINFOHEADER.biHeight
    .half 1     # 26>BITMAPINFOHEADER.biPlanes
    .half 1     # 28>BITMAPINFOHEADER.biBitCount
    .word 0     # 30>BITMAPINFOHEADER.biCompression
    .word 0     # 34>BITMAPINFOHEADER.biSizeImage;
    .word 0     # 38>BITMAPINFOHEADER.biXPelsPerMeter
    .word 0     # 42>BITMAPINFOHEADER.biYPelsPerMeter
    .word 0     # 46>BITMAPINFOHEADER.biClrUsed
    .word 0     # 50>BITMAPINFOHEADER.biClrImportant

    .byte 0x00 0x00 0x00 0x00   # first palette color (0 bits)
    .byte 0xff 0xff 0xff 0x00   # second palette color (1 bits)

arg1:   .asciiz "Enter square size: "
arg2:   .asciiz "Enter checkerboard size: "

arg1_error:     .asciiz "Illegal value of square size\n"
arg2_error:     .asciiz "Illegal value of checkerboard size\n"
mem_error:      .asciiz "Memory allocation error\n"
file_open_error:    .asciiz "Open file error\n"
file_write_error:   .asciiz "Write file error\n"

bmp_file:   .asciiz "chkboard.bmp"

ok_message: .asciiz "OK\n"


    .text
main:
    #----Get args from user----

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

    li  $v0, 5          # read integer
    syscall



    slti    $t0, $v0, 1
    sgt $t1, $v0, 100
    or  $t0, $t0, $t1
    beqz    $t0, get_arg2

    li  $v0, 4          # print string
    la  $a0, arg1_error
    syscall
    b   exit            # exit the program

get_arg2:
    move    $s0, $v0        # square size in $s0

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

    li  $v0, 5          # read integer
    syscall


    slti    $t0, $v0, 1
    sgt $t1, $v0, 100
    or  $t0, $t0, $t1
    beqz    $t0, set_header

    li  $v0, 4          # print string
    la  $a0, arg2_error
    syscall
    b   exit            # exit the program

set_header:
    move    $s1, $v0        # checkerboard size in $s1

    mul $a0, $s0, $s1
    add $t0, $a0, 0x0000001f
    andi    $t0, $t0, 0xffffffe0
    srl $s2, $t0, 3     # number of bytes per line in $s2

    la  $t0, bmpheader
    usw $a0, 18($t0)        # bitmap width
    usw $a0, 22($t0)        # bitmap height
    mul $a0, $a0, $s2       # bitmap pixels data size
    add $t1, $a0, 62
    usw $t1, 2($t0)     # bitmap file size
    usw $a0, 34($t0)        # BITMAPINFOHEADER.biSizeImage

    li  $v0, 9          # alloc memory
    syscall
    bnez    $v0, checkerboard

    li  $v0, 4          # print string
    la  $a0, mem_error
    syscall
    b   exit            # exit the program

checkerboard:
    move    $s3, $v0        # start address of pixels in memory in $s3
    move    $s4, $a0        # pixels data size in $s4

    move    $t0, $zero      # square flag
    move    $t1, $s3        # start address of a line
    move    $t2, $s1        # vertcal square counter (number of rows)

    #----Single line of pixels----

line:
    move    $t3, $t1        # pixel address
    li  $t4, 0x80       # pixel mask
    move    $t5, $s1        # square counter (in a line)
    move    $t6, $s0        # pixel counter (in a square)
                    # temporary buffer in $t7 (actually it needn't to be initialized)
pixel:
    beqz    $t0, clear      # if square flag is 0, branch to "clear" (current pixel is cleared)
    or  $t7, $t7, $t4       # otherwise, set the current pixel (we do it on the temporary buffer using our pixel mask)
    b   shift
clear:
    not $t8, $t4        # pixel mask inverted (because we need to do logical AND)
    and $t7, $t7, $t8       # clear the pixel

shift:
    srl $t4, $t4, 1     # shift the pixel mask one bit right (because we want to address the next pixel on the right)
    bnez    $t4, next       # if the mask is nonzero (so we are still on the same byte), branch to "next"
    sb  $t7, ($t3)      # otherwise (i.e. we have to address the next byte), store the whole previous byte from temporary buffer
    add $t3, $t3, 1     # increment the address, so it points to the next byte
    li  $t4, 0x80       # and reset the pixel mask, so it addresses the leftmost pixel in a byte

next:
    sub $t6, $t6, 1     # decrement the pixel counter in a square
    bnez    $t6, pixel      # repeat to produce one line of a black or white square

    move    $t6, $s0        # reset the pixel counter in a square (to square size - the first program argument)
    not $t0, $t0        # invert the square flag (if we have made a line of a black square, now we will make a line of a white square and vice versa)

    sub $t5, $t5, 1     # decrement the square counter in a line
    bnez    $t5, pixel      # loop if we haven't complete the whole line

    beq $t4, 0x80, advance  # if pixel mask is 0x80 (which means we've completed and stored the whole byte in memory), skip storing the buffer
    sb  $t7, ($t3)      # otherwise we have to "flush" the buffer

    #----Duplicate the line----

advance:
    add $t1, $t1, $s2       # move to the next line (add the line length in bytes to the start address of the line)

    sub $t6, $t6, 1     # this register (see above) contains the square size (in pixels) so we can use it as a counter for how many times to copy the line to produce a row of checkerboard
    beqz    $t6, row        # if the square size is 1, there is no need to do anything else (because the line have already been generated)

duplicate:
    sub $t3, $t1, $s2       # the address of the previous line (that one that was first generated or the one just copied)
    move    $t4, $t1        # the address of the current line

    move    $t5, $s2        # set byte counter (how many bytes to copy) to the line length, this value is a multiple of 4
copy:
    lw  $t7, ($t3)      # load a word from the source (previous) line
    add $t3, $t3, 4     # increment the source pointer
    sw  $t7, ($t4)      # store the word to the destination (current) line
    add $t4, $t4, 4     # increment the destination pointer
    sub $t5, $t5, 4     # decrement the byte counter
    bnez    $t5, copy       # loop if there's any data left for copying

    add $t1, $t1, $s2       # move to the next line (add the line length in bytes to the start address of the current line)

    sub $t6, $t6, 1     # decrement the line counter in a row of the checkerboard
    bnez    $t6, duplicate      # repeat to complete the row

row:
    move    $t6, $s0        # reset the pixel counter in a square (to square size - the first program argument)

    and $t5, $s1, 1     # check if bit 0 of checkerboard size value is set (i.e. simply check if the value is even)
    bnez    $t5, count      # and if not, branch to "count"

    not $t0, $t0        # negate logically the square flag

count:
    sub $t2, $t2, 1     # decrement the row counter
    bnez    $t2, line       # repeat if not done

    #----Write .BMP file (header+data)----

    li  $v0, 13         # open file
    la  $a0, bmp_file       # file path
    li  $a1, 0x8301     # flags WRITE|CREATE|TRUNCATE|BINARY
    li  $a2, 0x1a4      # 0644 UNIX mode (rw-r--r--)
    syscall
    bgez    $v0, write_file
    li  $v0, 4          # print string
    la  $a0, file_open_error
    syscall
    b   exit            # exit the program



write_file:
    move    $a0, $v0        # file descriptor

    li  $v0, 15         # write to file
    la  $a1, bmpheader      # file buffer
    li  $a2, 62         # number of bytes to write
    syscall
    bgez    $v0, write_data

    li  $v0, 4          # print string
    la  $a0, file_write_error
    syscall
    b   exit            # exit the program  


write_data:
    li  $v0, 15         # write to file
    move    $a1, $s3        # file buffer
    move    $a2, $s4        # number of bytes to write
    syscall
    bgez    $v0, close_file

    li  $v0, 4          # print string
    la  $a0, file_write_error
    syscall
    b   exit            # exit the program



close_file:
    li  $v0, 16         # close file syscall
    syscall

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


exit:
    li  $v0, 10         # exit the program
    syscall