MIPS - Memory-mapped I/O question

Posted on 2006-05-15
Last Modified: 2011-09-20
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"
Question by:cyrus_bu
    LVL 16

    Expert Comment

    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.


    Author Comment

    i need people who can help me to set up this program!! Thanks.
    LVL 3

    Accepted Solution

    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


    Author Comment

    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.

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Better Security Awareness With Threat Intelligence

    See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

    Digital marketing agencies have encountered both the opportunities and difficulties that emerge from working with a wide-ranging organizations.
    This paper addresses the security of Sennheiser DECT Contact Center and Office (CC&O) headsets. It describes the DECT security chain comprised of “Pairing”, “Per Call Authentication” and “Encryption”, which are all part of the standard DECT protocol.
    Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
    Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

    779 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    10 Experts available now in Live!

    Get 1:1 Help Now