Bitwise IO/MIPS Assembly

From Rosetta Code
Revision as of 18:06, 8 June 2010 by rosettacode>ShinTakezou (real mips implementation)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

<lang mips> .data

  1. the following are used by the subroutines

bitbuf: .byte 0, 0 cumulus: .word 0 rbitbuf: .byte 0, 0 rfree: .word 0

  1. these are instead for testing

outbuf: .space 16 abuf: .space 16

txt: .asciiz "This is a test"


   .text

main:

   # ---- encode txt to buf -----
   la    $s0, txt
   la    $s1, outbuf

encloop:

   lbu   $a0, ($s0)
   beq   $a0, $0, txtend
   li    $a1, 7
   move  $a2, $s1
   jal   bits_write
   addu  $s0, $s0, 1
   move  $s1, $v1
   b     encloop

txtend:

   move  $a1, $s1
   jal   bits_flush
   move  $s1, $v0     # update buf, will be used as "terminator"
   la    $s0, outbuf
   # ---- write buffer

wrtchar:

   beq   $s0, $s1, wrtend # while $s0 < $s1 {
   lb    $a0, ($s0)
   li    $v0, 11
   syscall                #   print_char($a0)
   addi  $s0, $s0, 1      #   inc $s0
   b     wrtchar          # }

wrtend:

   # ---- decode from buffer in bufferb----
   # $s1 is still our end marker
   la    $s3, outbuf           # prev. output becomes input
   li    $s7, 7                # commodity
   la    $s4, abuf             # current output buf

decloop:

   bge   $s3, $s1, decend      # while $s3(input) < $s1(limit)
   move  $a0, $0               #   clean acc.
   move  $a1, $s7              #   7 bits
   move  $a2, $s3              #   from input buf
   jal   bits_read             #   read 7 bits into acc.
   move  $s3, $v0              #   update input buf
   sb    $v1, ($s4)
   addi  $s4, $s4, 1           #   write char and update outp buf ptr
   b     decloop               # end while

decend:

   # lets output abuf; $s4 points to end of abuf,
   # we need to mark it with 0 to print it as a str
   sb    $0, ($s4)
   la    $a0, abuf
   li    $v0, 4
   syscall                     # print_string(abuf)
   li    $v0, 10               # exit
   syscall


  1. read_bits
  2. $a0 acc.
  3. $a1 how many (max 32)
  4. $a2 input buffer
  5. > $v1 (new acc)
  6. > $t0 num of read bits or less (failure)
  7. > $v0 updated input buffer

bits_read:

   sub   $sp, $sp, 20          # local vars
   sw    $ra, 0($sp)           # save regs
   sw    $s0, 4($sp)
   sw    $s1, 8($sp)
   sw    $s2, 12($sp)
   sw    $s3, 16($sp)
   move  $s3, $a2              # $s3 input buf
   move  $s0, $a0              # $s0 acc
   move  $s1, $a1              # $s1 n
   move  $s2, $0               # rbit = 0
   li    $t0, 32
   bgt   $a1, $t0, brexit      # if n > 32 then return

brloop:

   ble   $s1, $0, brexit       # while n > 0 (if <= 0 break)
   move  $a0, $s0
   move  $a1, $s3
   jal   read_bit              #   read 1 bit into acc.
   move  $s3, $v0              #   update input buf
   li    $t1, 1
   bne   $t0, $t1, brexit      #   exit if not read
   move  $s0, $v1              #   get updated acc
   sub   $s1, $s1, 1           #   n--
   addi  $s2, $s2, 1           #   rbit++
   b     brloop

brexit:

   move  $t0, $s2              # currently read bits
   move  $v1, $s0              # new accumulator
   move  $v0, $s3              # updated input ptr
   lw    $ra, 0($sp)           # restore regs
   lw    $s0, 4($sp)
   lw    $s1, 8($sp)
   lw    $s2, 12($sp)
   lw    $s3, 16($sp)
   addu  $sp, $sp, 20          # and free stack
   jr    $ra                   # return


  1. get last (maybe incomplete) accumulated byte
  2. $a0 accumulator
  3. >$v0 free storage

