⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

    .data

# the following are used by the subroutines
bitbuf:  .byte 0, 0
cumulus: .word 0
rbitbuf: .byte 0, 0
rfree:   .word 0

# 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


# read_bits
# $a0 acc.
# $a1 how many (max 32)
# $a2 input buffer
# > $v1 (new acc)
# > $t0 num of read bits or less (failure)
# > $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


# get last (maybe incomplete) accumulated byte
# $a0  accumulator
# >$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


# read a single bit
# $a0 accumulator
# $a1 input buffer
# > $v1 new accumulator
# > $t0 bit read (1 or not 1; in this impl, reading
#       can't fail unless input buffer is an invalid ptr
# > $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)

    

# bits_write; write upto 32 bits
# $a0 holds the bits (right aligned)
# $a1 how many bits are significative
# $a2 dest buf
# > $v1 updated buf ptr
# > $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


# flush bits
# $a1  output buf
# >$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


# add a single bit.
# $a0 holds the bit (as LSB i.e. "rightmost bit")
# $a1 output buf
# > $v0 number of written bits (always 1)
# > $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)