Some processors - generally, 32-bit RISC ones - make sure that all instructions fit in one location in memory. This works for them because 32 bits is enough to fit plenty of instructions, and it makes it easy for the processor to load instructions. All the instruction operands are included as part of the instruction. The instructions are often bigger than they need to be, but the simplicity can be worth it.
8-bit processors don't do this, because you can't really fit enough instructions in only 8 bits. You can only fit 256 instructions, in fact. If they have 4-bit operands (not enough) you can only fit 16 instructions (also not enough). So multi-byte instructions are a necessity.
However, 256 is plenty of opcodes. In the 8-bit era it was typical that a CPU would read a 1-byte opcode, and then the operands (if any) would be in the next 1 or 2 bytes.
I.e. - loading the MAR with the PC address, incrementing the PC, and loading from memory into part of the instruction register, repeated up to three times.
Almost. You could do this. But 8-bit CPUs generally do not have 3-byte instruction registers. Instead, the instructions are designed so only the opcode needs to be stored in the opcode register is needed, and the operand bytes can go directly to their final destination. An instruction like ADD BC, 1234
might process the bytes like this:
- load the MAR with the PC address, increment the PC, and load from memory into the opcode register
- load the MAR with the PC address, increment the PC, load from memory into the ALU right input, load from register C into the ALU left input, set the ALU mode to ADD, store from the ALU output into register C
- load the MAR with the PC address, increment the PC, load from memory into the ALU right input, load from register B into the ALU left input, set the ALU mode to ADC (add-with-carry), store from the ALU output into register B
To keep track of the steps, you might find it helpful to add a step counter "mini-register" which increments each cycle, except at the end of the instruction when it resets. Then you can use the opcode register and the step counter and combinational logic to select what the CPU should do in the current clock cycle. If you use a ROM chip instead of combinational logic, the contents of the ROM are called microcode.
For jump and call instructions specifically (with 16-bit addresses), the Z80 CPU uses an extra, hidden 16-bit register called WZ. Normally you would load 16 bits from memory into a register by loading one half, then the other half. But when you are loading into the program counter, you can't do this, because if you load the first half of the program counter then it messes up the address you load the second half from. So it loads the halves into WZ and then transfers WZ to PC.
To save having a WZ register, a different idea is to make the programmer load the address into a register, then jump to the address in the register. You can still have relative jumps (add an 8-bit value to the PC) and page-relative jumps (loading the lower 8 bits only) without needing any extra registers.
Also, how would this work for jump instructions? If I want to jump to a specific instruction in the program, but don't know the address in memory because of all the other multi-length instructions
You do know the address. Each instruction has an address, and you tell the CPU to jump to the address of the instruction.