Kingcom / armips

An assembler for various ARM and MIPS platforms. Builds available at http://buildbot.orphis.net/armips/
MIT License
363 stars 77 forks source link

Improve RSP immediate value range #202

Open anacierdem opened 3 years ago

anacierdem commented 3 years ago

Consider the following assembly;

.rsp
.create "text.bin", 0x40001000
    llv v1[0],lo(label1)(zero)
    llv v1[0],lo(label2)(zero)
    llv v1[0],lo(label3-_ref)($5)
    llv v1[0],lo(label_neg)(zero)
.close

.create "data.bin", 0x40000000
label1:
.word 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF
.word 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF
label2:
.word 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF

.org 0x40000800-32
label3:
.word 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF

.org 0x40000800
_ref:

.org 0x40000800+16
label4:
.word 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF

.org 0x40001000-32
label_neg:
.word 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF
.close

It fails with Immediate value 0x3F8 out of range. To make it work we can either change llv v1[0],lo(label_neg)(zero) to llv v1[0],lo(label_neg-0x40001000)(zero) or add a .headersize 0x40000000-0x1000 before the label_neg label. This is something that can be improved in practice.

The RSP dmem is limited to 4Kb and it should be possible to wrap around near the end of memory space when using zero relative addressing. The offset for the RSP load/store instructions is 7 bits so my proposal is that the assembler should just use the lowest 7 bits of the calculated value (after it is shifted depending on the instruction). It will properly become a negative offset when truncated to 7 bits.

e.g 0x3F8 & 0x7F = 0x78 which is (correctly) -8 in 7 bit two's complement.

It is not that easy for addressing with a random base register (see label3 in the above example) as the value of the register is dynamic - although we may even find a convention for that to enable it - but for the zero register the wrapping behavior is deterministic.

When the base register is zero, instead of doing the range check w.r.t a given threshold after shifting it, the assembler can just look at the distance from immediate_offset & 0x1FFF to both 0x0 and 0x1000 before shifting and truncating it. If the distance can be represented with a valid 7bit two's complement, it should not produce an error and continue with the shift and truncation.