Why no conditional BSR or JSR ? - Page 1
Forum section: electronics / general

author: Circlotron
author_rank: Super Contributor
timestamp: November 09, 2022, 11:25:03 pm
content: I'm stuck in the world of NXP 908 and S08 micros, so forgive me for my narrow world view...What I'd love to see is a conditional branch or jump to a subroutine in the same manner as BRSET, BRCLR, BCS, BCC and almost all the other instructions that start with "B". Is there some limitation in MCU architecture that would make this a difficult or expensive feature to implement? Or are there MCUs that actually do this?I might have asked this question previously and forgotten. I'm getting a bit like that nowadays.

author: brucehoult
author_rank: Super Contributor
timestamp: November 10, 2022, 12:19:55 am
content: There's probably no reason other than that as you add more and more features to an instruction you use up more and more opcode bits, and possibly have to leave out some other instruction entirely.That's a Cortex M4F? So it's T32. So you can conditionalise anything using IT**.ARM's A32 instruction set (supported in all Cortex A to date -- and of course older MCUs such as ARM7/ARM9 -- but not Cortex M) has conditional execution for all instructions, including BL. It takes up 4 bits in the instruction. T32, approximately speaking, instead uses those 4 bits to differentiate 2 byte opcodes from 4 byte opcodes.Which do you prefer: being able to have an occasional conditional JSR, or having 2/3 of your instructions be only 2 bytes instead of 4 bytes?

author: tabemann
author_rank: Contributor
timestamp: November 10, 2022, 03:59:32 am
content: They key thing is that subroutine calls typically involve larger offsets than other branches, and having condition codes in them would take bits away that could otherwise be dedicated to the offset, thus reducing the possible range of the subroutine call (and thus increasing the number of subroutine calls that need to be implemented through some sort of "far call" fashion, such as setting a register to a constant, and then doing an indirect subroutine call on that register).

author: brucehoult
author_rank: Super Contributor
timestamp: November 10, 2022, 05:20:30 am
content: Yup, you could steal 4 bits for the condition from the BL offset and reduce it from ±16 MB (Thumb2) to ±1 MB. How harmful this is depends on how often you have code sizes between 1 MB and 16 MB that will then have to use alternative instruction sequences.RISC-V only has ±1 MB range for JAL anyway, but it is designed such that a AUIPC/JALR pair can reach ±2 GB, and a LUI/JALR pair can reach absolute addresses in the bottom or top 2 GB of the address space (which is all of it on a 32 bit CPU).On Thumb2 extending the range requires a PC-relative load from a constant pool then a BLX for an absolute address, or the same plus an add for a relative address.On a microcontroller with maximum 256 kB ROM and 512 kB flash you probably don't care. Unless the ROM and flash are separated in the address space and you want to call between them.

author: westfw
author_rank: Super Contributor
timestamp: November 10, 2022, 05:34:23 am
content: QuoteNo, 908 and S08 are 8bit micros; followons to the 6805.If you look at the opcode map, you'll see that there isn't room for the additional 32 (?) opcodes that would be needed.

author: brucehoult
author_rank: Super Contributor
timestamp: November 10, 2022, 06:48:47 am
content: Quote from: westfw on November 10, 2022, 05:34:23 amAhhhh.But, on the contrary, they can just use one of the free opcodes to make a prefix introducing an entire new page of 256 instructions, and add conditional BSRs in there. It's all just microcoded anyway.That would save 1 byte of program code compared to doing a B<opposite condition> around the BSR. Might not save any clock cycles though.

author: Kleinstein
author_rank: Super Contributor
timestamp: November 10, 2022, 07:29:43 am
content: There is not that much need for a conditional jump to a subroutine. One can always work around with skipping a jump to subroutine, either with a special command or a short conditional jump.An additional problem is that the JSR command already tends to be one of the slowest commands and an additional condition may add to this. The slowest OP-code effects the interrrupt latency.

author: westfw
author_rank: Super Contributor
timestamp: November 10, 2022, 07:36:07 pm
content: Quotethat wouldnotbe an "easy" modification :-) Pretty soon you'd have a 68000."(Were 6800-class CPUs actually microcoded? I didn't think that showed up till later.)I think the 8080 family is the only place I've seen "conditional call" instructions.(Not counting ARM's "any instruction can be conditional", which is mostly not present in the microcontrollers.)

author: Kleinstein
author_rank: Super Contributor
timestamp: November 10, 2022, 08:05:10 pm
content: The 6800 type CPUs should be more directly hard coded, similar to the 6502 (the 6502 is kind of a simplified / reduced version of the 6800).Microcode is more thing of 8080, 8051 and simialr CPUs that use many more cycle but a higher clock frequency,AFAIK a prefix is used in the Z80 for extra instructions. But of cause not just for a few easy to replace commands.

