Use of keypad in Digital Lab Sim of Mars simulator - mars-simulator

I do not achieve to control keypad of the Digital Lab Sim tool of Mars 4.2.
According to the directions in the help "Byte value at address 0xFFFF0014 : receive row and column of the key pressed, 0 if not key pressed ". Nevertheless, if you read that memory position it does not work. Next simple sequence should read the keypad, but it does not work
ini:
lui $1,0xffff
lw $2,0x0014($1)
j ini
It always returns a 0 in spite of pressing any key of the tools.
I have no problem with the seven segment digit of this tool at all. It is quite easy to use through the address 0xFFFF0012. Nevertheless, no way with the keypad of this tool
Does anybody know how to read the keypad of the Digital Lab Sim of Mars 4.2?
Thank you very much

I answer myself.
Before reading a key, you have to select the row. The next sequence check the three rows (and it works):
sub $0,$0,$0
lui $2,0xffff # Base address IO
main:
addi $3,$0,0x01 # bit 0 =1 for row 1
sb $3,0x0012($2) # Selection row 1 (write on port 0xFFFF 0012)
lb $4,0x0014($2) # $4= code of pressed key of row 1 ($4=0 if not pressed)
bne $4,$0,row1 # if some key of row 1 was pressed -> go row1
# test of row 2
addi $3,$0,0x02 # bit 1 =1 for row 2
sb $3,0x0012($2)
lb $4,0x0014($2)
bne $4,$0,row2
# test of row 3
addi $3,$0,0x04 # bit 2 =1 for row 3
sb $3,0x0012($2)
lb $4,0x0014($2)
bne $4,$0,row3
# test of row 4
addi $3,$0,0x08 # bit 3 =1 for row 4
sb $3,0x0012($2)
lb $4,0x0014($2)
bne $4,$0,row4
j main
row1: # $4 has the code of the pressed key of this row
row2: # $4 has the code of the pressed key of this row
row3: # $4 has the code of the pressed key of this row
row4: # $4 has the code of the pressed key of this row

Related

How can you reverse a list in LMC language?

I have a list in LMC and I would like to try to reverse it like so :
tab dat 111
dat 222
dat 333
dat 444
dat 555
tab dat 555
dat 444
dat 333
dat 222
dat 111
-I tried to find the right element first by using the table size
-Then I substracted 200 from that instruction so that the instructions it turns from 520 -> 320.
-Essentially I changed the instruction from LOAD what is currently in the accumulator to the 20th square in the RAM to STORE what is currently in the accumulator to the 20th sqaure in the RAM
-Then I loaded the content tab at index 0 into the accumulator (111) then saved it in the last index
-I dont know what I have to do afterwards
-I feel like my approche to the problem is somehow wrong
right_el lda size
sub one
sta size
lda load
add size
sub 2hund
sta save
load lda tab
bra save
inc lda load
add one
sto load
bra load
save dat
bra right_el
left_el dat
tab dat 111
dat 222
dat 333
dat 444
dat 555
one dat 1
size dat 5
temp dat
2hund dat 200
I tried to run the program step by step. I managed to turn the table into:
tab dat 111
dat 222
dat 333
dat 444
dat 111
but I dont know what to do afterwards
This is a good start. A few issues:
At save you will write the moved value, but thereby lose the value that was sitting there.
temp is not used, but you would need it for saving the original value before it is overwritten, so that you can then read it again from temp and write that back to the first half of the list.
When branching back to the top, you need size to be reduced by 2, not by 1, because the load address has increased by one, and the distance to the target reduced with 2, not 1. You could solve this by changing the start of your program to:
lda size
add one # to compensate for the minus 2
sta size
right_el lda size
sub two
sta size
... and define two as 2.
You need a stop condition. When the reduced size is zero or less, the program should stop.
The code at inc is never executed. It should be.
You need two more self-modifying instructions. You currently have them for:
Reading from the left side of the list
Writing to the right side of the list
But you also need two for:
Reading from the right side of the list
Writing to the left side of the list
Some other remarks:
Your code mixes two variants of mnemonics: sto and sta. I would stick with one flavour.
Instead of bra save, you could just move that targeted code block right there, so no branching is needed.
I would use twohund as label instead of 2hund. It is common practice to not start identifiers with digits, and some simulators might even have a problem with it.
I would use loop as label instead of right_el as surely the loop will have to cover the complete swap -- from left to right and vice versa.
The following three instructions:
sta size
lda load
add size
Can be written with just two:
sta size
add load
Here is the resulting code -- I suffixed a few of your labels with "left" and "right" so I could add my own and make the distinction:
start LDA size
ADD one # to compensate for the minus 2
STA size
loop LDA size
SUB two
BRP continue # check the loop-stop condition
quit HLT
continue BRZ quit
STA size
ADD loadleft # add size in one go
STA loadright # manage the other dynamic opcode
SUB twohund
STA saveright
SUB size
STA saveleft # and another dynamic code.
loadright DAT
STA temp # first save the value that is targeted
loadleft LDA tab
saveright DAT
LDA temp # copy in the other direction
saveleft DAT
inc LDA loadleft
ADD one
STA loadleft # use consistent mnemnonic
BRA loop
tab DAT 111
DAT 222
DAT 333
DAT 444
DAT 555
one DAT 1
two DAT 2
size DAT 5
temp DAT
twohund DAT 200
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc#v0.816/lmc.js"></script>
You can run the code right here.

