Live data from Hacker News

Solving the Mystery of ARM7TDMI Multiply Carry Flag

bmchtech.github.io

11–20 of 35 posts

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#11
post #8
post #5

> Seriously, they decided that the program counter should be a general purpose register. Why??? Don't really understand this reaction. Why not? Seems to make for a nice regular design that the PC is just another register.

Yeah, it was that way for all previous ARM processors too, for exactly that reason. Adding special cases would have increased the transistor count, for no great benefit. The only downside was that it exposed internal details of the pipelining IIRC. In the ARM2, a read of the PC would give the current instruction's location + 8, rather than its actual location, because by the time the instruction 'took place' the PC h…

Hey, I'm the author, sorry it came off that way, I was really just poking fun. I should've definitely phrased that better!

But no, I really think that making the program counter a GPR isn't a good design decision - there's pretty good reasons why no modern arches do things that way anymore. I admittedly was originally in the same boat when I first heard of ARMv4T - I thought putting the PC as a GPR was quite clean, but I soon realized it just wastes instruction space, makes branch prediction slightly more complex, decrease the number of available registers (increasing register pressure), all while providing marginal benefit to the programmer

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#12
post #6

And just to get this out of the way, the carry flag’s behavior after multiplication isn’t an important detail to emulate at all. Software doesn’t rely on it. On as fixed of a hardware as a game console, and with the accompanying anti-piracy/anti-cheating/emulation efforts of that industry, I'd expect it to be. From the history of emulating previous consoles, we know that any deterministic difference can and will be e…

While it’s a bit newer than the GBA, there is at least one Wii game with intentional anti-emulation measures: https://tcrf.net/Cars_2_(PlayStation_3,_Xbox_360,_Windows,_W...

[deleted]

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#13

Earlier quoted context omitted.

The big issue is that it doesn't really need to be a GPR. You never find yourself using the PC in instructions other than in, say, the occasional add instruction for switch case jumptables, or pushes / pops. So it ends up wasting instruction space, when you could've had an additional register, or encoded a zero register (which is what AARCH64 does nowadays).

But it is (or was originally) used in lots of places, not just jump tables, generally to do relative addressing, for example when you want to refer to data nearby, e.g. ADD r0, r15, #200 LDR r1, [r15, #-100] etc

Ah I miscommunicated, I still think PC can and should be used in places like the operand of an LDR / ADD. It's using it as the output of certain instructions (and allowing it to be used as such) that I take issue with. ARMv4T allowed you to set PC as the output of basically any instruction, allowing you to create cursed instructions like this lol:

eor pc, pc, pc

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#14
post #8

Earlier quoted context omitted.

Yeah, it was that way for all previous ARM processors too, for exactly that reason. Adding special cases would have increased the transistor count, for no great benefit. The only downside was that it exposed internal details of the pipelining IIRC. In the ARM2, a read of the PC would give the current instruction's location + 8, rather than its actual location, because by the time the instruction 'took place' the PC h…

Hey, I'm the author, sorry it came off that way, I was really just poking fun. I should've definitely phrased that better! But no, I really think that making the program counter a GPR isn't a good design decision - there's pretty good reasons why no modern arches do things that way anymore. I admittedly was originally in the same boat when I first heard of ARMv4T - I thought putting the PC as a GPR was quite clean, b…

Anyway, I took the time to rewrite that paragraph a bit to be more respectful. :P Hopefully that'll come off better. The website take a few minutes to update.

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#15
post #8

Earlier quoted context omitted.

Yeah, it was that way for all previous ARM processors too, for exactly that reason. Adding special cases would have increased the transistor count, for no great benefit. The only downside was that it exposed internal details of the pipelining IIRC. In the ARM2, a read of the PC would give the current instruction's location + 8, rather than its actual location, because by the time the instruction 'took place' the PC h…

Hey, I'm the author, sorry it came off that way, I was really just poking fun. I should've definitely phrased that better! But no, I really think that making the program counter a GPR isn't a good design decision - there's pretty good reasons why no modern arches do things that way anymore. I admittedly was originally in the same boat when I first heard of ARMv4T - I thought putting the PC as a GPR was quite clean, b…

I think I misread your tone, sorry.

