MIPS - Memory-mapped I/O question

Turn off branch and load delays for this program.  It will make it MUCH simpler…  Be sure to turn on memory-mapped I/O.

You may start with the "Test of memory mapped IO" example program.  Make sure you fully understand what it is doing before you start programming.  Remove all parts of the example program that are not being used by your program.

You cannot use syscall for input, because the program would then block on the input.  Instead, use an interrupt-driven input routine catch input.

Write a program that starts with two arrays of characters (.asciiz strings), of length 25, labeled 'source' and 'display'.  Initially, the two arrays are identical and contain 24- character strings.  You may start your program by copying the source array into the display array.  Use a subroutine to do this.  Then run repeatedly displaying the display array character-by-character with a terminating newline.  To make debugging easier, code a delay loop (perhaps 2 nested loops with 300 to 500 passes through each one, to make the total elapsed time approximately 1 second between each display of the display array.  Also, use a delay loop to slow down the printing of the elements in the array so you can watch what happens as keyboard interrupts occur.

Do the following tasks depending on the user's input:

'S' or 's': sort the display array using the ripple sort routine.

'T' or 't': toggle the case of every character (for example, 'T' becomes 't', 't' becomes 'T' and all non-alphabetic characters stay unchanged) .

'A' or 'a': replace the display array elements with the source elements once again.

'R' or 'r': reverse the elements in the display array.

'Q' or 'q': terminate program execution gracefully.

Note: an interrupt could happen in the middle of displaying the array, so the characters being displayed could change mid-line.

This program is obviously designed to build on previous assignments, so you should reuse code wherever possible.  The primary new feature is the interrupt-driven input.  Instead of reading until you have the entire string (up to NL or CR to stop), read and process each character as it arrives.

Here is the example code:

prompt: .asciiz "SPIM IO Test.\nOnly runs with -mapped_io flag.\nPlease type 6 input lines:\n"
nl:      .asciiz "\n"

      .globl main
      li $v0 4
      la $a0 prompt

# Register usage:
#            s0            loop counter
#            t0            address of recv_ctrl
#            t1            address of recv_buffer
#            t2            address of trans_ctrl
#            t3            address of trans_buffer
#            t4, t5            temporaries
#            t6            char read from input
#            t7            1 => char in t6

      li      $s0, 3            # loop counter

      li       $t0, 0xffff0000      # recv ctrl
      li      $t1, 0xffff0004      # recv buf
      li       $t2, 0xffff0008      # trans ctrl
      li       $t3, 0xffff000c      # trans buf

# First, read and echo 3 lines of input by polling the IO registers, not through
# interrupts:

      mtc0      $0, $12            # Clear IE bit in Status reg to disable interrupts

      lw      $t4, 0($t0)      # Wait for receiver ready
      and       $t4, $t4, 1
      beq      $t4, 0, l1

      lw      $t6, 0($t1)      # Read character

      lw      $t4, 0($t2)      # Wait for transmitter ready
      and      $t4, $t4, 1
      beq      $t4, 0, l2

      sw      $t6, 0($t3)      # Write character

      beq      $t6, 0xa, decr      # New line (nl)
      bne      $t6, 0xd, l1      # Carriage return (cr)

      add      $s0, $s0, -1      # Decrement line counter
      bne      $s0, 0, l1      # If not zero, get another line

# Second, read and echo 3 lines of input by through interrupts:

      mfc0      $t4, $13
      and      $t4, 0xffff00ff      # Clear IP bits in Cause register
      mtc0      $t4, $13

      li      $s0, 3            # loop counter

      li      $t4, 0x2      # Enable device interrupts
      sw      $t4, 0($t0)
      sw      $t4, 0($t2)

      mfc0      $t4, $12      # Enable interrupts and mask in Status reg
      ori      $t4, $t4, 0xff01
      mtc0      $t4, $12

l3:      b      l3            # Loop waiting for interrupts

# Trap handler. Replaces the standard SPIM handler.

      .ktext 0x80000180
      mfc0      $t4, $13      # Get ExcCode field from Cause reg
      srl      $t5, $t4, 2
      and      $t5, $t5, 0x1f      # ExcCode field
      bne      $t5, 0, exception

# An interrupt:
      and      $t5, $t4, 0x800      # Check for IP3 (HW 1)
      beq      $t5, 0, check_trans

# Receiver interrupt:
      lw      $t5, 0($t0)      # Check receiver ready
      and      $t5, $t5, 1
      beq      $t5, 0, no_recv_ready      # Error if receiver is not ready

      lw      $t6, 0($t1)      # Read character
      li      $t7, 1

      beq      $t6, 0xa, decr2      # New line (nl)
      bne      $t6, 0xd, next      # Carriage return (cr)

      add      $s0, $s0, -1      # Decrement line counter

      mfc0      $t4, $13      # Get Cause register
      and      $t4, 0xfffff7ff      # Clear IP3 bit
      mtc0      $t4, $13

      beq      $t7, 0, ret_handler      # No char to write yet

      and      $t5, $t4, 0x400      # Check for IP2 (HW 0)
      beq      $t5, 0, check_loop

# Transmitter interrupt:
      lw      $t5, 0($t2)      # Check transmitter ready
      and      $t5, $t5, 1
      beq      $t5, 0, no_trans_ready

      sw      $t6, 0($t3)      # Write character
      li      $t7, 0

      mfc0      $t4, $13      # Get Cause register
      and      $t4, 0xfffffbff      # Clear IP2 bit
      mtc0      $t4, $13

      bne      $s0, 0, ret_handler      # If line counter not zero, get another line

# Done echoing, so terminate program.
      li      $v0, 10
      syscall                  # syscall 10 (exit)

# Return from handler.
      mfc0      $t4, $12      # Enable interrupts and mask in Status reg
      ori      $t4, $t4, 0xff01
      mtc0      $t4, $12

      eret                  # return to interrupted instruction

      li      $v0, 4            # Non-interrupt exception
      la      $a0, other_str      # Print message and ignore
      b      ret_handler

      li      $v0, 4            # Receiver was not ready after interrupt
      la      $a0, no_recv_str      # Print message and ignore
      b      ret_handler

      li      $v0, 4            # Interrupt was not from recv or trans
      la      $a0, bad_int_str      # Print message and ignore
      b      ret_handler

      li      $v0, 4            # Transmitter was not ready after interrupt
      la      $a0, no_trans_str      # Print message and ignore
      b      ret_handler

      .asciiz "Non-interrupt exception\n"
      .asciiz "Receiver not ready\n"
      .asciiz "Transmitter not ready\n"
      .asciiz "Unknown interrupt\n"
Who is Participating?
Hi cyrus_bu,

Here is my hint.

Try to understand the following Porgramming definition language and then
write codes based on the description.

Good Luck!

The features of this program are:

1) In the Main Task, use the I/O polling scheme and the memory map I/O to
   transmit characters repeatly.

