QuoteThe MSP430 code gcc produced for your example is depressingly bad.Here's what I get for a hand-written MSP430 version.
mul rd rs1 rs2 31..25=1 14..12=0 6..2=0x0C 1..0=3
mulh rd rs1 rs2 31..25=1 14..12=1 6..2=0x0C 1..0=3
mulhsu rd rs1 rs2 31..25=1 14..12=2 6..2=0x0C 1..0=3
mulhu rd rs1 rs2 31..25=1 14..12=3 6..2=0x0C 1..0=3
div rd rs1 rs2 31..25=1 14..12=4 6..2=0x0C 1..0=3
divu rd rs1 rs2 31..25=1 14..12=5 6..2=0x0C 1..0=3
rem rd rs1 rs2 31..25=1 14..12=6 6..2=0x0C 1..0=3
remu rd rs1 rs2 31..25=1 14..12=7 6..2=0x0C 1..0=3
Do people use gcc for msp430, or something else?
fd4e: 27 4d mov @r13, r7 ;
fd50: 08 47 mov r7, r8 ;
fd52: 28 5e add @r14, r8 ;
fd54: 09 48 mov r8, r9 ;
fd56: 09 5a add r10, r9 ;
fd58: 8c 49 00 00 mov r9, 0(r12) ;
fd5c: 4b 46 mov.b r6, r11 ;
fd5e: 08 97 cmp r7, r8 ;
fd60: 01 28 jnc $+4 ;abs 0xfd64
fd62: 4b 45 mov.b r5, r11 ;
fd64: 48 46 mov.b r6, r8 ;
fd66: 09 9a cmp r10, r9 ;
fd68: 01 28 jnc $+4 ;abs 0xfd6c
fd6a: 48 45 mov.b r5, r8 ;
fd6c: 4b d8 bis.b r8, r11 ;
fd6e: 4a 4b mov.b r11, r10 ;
fd70: 2d 53 incd r13 ;
fd72: 2e 53 incd r14 ;
fd74: 2c 53 incd r12 ;
fd76: 0f 9d cmp r13, r15 ;
fd78: ea 23 jnz $-42 ;abs 0xfd4e
c: 38 4d mov @r13+, r8
e: 3b 4e mov @r14+, r11
10: 0b 58 add r8, r11
12: 0a 43 clr r10
14: 0b 98 cmp r8, r11
16: 01 2c jc $+4 ;abs 0x1a
18: 1a 43 mov #1, r10 ;r3 As==01
1a: 0b 59 add r9, r11
1c: 2c 53 incd r12
1e: 8c 4b fe ff mov r11, -2(r12) ; 0xfffe
22: 08 43 clr r8
24: 0b 99 cmp r9, r11
26: 01 2c jc $+4 ;abs 0x2a
28: 18 43 mov #1, r8 ;r3 As==01
2a: 09 48 mov r8, r9
2c: 09 da bis r10, r9
2e: 1f 83 dec r15
30: ed 23 jnz $-36 ;abs 0xc
(!12 of those instructions are faking the carry status, which is the sort of thing that makes assembly programmers curse at HLLs...) e: 594b ldr r3, [r1, r5]
10: 5954 ldr r4, [r2, r5]
12: 191c adds r4, r3, r4
14: 19a7 adds r7, r4, r6
16: 42b7 cmp r7, r6
18: 41b6 sbcs r6, r6
1a: 429c cmp r4, r3
1c: 41a4 sbcs r4, r4
1e: 5147 str r7, [r0, r5]
20: 4264 negs r4, r4
22: 4276 negs r6, r6
24: 3504 adds r5, #4
26: 4326 orrs r6, r4
28: 45ac cmp ip, r5
2a: d1f0 bne.n e <bignumAdd+0xe>
If anybody is interested, I've put my RISC-V toy up on Github - https://github.com/hamsternz/emulate-risc-v - I've even added a little colour.
Does anybody know where I can find the encoding for the RV32M extensions? I've got to the point where the binary I am using uses DIVU...
make software PROGRAM=hello RISCV_ARCH=rv32i
I was going to complain about CM0, since it has a bunch of unpleasant surprises for the assembly programming
I was going to complain about CM0, since it has a bunch of unpleasant surprises for the assembly programming
I am coding CM0+ in assembler, and didn't found any unpleasant surprises till now. Coming from MSP430 (20-bit CPUvX2) assembler.
Also, for comparing code that is executing on different MCU's, relevant is number of cycles, not number of instructions.
Number of clock cycles depends not only on the instruction set but on the implementation
Or, in the case of ARM, it's nice that the ABI and the hardware agree on which registers get saved, so that ISR functions and normal C functions are indistinguishable. I guess. Other times I wish the ISRs in C code were more easily distinguishable, and that the HW interrupt entry was quicker...
What I really need is a reference book for the RISC-V that covers all the hardware details. Not just at 10,000 feet up but right down in the dirt. Something I can convert from text to HDL or, better yet, maybe the HDL is given.
Are there any such references?
I think that this is the key of the RISC-V ethos - it is just the ISA specification. What you do with it is up to you.
As long as your hardware runs the RISC-V RV32I (+ whatever extensions) you don't have to worry too much about the software tooling.
RISC-V it isn't a hardware specification - it is a specification of the interface between the software layer and digital logic layers. If you build a CPU that implements RISC-V, you have a ready-made software layer.
I think I am coming at this from the other end. I don't particularly care about the ISA, I am primarily interested in implementing pipelined hardware that implements the/an ISA in some minimal number of clocks, But, as long as I'm implementing something, it might as well be for a modern ISA. The two are tied together, without doubt, but an ISA without hardware is pretty meaningless.
I think I am coming at this from the other end. I don't particularly care about the ISA, I am primarily interested in implementing pipelined hardware that implements the/an ISA in some minimal number of clocks, But, as long as I'm implementing something, it might as well be for a modern ISA. The two are tied together, without doubt, but an ISA without hardware is pretty meaningless.
It will be easier to implement RISC-V ISA and you're likely to make it run at faster clock speeds. Of course, you can probably do better if you design your own RISC ISA which is specifically suited for your particular hardware (such as specific FPGA), but not by much, and with RISC-V you get free software tools.
I have VS Code and PlatformIO installed and I can build the blinking LED example from the videos. What I haven't tumbled to is how to get Debug to work. If I attempt to debug, the .elf file is created, a bunch of messages pour out on the terminal then, after a few second timeout, I get an error dialog that says the connection was refused.
I wandered through PlatformIOs site and while they extol the virtues of the debugger, I can't seem to find PHD type instructions (Push Here Dummy). There doesn't seem to be much help on the SiFive site either. Or, I missed it...
Any hints?
RISC-V is at the very beginning. They have chosen RISC. For the RISC approach, it is designed exceptionally well, and I don't think it's possible to create RISC ISA which would be substantially better. If it spreads, it should outcompete ARM fairly quickly.
Without any doubts, you can create CISC ISA which will provide better code density, the same way as Huffman compression will always take less space than plain text.
QuoteCM0 ... has a bunch of unpleasant surprisesI am coding CM0+ in assembler, and didn't found any unpleasant surprises
PORT->Group[0].PINCFG[12].reg |= PORT_PINCFG_DRVSTR;
PORT->Group[0].DIRSET.reg |= 1<<12;
ldr r1, =(PORT + <offset of GROUP[0]>)
ldr r2, [r1, #<offset of PINCFG[12]>]
orr r2, #PORT_PINCFG_DRVSTR
str r2, [r1, #<offset of PINCFG[12]>]
ldr r2, [r1, #PORT_DIRSET]
orr r2, #4096
str r2, [r1, #PORT_DIRSET]
Hmm ... I will be surprised. RISC-V might take 10% of ARM's market in the next five years, but ARM is awfully entrenched. They have a good product, refined over many years.
RISC-V is at the very beginning. They have chosen RISC. For the RISC approach, it is designed exceptionally well, and I don't think it's possible to create RISC ISA which would be substantially better. If it spreads, it should outcompete ARM fairly quickly.
Hmm ... I will be surprised. RISC-V might take 10% of ARM's market in the next five years, but ARM is awfully entrenched. They have a good product, refined over many years.
I wouldn't be surprised to see MicroChip convert their 32 bit PIC line from MIPS to RISC-V.
1) modern RISC ISAs such as Thumb2 and RISC-V are already Huffman encoded.
2) 8086 is nowhere near Huffman encoded. It's encoded as "if it doesn't need any arguments then it gets a short encoding". Just look at AAA, AAD, AAM, AAS, ADC, CLC, CLD, CLI, CMC, DAA, DAS, HLT, IN, INT, INTO, IRET, JNP, JO, JP, JPE, JPO, LAHF, OUT, RCL, RCR, SAHF, SBB, STC, STD, STI, XLATB. That's 31 instructions -- almost 1/8th of the opcode space -- taken up by instructions that are either statistically never used (especially now), or that even in 8086 days were not used often enough to justify a 1-byte encoding (plus offset for the Jumps). Most of them probably do need to exist (or did) but the effect on program size or speed if they'd been hidden away in a secondary opcode page would be minuscule. And those opcodes could have been used for something useful.
If RISC-V spreads, it should outcompete ARM fairly quickly.
QuoteIf RISC-V spreads, it should outcompete ARM fairly quickly.I think you underestimate the effectiveness and importance of a large marketing, sales, and support organization...
My surprises show up when initializing periperals. I expected code like:Code: [Select]PORT->Group[0].PINCFG[12].reg |= PORT_PINCFG_DRVSTR;
PORT->Group[0].DIRSET.reg |= 1<<12;
To be implementable with code something like:Code: [Select]ldr r1, =(PORT + <offset of GROUP[0]>)
ldr r2, [r1, #<offset of PINCFG[12]>]
orr r2, #PORT_PINCFG_DRVSTR
str r2, [r1, #<offset of PINCFG[12]>]
ldr r2, [r1, #PORT_DIRSET]
orr r2, #4096
str r2, [r1, #PORT_DIRSET]
Instead, you run into "orr doesn't have immediate arguments any more" and "PINCFG is beyond the range allowed by the [r, #const] encoding", so the code takes an extra 5 instructions and two additional registers. The extra instructions may be a wash with the 32bit forms on the v7m chips, but having to use the extra registers (out of the limited set available) is ... annoying.
ldr r1, =(PORT + <offset of GROUP[0]> + #<offset of PINCFG[12]>)
ldr r2, [r1]
ldr r3, #PORT_PINCFG_DRVSTR
orr r2, r3
str r2, [r1]
ldr r1, =(PORT + <offset of GROUP[0]> + #PORT_DIRSET)
ldr r2, [r1]
ldr r3, #4096
orr r2, r3
str r2, [r1]
Now, what Bruce's example code seems to demonstrate is that the "peripheral initialization" is essentially a degenerate case and that the issues I'm complaining about show up less in the "meat" of a real program. That could be, and it's an interesting result.
(I was impressed by the RV32i summary that was posted, WRT the impressive array of "immediate" operands. But I haven't looked too carefully to see if it does the things I want.)
Probably I will buy a tiny RISC-V board to develop a pocket calculator. This idea sounds really intriguing to me
I have already reverse engineered a CASIO Graphics calculator, thus I can re-use the keyboards, I just need a proper LCD ... and a motherboard. The software can be derived from the NUMWorks's project (opensource).