MIPS: Can I get unsigned int value from user via syscall? - mips

The title pretty much sums this up. I am writing a program in 32-bit MIPS Assembly Language (using the MARS emulator) for a school project and I'm having zero luck reading in int values > 2,147,483,647.
I spent a decent amount of time hunting around the internet and in my book to no avail. This is not central to the assignment (which, if you happen to know it is impossible, you probably already realized) but curiosity is killing this cat. Now that I've hit this brick wall, I must know for sure.
Notes:
I'm specifically looking for a way to grab an unsigned int as opposed to taking a float or a double.
The standard code for grabbing an int with syscall:
li $v0, 5
syscall
move $t0, $v0
The error that occurs when 2 500 000 000 is passed at prompt for integer:
Error in C:\DEV\....... line 57: Runtime exception at
0x004000034: invalid integer input (syscall 5)
Help me Obi-Wan, you're my only hope!

You'll need to use a different system call -- MARS is throwing the exception, not anything "inside" the MIPS CPU. Try, for instance, syscalls 8 or 12 (read string and read character). Note that, as a result, you'll have to implement a lot more of the parsing yourself to make these work.
Alternatively, you might try reading a double (syscall 7) and converting it to an integer...
There's a full list of MARS syscalls online at:
http://courses.missouristate.edu/KenVollmar/MARS/Help/SyscallHelp.html

Related

What does "extend immediate to 32 bits" mean in MIPS?