author: Benta
author_rank: Super Contributor
timestamp: November 10, 2022, 08:39:00 pm
content: You might as well ask "why doesn't a simple 8-bit MCU not have a 16 x 16 MAC instruction?".If using a branch instruction followed by a JSR is overwhelming, well, there are other architectures out there.

author: brucehoult
author_rank: Super Contributor
timestamp: November 10, 2022, 09:58:13 pm
content: Quote from: westfw on November 10, 2022, 07:36:07 pm6809 has multiple opcode pages.68000 *doesn't*. All opcodes are exactly 2 bytes, plus possibly one or two following pure literal/offset words.QuoteAnything that decodes instructions step by step and then performs operations such as "load data from a memory address, increment it, write it back to memory" is microcoded. Or at least micro-sequenced. A state machine. This is very different from the one-hit and it's done RISC non-microcoded model, or the "we don't even have to decode the instruction, the hardware is directly controlled by bits in the opcode" model of the PDP-8 and Nova.

author: westfw
author_rank: Super Contributor
timestamp: November 10, 2022, 10:27:23 pm
content: QuoteMicro-sequenced I believe. IMO, it's not "micro-coded" unless your state machines are driven by a memory array that you can point at and say "there's the microcode!"

author: brucehoult
author_rank: Super Contributor
timestamp: November 10, 2022, 11:19:31 pm
content: Quote from: Kleinstein on November 10, 2022, 08:05:10 pmThe 6502 is quite a lot more complex than the 6800, not simplified.The 6502 is an attempt to get much better performance from about the same amount of silicon as the 6800. The first 6800s were 5.4mm square, and the 2nd generation ones (1.5 and 2 MHz) were 4mm square. The first 6502 chips were 4.3 x 4.7 mm. So very similar. The 6502 reduced the amount of the chip used by registers, but increased the amount of the chip used by microcode control for the much more complex instructions. On the 6502 about 1/6th of the area was used by the microcode ROM. I don't know how much of the 6800 was ... I can find 6800 die shots but not annotated ones.A 6800 instruction such as INC 13,X or INC $1234 had to perform quite a lot of individual steps:1) load and decode the opcode2) load the 133) add 13 to X4) load the contents at address 13+X5) increment it6) write the result back to memory at address 13+XI've listed six steps there but the instruction took seven cycles, presumably because adding the offset to X used an 8 bit adder and took 2 cycles.For INC $1234:1) load and decode the opcode2) load the $123) load the $344) load data from address $12345) increment it6) write the result back to address $1234Six steps, the the instruction indeed took six cycles to execute.A 6502 instruction such as ADC (13),Y with RAM address 13-14 containing $1234 has more steps:1) load and decode the opcode2) load the 133) load $34 from address 134) add $34 to Y and save as the LSB of the final memory address5) load $12 from address 146) add $12 to the carry from adding Y (if necessary) and save as the MSB of the final memory address7) load the data from address $1234+Yadd it to the accumulatorThere are 8 steps there, but the 6502 actually took 5 cycles if there was no carry in the add or 6 cycles if there was a carry.I believe this is because of the following clever bits:- steps 4 and 5 are done at the same time. This would not have worked with addresses in big endian order like the 6800.- step 6 is skipped if no carry- step 1 is overlapped with the ALU cycle of the previous instruction (except STA/STX/STY which don't have one); the next opcode is fetched during step 8.Note that the Read-Modify-Write instructions on 6502 (inc, dec, shifts & rotates) are limited to the simpler addressing modes -- no (zp,X) or (zp),Y -- to reduce the maximum number of microcode steps in one instruction to make the microcode ROM smaller.Note the difference to something like RISC-V RV32I or RV64I which on the simplest implementation with async SRAM can execute everything except loads and stores in 1 clock cycle:PC -> SRAM -> opcode -> Rs1 & Rs2 fields -> register SRAM -> ALU (with operation field, and maybe constant from opcode) -> (new PC; new Rd contents)It's just pure combinatorial data flow, not sequential.

author: brucehoult
author_rank: Super Contributor
timestamp: November 10, 2022, 11:32:05 pm
content: Quote from: westfw on November 10, 2022, 10:27:23 pm6502:http://www.weihenstephan.org/~michaste/pagetable/6502/6502-die.jpgThat green rectangle at the bottom is the 130×21 bit microcode ROM.The less regular big rectangle at the top is the registers and ALU, with the ALU being kind of the middle 3rd.6800:https://www.cpu-world.com/CPUs/6800/die/L_AMI-S6800.jpgI'm unable to find an annotated version, but I expect the microcode array is the rectangle on the right, taking up a considerably smaller proportion than on the 6502, but definitely still present. I expect the registers and ALU are on the left, and messy random looking control stuff in the middle.It's definitely not just a couple of flip-flops or shift register for the state and some random gates to derive the control signals and next state. It's an organised rectangular microcode ROM that you can, as you say, point to.

author: tabemann
author_rank: Contributor
timestamp: November 11, 2022, 05:49:51 am
content: Quote from: brucehoult on November 10, 2022, 05:20:30 amI found that on the RP2040 the SRAM and the XIP memory-mapped Quad SPI flash spaces are too far apart for BL to reach one from the other, and as zeptoforth's kernel lives in SRAM (due to the nature of the beast, it needs to execute out of SRAM while programming or erasing the Quad SPI flash) but the remainder of zeptoforth lives in flash it needs to use PC-relative LDR instructions to load constant addresses into registers which are then called with BLX so that the portion of zeptoforth in flash can call the zeptoforth kernel.

author: brucehoult
author_rank: Super Contributor
timestamp: November 11, 2022, 09:24:17 am
content: Quote from: tabemann on November 11, 2022, 05:49:51 amYeah. With flash XIP at 0x10000000 and SRAM starting at 0x20000000 -- 256 MB apart -- that is waaaay too far for a B or BL to reach. Not even 64 bit ARMv8-A with ±128 MB BL range can do that!A similar problem exists in RISC-V microcontrollers. The Zcmt extension, which is currently under public review and will have the ratification vote in December, aims to solve this with the cm.jt and cm.jalt instructions.The extension introduces the JVT CSR which points to a 256-entry table of 4 byte or 8 byte addresses of code (RV32 or RV64).The cm.jalt instruction is a 2 byte instruction with an 8 bit index field. The index is multiplied by the word size, added to the base address in the CSR, the data at that address fetched, and the fetched data loaded into the PC. Indexes of 0..31 result in a simple branch to the address, indexes 32..255 result in a branch and link.So you can have up to 192 well-known functions located anywhere in the address space (ROM, RAM, XIP, whatever) and call them with a single 2-byte instruction.It's not very RICSy :-( But a subset of people using small microcontrollers are "we don't care, we just want the smallest code size".The Zcmp extension (also now under review for ratification) introduces 2-byte "C" instructions for function prolog and epilog that push/pop RA and S0..Sn *and* adjust SP to the next multiple of 16 bytes *and* then inc/dec SP by an additional {0,16,32,48) bytes. The pop instruction can also optionally jump (return) to the address just loaded into RA, and can also optionally load 0 into A0 (function result).Zcmp and Zcmt reuse C extension opcodes that are already used to load/store double precision floating point registers relative to SP, and so are incompatible with general purpose RV32GC and RV64GC code. Zcmp and Zcmt are NOT intended to be implemented in Applications-class processors and will never be expected by standard Linux etc distributionsJust for completeness, the Zcb extension (also now under review for ratification) adds 2-byte "C" instructions for byte/half load/store and for sign/zero extend for byte/half and zero extend from word to double on 64 bit CPUs. Also a 1-address NOT and 2-address multiply. These use previously unallocated opcode space and will probably be implemented on almost all CPU cores in future (including Application-class processors), though they are not included in RVA22.I note that RISC-V C extension still lacks Thumb's 2-byte instructions for 3-address add/subtract (register or 3 bit constant) and the (rarely used) dynamic shift counts. There isn't opcode space for the add/sub so it will never happen, and the variable shift simply isn't important.https://github.com/riscv/riscv-code-size-reduction/releases/download/v1.0.0-RC5.7/Zc-v1.0.0-RC5.7.pdf

author: Retep
author_rank: Regular Contributor
timestamp: November 11, 2022, 10:00:16 am
content: Quote from: brucehoult on November 10, 2022, 11:32:05 pmI think this site can answer that question- Transistor level simulation of the 6502:http://visual6502.org/JSSim/index.html- Transistor level simulation of the 6800:http://visual6502.org/JSSim/expert-6800.htmlThe layout of the 6502 & 6800 dies look very similar (perhaps not too surprising considering the history of the 6502 designer).

author: brucehoult
author_rank: Super Contributor
timestamp: November 11, 2022, 11:07:58 am
content: Quote from: Retep on November 11, 2022, 10:00:16 amIt doesn't have an annotated die shot showing the functional units. It shows the silicon and metal layers.