bits_getlast:

   lw    $t0, rfree
   li    $t1, 8   
   sub   $t1, $t1, $t0          # sochar - rfree
   sllv  $a0, $a0, $t1          # *d << (8 - rfree)
   lbu   $t2, rbitbuf
   srlv  $t2, $t2, $t0          # rbitbuf >> rfree
   sb    $0, rbitbuf            # rbitbuf = 0
   sw    $0, rfree              # rfree = 0
   move  $v0, $t1               
   jr    $ra                    # return sochar - rfree


  1. read a single bit
  2. $a0 accumulator
  3. $a1 input buffer
  4. > $v1 new accumulator
  5. > $t0 bit read (1 or not 1; in this impl, reading
  6. can't fail unless input buffer is an invalid ptr
  7. > $v0 updated input buffer

read_bit:

   sub    $sp, $sp, 20          # local stack,
   sw     $s0, 0($sp)           # save regs
   sw     $s1, 4($sp)
   sw     $s2, 8($sp)
   sw     $s3, 16($sp)
   move   $s0, $a0              # save args
   move   $s3, $a1              # $s0 = acc, $s3 = inbuf
   lw     $s1, rfree            # preload rfree and
   lbu    $s2, rbitbuf          # rbitbuf
   bne    $s1, $0, skipif       # if rfree == 0 then
   lbu    $s2, ($s3)            # rbitbuf = nextchar()
   addi   $s3, $s3, 1           # update it inp buf
   li     $s1, 8                #   rfree = 8

skipif:

   sll    $s0, $s0, 1           #   *d << 1
   srl    $t0, $s2, 7           #   rbitbuf >> (8-1)
   andi   $t0, $t0, 1           #     & 1
   or     $s0, $s0, $t0         #         | *d
   sll    $s2, $s2, 1           #   rbitbuf << 1
   sub    $s1, $s1, 1           #   rfree--
   sw     $s1, rfree
   sb     $s2, rbitbuf          # update rfree, rbitbuf
   li     $t0, 1                # $t0 returns 1
   move   $v1, $s0              # return the acc. in $v1
   move   $v0, $s3              # and updated inp buf in $v0
   lw     $s0, 0($sp)           # restore regs
   lw     $s1, 4($sp)  
   lw     $s2, 8($sp) 
   lw     $s3, 16($sp)
   add    $sp, $sp, 20          # .. and stack
   jr     $ra                   # return($v0, $v1)


  1. bits_write; write upto 32 bits
  2. $a0 holds the bits (right aligned)
  3. $a1 how many bits are significative
  4. $a2 dest buf
  5. > $v1 updated buf ptr
  6. > $v0 written bits (-1 on error)

bits_write:

   sub    $sp, $sp, 28          # some local storage
   sw     $fp, 20($sp)
   move   $fp, $sp
   sw     $s1, 4($fp)           # save regs and values
   sw     $s0, 0($fp)
   sw     $s2, 8($fp)
   sw     $s3, 12($fp)
   sw     $ra, 16($fp)
   sw     $s4, 24($fp)
   move   $s4, $a2
   move   $s1, $a1              # n is $s1
   li     $t0, 32
   bgt    $a1, $t0, error       # n > 32 => return(-1)
   
   sub    $t0, $t0, $a1         # 32 - n
   sllv   $s0, $a0, $t0         # d << (32-n)
   move   $s3, $0

loop:

   blez   $s1, exit0            # if n <= 0 then break
   sub    $s1, $s1, 1           # n--
   addu   $s3, $s3, 1           # wbit++
   move   $a0, $s0
   rol    $a0, $a0, 1           # place "last" bit in first pos.
   move   $a1, $s4
   jal    appendbit             # append it
   sll    $s0, $s0, 1           # dpad << 1
   move   $s4, $v1              # update buf ptr
   b      loop                  # loop

error:

   li     $v0, -1
   b      exit

exit0:

   move   $v0, $s3

exit:

   lw     $s1, 4($fp)           # restore regs
   lw     $s0, 0($fp)
   lw     $s2, 8($fp)
   lw     $s3, 12($fp)
   move   $v1, $s4
   lw     $s4, 24($fp)
   lw     $ra, 16($fp)
   move   $sp, $fp              # and release stack
   lw     $fp, 20($sp)
   addi   $sp, $sp, 28
   jr     $ra                   # return wbit, ptr to byte beyond last
                                # written


  1. flush bits
  2. $a1 output buf
  3. >$v0 adv. ptr to buf.

bits_flush:

   li     $t0, 8
   lw     $t1, cumulus
   sub    $t0, $t0, $t1         # 8 - cumulus
   lbu    $a0, bitbuf
   sllv   $a0, $a0, $t0         # bitbuf <<= (8 - cumulus)
   sb     $a0, ($a1)            # write to buf
   addi   $v0, $a1, 1           # inc buf ptr
   sb     $0, bitbuf            # bitbuf := 0
   sw     $0, cumulus           # cumulus := 0
   jr     $ra


  1. add a single bit.
  2. $a0 holds the bit (as LSB i.e. "rightmost bit")
  3. $a1 output buf
  4. > $v0 number of written bits (always 1)
  5. > $v1 incremented buf ptr

appendbit:

   sub    $sp, $sp, 16        # save s-regs on stack
   sw     $s0, 0($sp)
   sw     $s1, 4($sp)
   sw     $s2, 8($sp)
   sw     $s3, 12($sp)
   move   $s3, $a1            # save buf ptr
   move   $s0, $a0            # copy argument                        
   lw     $s1, cumulus        # get cumulus
   lbu    $s2, bitbuf         # preload bitbuf
   li     $t1, 8
   bne    $s1, $t1, mroom     # if cumulus = 8 then
   sb     $s2, ($s3)          #   write bitbuf to buf
   add    $s3, $s3, 1         #   inc buf.
   move   $s2, $0             #   bitbuf := 0
   move   $s1, $0             #   cumulus := 0

mroom: # endif

   sll    $s2, $s2, 1         # bitbuf <<= 1
   andi   $s0, $s0, 1         # arg & 1
   or     $s2, $s2, $s0       # bitbuf |= arg
   sb     $s2, bitbuf         # store bitbuf
   addi   $s1, $s1, 1         # cumulus++
   sw     $s1, cumulus        # store cumulus
   lw     $s0, 0($sp)         # restore regs
   lw     $s1, 4($sp)
   lw     $s2, 8($sp)
   move   $v1, $s3
   lw     $s3, 12($sp)
   addi   $sp, $sp, 16        # restore stack
   li     $v0, 1
   jr     $ra                 # return(1)</lang>