I'm reading about the Instruction Decode (ID) phase in the MIPS datapath, and I've got the following quote: "Once operands are known, read the actual data (from registers) or extend the data to 32 bits (immediates)."
Can someone explain what the "extend the data to 32 bits (immediates)" part means? I know that registers all contain 32 bits, and I know what an immediate is. I just don't understand why you need to extend the immediate from 26 to 32 bits.
Thanks!
26-bit immediates are only in jump instructions, and aren't sign- or zero-extended to 32 bit, because they're not displacements to be added/subtracted.
I-type instructions with 16-bit immediates are different.
addi / addiu immediates are sign-extended (by duplicating the top/sign bit of the immediate to all higher bits).
https://en.wikipedia.org/wiki/Two%27s_complement#Sign_extension
This allows 2's complement numbers from -2^15 .. +2^15-1 to be encoded.
(0xFFFF8000 to 0x00007FFF)
ori/andi/xori boolean immediates are zero-extended (by setting all higher bits to zero)
This allows unsigned / 2's complement numbers from 0 .. 2^16-1 to be encoded.
(0x00000000 to 0x0000FFFF)
For other instructions see this instruction-set reference which breaks down each instruction showing 016 || [I15..0] for zero-extension or [I15]16 || [I15..0] for sign-extension.
This makes it possible to use 16-bit immediates as inputs to a 32-bit binary operation that only makes sense with 2 equal-width inputs. (In a simple classic MIPS pipeline, the decode stage fetches operands from registers and/or immediates. Register inputs are always going to be 32-bit, so the ALU is wired up for 32-bit inputs. Extending immediates to 32-bit means the rest of the CPU doesn't have to care whether the data came from an immediate or a register.)
Also sign-extended:
offsets in the reg+imm16 addressing mode used by lw/sw and other load/store instructions
relative branches (PC += imm16<<2)
maybe others, check the manual for instructions I didn't mention to see if they sign- or zero- extend.
You might be wondering "why does addiu sign-extend its immediate even though it's unsigned?"
Remember that there's no subiu, only addiu with a negative immediate. Being able to add or subtract numbers in the range -2^15 .. +2^15-1 is more useful than only being able to add 0 .. 2^16-1.
And usually you don't want to raise an exception on signed overflow, so normally compilers use addu / addiu even on signed integers. addu is badly named: it's not "for unsigned integers", it's just a wrapping-allowed / never-faulting version of add/addi. It sort of makes sense if you think of C, where signed overflow is undefined behaviour (and thus could use add and raise an exception in that case if the compiler wanted to implement it that way), but unsigned integers have well-defined overflow behaviour: base 2 wraparound.
On a 32-bit CPU, most of the operations you do (like adding, subtracting, dereferencing a pointer) are done with 32-bit numbers. When you have a number with fewer bits, you need to somehow decide what those other bits are going to be when you want to use that number in one of those operations. The act of deciding what those new high bits are is called "extending".
Assuming you are just doing a standard zero extension or sign extension, extending is very cheap. However, it does require some circuitry, so it makes sense that a description of the MIPS datapath would mention it.

effects of different scenarios on a single cycle datapath (beq command)

I am stuck and unsure regarding the following situation.
I have the following datacycle:
and I know that in 0x3000 I have the following command: beq $t1,$t2,home - where home is 0x30AC, $t1=$t2=0x2000.
For some reason, I cannot translate it into hexa using online converters. The command I tried is: beq 0x2000, 0x2000, 0x30AC. Since the syntax of a beq command, as far as I know is: BEQ rs, rt, offset [I-type], then I don't understand why it doesn't work.
Anyways, my main problem are with the following cases:
If the control line of ALUSrc is stuck on 1, what will the command do?
If MemWrite is stuck on 1, what will the command do?
If ALUOp is stuck on the value 10 (binary), what will the command do?
What I think:
If alusrc equals one, then the lower 16 bits will be taken (with sign extenstion) from the command and added to $rs (0x2000).
If Memwrite equals one, then the data memory will be written unexpectedly.
I really don't know what will happen if ALUop will be stuck on 10. would really appreciate explanations regarding this situation.
I tried to elaborate as much as I can to make it understandable and also provide my attempts and insights (if correct, hope that some are lol).

MIPS: legal to have two consecutive "load word" instructions into the same register?

Background: We're seeing a very intermittent crash in a function foo(int *p). The crash occurs while dereferencing p, whose value in these cases turns out to be 0xffffffff. An analysis of the core dump shows that foo() is called from the following assembly snippet:
bne ... somewhere else
lw $a0,44(sp)
lw $a0,40(sp)
jal foo()
lui s1, 0x1000
Inspecting memory in the core dump shows that 44(sp) is 0xffffffff, whereas 40(sp) is the correct value we intend to dereference. However, the value of a0 at the time of the crash, inside foo(), is 0xffffffff. (It's important to note that foo() in this case is just accessing a member; so it's literally the first instruction in foo() which is already attempting to access via a0, and crashing. Also, ra is pointing to the instruction following the above snippet, and s1 currently contains 0x10000000, so we're quite confident that foo() was, indeed, called from the above snippet.)
Our only theory at the moment is that the two consecutive lws into a0 are a hazard -- either a documented one, in which case this looks like a compiler bug; or an undocumented one.
So: is the above assembly legal? If it is, any other ideas about what could be going on here?
Thanks!
UPDATE: Well, turns out this was all a wild goose chase: a repeat analysis of the coredump by a colleague turned up a path in the code which I had missed, where there was a jump directly to the jal foo() instruction, immediately after having set a0 to 44(sp). In other words, there is a path in the code which is consistent with the result we're seeing that does not involve hazards, or "skipped instructions" or anything... I thought I checked this, but I guess I either didn't, or missed it... :(
Anyway, I've accepted markgz's answer, since it answers my original question about the legality of these instructions (apparently they are).
A quick search of the MIPS documentation for the MIPS32R2 ISA doesn't show any restrictions on LW after LW instructions.
There might be a bug in the MIPS implementation in your CPU. Things to look at include:
What address is 44(sp), 40(sp) - are they on a page boundary or a 256MByte boundary, or other interesting address?
Do either of the loads trigger a page fault?
Does patching the binary to insert a NOP, SSNOP, or a SYNC instruction between the loads make the problem go away?

get wrong epc on MIPS

I know MIPS would get wrong epc register value when it happens at branch delay, and epc = fault_address - 4.
But now, I often get the wrong EPC value which is even NOT in .text segment such as 0xb6000000, what's wrong with the case??
Thanks for your advance..
The CPU does not know anything about the boundaries of the .text region in your program. It simply implements a 2^32 byte address space.
It is possible for an incorrectly programmed jump to go to any address within the 2^32 byte address space. The jump instruction itself will not cause any sort of exception - in fact the MIPS32® Architecture for Programmers Volume II: The MIPS32® Instruction Set explicitly states that jump (J, JR, JALR) instructions do not trigger any exceptions.
When the processor starts executing from the destination of an incorrectly programmed jump, in presumably uninitialized memory, what happens next depends on the contents of that memory. If uninitialized memory is filled with "random" data, that data will be interpreted as instructions which the processor will execute until an illegal instruction is found, or until an instruction triggers some other exception.

Why do MIPS operations on unsigned numbers give signed results?

When I try working on unsigned integers in MIPS, the result of every operation I do remains signed (that is, the integers are all in 2's complement), even though every operation I perform is an unsigned one: addu, multu and so fourth...
When I print numbers in the range [2^31, 2^32 - 1] I get their 'overflowed' negative value as if they were signed (I guess they are).
Though, when I try something like this:
li $v0, 1
li $a0, 2147483648 # or any bigger number
syscall
the printed number is always 2147483647 (2^31 - 1)
I'm confused... What am I missing?
PS : I haven't included my code as it isn't very readable (such is assembly code) and putting aside this problem,
seems to be working fine. If anyone feels it is necessary I shall include it right away!
From Wikipedia:
The MIPS32 Instruction Set states that the word unsigned as part of Add and Subtract instructions, is a misnomer. The difference between signed and unsigned versions of commands is not a sign extension (or lack thereof) of the operands, but controls whether a trap is executed on overflow (e.g. Add) or an overflow is ignored (Add unsigned). An immediate operand CONST to these instructions is always sign-extended.
From the MIPS Instruction Reference:
ALL arithmetic immediate values are sign-extended [...] The only difference between signed and unsigned instructions is that signed instructions can generate an overflow exception and unsigned instructions can not.
It looks to me like the real problem is the syscall that you are using to print numbers. It appears to and to always interpret what you pass as signed, and to possibly to bound as as well.