Programming arrays in LMC

I am working on this challenge:
The program needs to accept a sequence of integers. It ends with number 999. The integers (except 999) are placed in a list.
The integers must be less than or equal to 99. Any inputs greater than 99 are not placed in the list.
If the input would have more than ten numbers, only the first ten are stored.
999 is not part of the output.
I don't know how to limit the list length to ten (10) numbers. Also I don't know how to output the list in reverse order.
This is my code:
start INP
STA temp
SUB big
BRZ doout
LDA temp
SUB hundred
BRP start
sub one
STA N
xx STA ARR
LDA xx
add one
sta xx
BRA start
doout HLT
temp dat 0
big dat 999
hundred dat 100
ARR dat
one dat 1
N dat 10
The xx in your program show that you haven't taken the hint from How can I store an unknown number of inputs in different addresses in LMC (little-man-computer)?
It explains how you can have self-modifying code to walk through an array -- either to store values or to load them.
In your attempt there is no section that deals with outputting.
For the start section of the program I would actually suggest to subtract first the 100 and then 899 (which amounts to 999). That way you can keep the (reducing) input in the accumulator without having to restore it.
Also, due to an ambiguity in the specification of LMC, it is not entirely "safe" to do a BRZ right after a SUB (this is because the content of the accumulator is undefined/unspecified when there is underflow, so in theory it could be 0). You should always first do a BRP before doing a BRZ in the branched code. However, as input cannot be greater than 999, a BRP is enough to detect equality.
For the self modifying part, you can set an end-marker in your array data section, and define the LDA and STA instructions that would read/store a value at the end of the array. Whenever your code has that exact instruction, you know you have reached the end.
Here is how it can work:
LDA store # Initialise dynamic store instruction
STA dyna1
loop INP
dyna1 STA array
SUB toobig
BRP skip
LDA dyna1
ADD one
STA dyna1
SUB staend
BRP print
BRA loop
skip SUB trailer
BRP print # Safer to do BRP than BRZ
BRA loop # Input was less than 999
print LDA dyna1 # Convert dynamic store instruction
SUB store # ... to index
ADD load # ... to load instruction
STA dyna2
loop2 LDA dyna2
SUB one
STA dyna2
SUB load
BRP dyna2
end HLT # all done
dyna2 LDA array
OUT
BRA loop2
store STA array
load LDA array
staend STA after
one DAT 1
toobig DAT 100
trailer DAT 899
array DAT
DAT
DAT
DAT
DAT
DAT
DAT
DAT
DAT
DAT
after DAT
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc#v0.816/lmc.js"></script>
As you can see (while running the script here), the instructions at dyna1 and dyna2 are modified during the execution of the loop they are in.

Getting an error when trying to fill an array with Strings and ints in MIPS?

So I need to fill an array in MIPS with 10 "records", which consist of an employee's name, age, and salary. The employee's name is a max of 40 characters and both the age and salary are supposed to be integers. However, when testing this loop I wrote, I always get an "invalid integer input (syscall 5)" for line 18 after I go through the first 5 employees and I type "Emp6" and press enter and I can't seem to figure out why. Any help would be greatly appreciated!
Test Input:
Emp1
1
1
Emp2
2
2
Emp3
3
3
Emp4
4
4
Emp5
5
5
Emp6
Error Code:
Error in line 18: Runtime exception at 0x00400020: invalid integer input (syscall 5)
Go: execution terminated with errors.
Your main problem seems to be that the read_string system call expects the buffer size in $a1, but you use that for your loop counter. Thus, you eventually run out of space, and there will be unprocessed text left in the input buffer which will then be read by the subsequent read_int and that blows up.
Further problem is that you keep incrementing $a0 but fail to account for that in your addressing. Also sw $v0, 0($a0) doesn't make much sense, the string has been read into memory already, $v0 has nothing interesting in it.

