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
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.