1

The system has 4 push buttons, named A to D. The push buttons are memory mapped to address 0xffffe440. The status of the buttons are given at bit indices 7 through 4, where button A is given at index 7 and button D at index 4. A bit value 1 means that the button is currently pushed. The system has 8 LED lights, memory mapped at address 0x17880010. The LED lights are located at bit indices 12 through 5.

What to do:

Create a program that loops forever. In the loop, read the status of the push buttons A and D, and turn on the LED lights to show the binary representation of the decimal value 13 if A is pressed. If A is released, value 13 should continue to be displayed, until button D is pressed. If D is pressed, all LED lights should be turned off. If button A is pressed again, value 13 should be displayed again, etc. If both A and D are pressed at the same time, the LEDs should be turned off. When the program starts, and no buttons are pressed, all LEDs should be turned off. Note that you can get points for a partially correct solution.

When writing to the memory mapped I/O port, you do not have to take into consideration if some of the other unused bits of the port are changed.

What I have tried:

This is what I have tried, the solution in the answers is very short, but mine is long and probably not a beautiful but it looks correct to me I wanna hear what you guys think. (The reason I don't want to just rewrite it is because I wanna know whether this is correct or not, I am doing old exams)

funct : 
      lui $t0, 0xffff
      ori $t0, $t0, 0xe440
      lui $t1, 0x1788
      ori $t1, $t1, 0x0010
loop : 
     lw   $t2, 0($t0)
     andi $t3, $t2, 0x90
     addi $t4, $0, 0x90
     bne  $t3, $t4, check_A
     andi $t9, $t9, 0x0
     sw   $t9, 0($t1)
     j    loop

check_A : 
     andi $t3, $t2, 0x80
     addi $t4, $0, 0x80
     bne  $t3, $t4, check_D
     andi $t9, $t9, 0x1a0
     sw   $t9, 0($t1)
     j    loop
check_D:
     addi $t4, $0, 0x10
     andi $t4, $0, 0x10
     bne  $s3, $t4, exit
     andi $t9, $t9, 0x0
     sw   $t9, 0 ($t1)
     j    loop
exit:
     j    loop
 

1 Answer 1

2

There's one line that doesn't do what you're thinking:

andi $t9, $t9, 0x1a0

This looks wrong as it (a) relies on the original value of $t9, and (b) masks it with a constant, having virtually no effect.  The incoming value of $t9 is most likely 0 so still 0 after this instruction.

Probably you wanted:

addi $t9, $0, 0x1a0

Though I have to admit I don't understand whence that constant value.  I would have thought to put 13 there (or in hex, 0xD).


The following:

check_D:
     addi $t4, $0, 0x10
     andi $t4, $0, 0x10

is also surely not doing what you want.  That is setting $t4 to 0x10, then masking with 0x10, which leaves $t4 with 0x10.  Need to fix the register usages to be more like the Check_A section.


Algorithmically, I'm not sure of the value or reason to check for both A & D buttons at the same time, since the D button being pressed means to turn off the lights, whether or not the A button is pressed.  So, as I read the problem statement, it seems proper to check for D (regardless of A) and then only if D is not pressed to check for A.  (As you already have, nothing should be done if no button is pressed, thus leaving the lights as they were by the last press (as 13 if last was A, or off if last was D), however, you should turn the lights off once at the start of the program.)


As far as making your program shorter, let's observe that lw allows for a 16-bit signed immediate.  So, you can access 0xffffe440 without a base register, as follows:

lw $t2, 0xe440($0)   # Note using $0/$zero as base register

This will access location 0xffffe440, and that removes the need to setup $t0 as a base register for the buttons, so saves 2 instructions (lui/ori).

Next, the memory location 0x17880010 does require a base register, but only for the 0x1788 part, as the 0x0010 part can be put into the offset of the sw instruction, so saves 1 instruction (ori).

The $0 register always holds 0, so this:

 andi $t9, $t9, 0x0
 sw   $t9, 0($t1)

is more simply done as follow:

 sw   $0, 0($t1)

(btw, that andi is an unusual but ok way to clear $t9, most would use addi $t9, $0, 0, or add $t9, $0, $0)

The branch to label exit should simply branch directly to loop, allowing elimination of that label and another instruction (j).

You can also dynamically shorten the loops by putting constants 0x90, etc.. in their own dedicated register instead of reloading those inside the loop.  That won't lower the static instruction count, though will help with dynamic instruction count.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for this! The t4 was just an accidental mistake since I first wrote on paper instead I have: t3 and t4. You are totally correct, your understanding of the question basically summerizes the solution they have. Another thing that confused me was 13, aren't they asking us to turn the leds so they can represent the binary value of 13?
Ok, your right 1a0 b/c 13 has to be shifted by 5 bits. Sorry I missed the necessary shift.
@Need_MathHelp Also, the following are equivalent: (x & 0x80) != 0 and (x & 0x80) == 0x80, but its shorter sequence to check != 0 rather than == 0x80. (Same obviously holds that (x & 0x80) == 0 and (x & 0x80) != 0x80 are equivalent, and again compare with zero is simpler and so, preferred).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.