2) Use an interrupt service routine to receive any input character and also
   echo back this character. This routine will save the input in got_input_data
   and also set the flag of "got_input_flag" to TRUE in order to wake-up the
   Main Task to process the command (for example, 'T' or 't').

Main Task

initialization includes

   copy source array element to display array
   set got_input_flag to FALSE
   set the xmit pointer to the 1st element of display array
   enable the receiver and disable the transmitter
   enable the interrupt and turn on the mask
do forever loop
   delay 1 sec
   if got_input_flag is TRUE then
      set got_input_flag to FALSE
      select on the got_input_data
         case 'S' or 's'
            Sort the display array
         case 'T' or 't'
            Toggle the case of every characters in the display array
         case 'A' or 'a'
            Copy the source array to the display array
         case 'R' or 'r'
            Reverse the display array elements
         case 'Q' or 'q'
            Call syscall to terminate this program
   xmit the next char from display array
   if reaches the end of display array then
      reset xmit pointer back to the beginning of display array
Interrupt Service Routine at .ktext 0x80000180

Read the Cause Register

Fetch the exception code from it

if exception code <> 0 then
   enable interrupt and turn on mask (via the Status Register)
   return from interrupt

if the receive interrupt pending bit is set in the Cause Register then
   if the receiver control register shows RECV_READY then
      read receiver data register to got_input_data
      set got_input_flag to TRUE
      poke the transmitter control register for XMIT_READY
      write (echo) the got_input_data to the transmitter data register
      clear the receiver interrupt pending bit
enable interrupt and turn on mask (via the Status Register)
return from interrupt

Hi cyrus_bu,

Would you please highlight the code that you have done so we can tell what was provided for you. That would make it easier to help you because we can then assume that the rest is correct. If that is not possible, please indicate where you think the problem is and what difficulties you are having with it.

cyrus_buAuthor Commented:
i need people who can help me to set up this program!! Thanks.
cyrus_buAuthor Commented:
Hi PeterdLo:
    Thanks your comment.
    As the first one: 'S' or 's': sort the display array using the ripple sort routine.
    Could you write this piece of code that i can fully understand the program? I think i will follow your code to finish the
program!! Thanks.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.