MIPS Constructing Loops

Okay, so this might be a really silly question but I don't quite have the hang of Assembly yet. I have to write a program that calculates the summation of a series of numbers. It should behave like so:
Enter the first integer in the series: 5
Enter the number of integers in the series: 3
Enter the offset between integers in the series: 4
The series is: 5, 9, 13.
The summation of the series is 27.
Would you like to calculate another summation (Y/N)? y
Enter the first integer in the series: 4
Enter the number of integers in the series: 5
Enter the offset between integers in the series: 27
The series is 4, 31, 58, 85, 112.
The summation of the series is 290.
Would you like to calculate another summation (Y/N)? Y
Enter the first integer in the series: -16
Enter the number of integers in the series: -22
There must be a positive number of integers in the series.
Would you like to calculate another summation (Y/N)? n
This is what I have so far:
li $v0, 4 #put 4 in as main parameter in v0
la $a0, Q1 #syscall will print string query 1
syscall
Store first integer in series in s0
li $v0, 5 #put 5 in as main parameter in v0
syscall #syscall will read integer from Q1
move $s0, $v0 #move integer in v0 to s0
Request number of integers in series
li $v0, 4 #put 4 in as main parameter in v0
la $a0, Q2 #syscall will print string query 2
syscall
Store number of integers in series in s1
li $v0, 5 #put 5 in as main parameter in v0
syscall #syscall will read integer from Q2
move $s1, $v0 #move integer in v0 to s1
Request offset of integers
li $v0, 4 #put 4 in as main parameter in v0
la $a0, Q3 #syscall will print string query 3
syscall
Store offset of integers in s2
li $v0, 5 #put 5 in as main parameter in v0
syscall #syscall will read integer from Q3
move $s2, $v0 #move integer in v0 to s1
Set counter
li $s3, 1 #Set counter to zero
li $t0, 1 #iterator count is in t0
I'm just curious as to where to start my loop? And how exactly would I go about printing the entire series? Any advice would be greatly appreciated.
I'm not sure what you do in "set counter" part, as the s1 already contains number of series members.
And s0 contains current element.
All you need (additional information) is to clear current_sum, let's say as s3:
add $s3, $zero, $zero ; or "move $s3, $zero" if you prefer the pseudo-ops
So for your first example s0-s3 will be set to [5, 3, 4, 0] before first loop iteration. This is everything ("world state") you need, any other value you will set up is probably some temporary for particular sub-task like displaying some value and similar, but as long as the core computation goes, these four values represent all you need, and everything else can be based upon them.
If s1 is already less than 1 (<=0 test), report wrong input.
Then the loop algorithm:
add current element (s0) to current sum (s3) ; summing up all numbers
display current element (s0)
; handle the correct count of series' members
decrement counter s1
if s1 is zero, then goto exit_loop
; preparing for next loop iteration
add offset (s2) to current element (s0)
display ", "
jump to first step
exit_loop: logic will involve printing end of line, summation text description, current sum value (s3), another new line(s) and asking for repeat y/n.
For example that 4 core values will evolve during iterations like this:
[5, 3, 4, 0] => displays "5, " + all the updating of values
[9, 2, 4, 5] => displays "9, " + all the updating of values
[13, 1, 4, 14] => modifies s3 to 27, displays "13", --s1, jumps to exit_loop
At exit_loop the core values are [13, 0, 4, 27], code will display 27 as series sum.

MIPS findmin of array function

Hello I am getting exception 7 [bad data address] for the following findMin number in an array function. The length of the array is already in $a1, and the address of the start of the array is in $a0. I want to have the min in $v0 after all is said and done. My function works for arrays with 2 elements but shoots out exception 7 errors when using bigger sized arrays. I am offsetting the array by adding to the address instead of using something like the 4 in 4($a0) offsetting.
They key here is add $a0, $a0, $t1. Consider what that will do in the case of an array with N elements: on the second iteration you'll add 1*4, on the third iteration 2*4, and so on. So on the third iteration you'd be trying to read from array + 1*4 + 2*4 == array + 3*4 instead of array + 2*4. And on the N:th iteration you'd be trying to read from array + 1*4 + 2*4 + ... + (N-1)*4.
The sll + add before the lw should be removed. Updating the address can be done after the lw with an addiu $a0, $a0, 4.

Resources