It's a good article though, the explanation of how multiplies work is nicely written.

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#16

Earlier quoted context omitted.

But it is (or was originally) used in lots of places, not just jump tables, generally to do relative addressing, for example when you want to refer to data nearby, e.g. ADD r0, r15, #200 LDR r1, [r15, #-100] etc

Ah I miscommunicated, I still think PC can and should be used in places like the operand of an LDR / ADD. It's using it as the output of certain instructions (and allowing it to be used as such) that I take issue with. ARMv4T allowed you to set PC as the output of basically any instruction, allowing you to create cursed instructions like this lol: eor pc, pc, pc

Isn't writing to it except by a branch instruction undefined behaviour?

If you can use it as an operand, it has a register number, so you can use it as a result, unless you special-case one or the other, which ARM didn't do because it was supposed to be simple. They could have ignored it by omitting some write decode circuitry, but why?

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#17

And just to get this out of the way, the carry flag’s behavior after multiplication isn’t an important detail to emulate at all. Software doesn’t rely on it. On as fixed of a hardware as a game console, and with the accompanying anti-piracy/anti-cheating/emulation efforts of that industry, I'd expect it to be. From the history of emulating previous consoles, we know that any deterministic difference can and will be e…

>> the carry flag’s behavior after multiplication isn’t an important detail to emulate at all. Software doesn’t rely on it.

Famous last words:

https://www.hyrumslaw.com/

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#18

Earlier quoted context omitted.

Hey, I'm the author, sorry it came off that way, I was really just poking fun. I should've definitely phrased that better! But no, I really think that making the program counter a GPR isn't a good design decision - there's pretty good reasons why no modern arches do things that way anymore. I admittedly was originally in the same boat when I first heard of ARMv4T - I thought putting the PC as a GPR was quite clean, b…

I think I misread your tone, sorry. It's a good article though, the explanation of how multiplies work is nicely written.

No worries, I'm glad you brought it up so I could amend the article to be more respectful to those that I look up to :)

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#19
post #16

Earlier quoted context omitted.

Ah I miscommunicated, I still think PC can and should be used in places like the operand of an LDR / ADD. It's using it as the output of certain instructions (and allowing it to be used as such) that I take issue with. ARMv4T allowed you to set PC as the output of basically any instruction, allowing you to create cursed instructions like this lol: eor pc, pc, pc

Isn't writing to it except by a branch instruction undefined behaviour? If you can use it as an operand, it has a register number, so you can use it as a result, unless you special-case one or the other, which ARM didn't do because it was supposed to be simple. They could have ignored it by omitting some write decode circuitry, but why?

It's not really UB, I've seen games do things like this before. Basically, all data processing instructions can now act as branch instructions, simply by having their dest be PC. Bowser's Inside Story on the DS for example liked to use EOR to write to PC, as a form of encrypting their pointers.

Yeah I think AARCH64 special cases it? Not too familiar with their encoding or how they achieved it. My guess as to why is that it allows you to use more helpful registers (e.g. a zero register) in data processing instructions.

I think I can see your point though - from the perspective of ARMv4T's design, which was to be a simple yet effective CPU, making the PC a GPR does its job. Nowadays the standards are different, but I can see why it made sense at the time.

Re: Solving the Mystery of ARM7TDMI Multiply Carry Flag

#20
> it allows the program counter to be used a general purpose register

From a CPU emulator writer's perspective this isn't all that strange. For instance on Z80 the immediate jump instruction `JP nnnn` is loading a 16-bit immediate value into the internal PC register, which is the same thing as loading a 16-bit value into a regular register pair (e.g. 'LD HL,nnnn') - e.g. the mnemonics for the jump instruction could just as well be `LD PC,nnnn` ;)

A relative jump (which does a signed-add of an 8-bit offset value to the 16-bit address in PC) is the same math as the Z80 indexed addressing mode (IX+d) and (IY+d) (I don't know though if the same transistors are used).

A RET (load 16-bit value from stack into PC) is the the same operation as a POP (load 16-bit value from stack into a regular register pair).

...so it's almost surprising that the program counter isn't exposed as a regular register in most (traditional) CPUs. I guess in modern CPUs it's not so simple because of the internal pipelining though.

Post reply on HN