/prog/, I'm working on a RISC instruction set that is more RISC than any RISC out there. I've devised an instruction format, plus fifteen core instructions that should suffice for any programming out there. The instruction format, instruction forms, and instructions can be found here:
Seems fine, although you're wasting 4 bits on the opcode there, however they're probably well-wasted as it makes tools (assembler/disassembler/...) easier to write.
Fucking terrible. Have you even attempted to implement any nontrivial algorithm in it? Have you simulated it? Implementing a synthesizable Verilog/VHDL simulation would be educational for you.
Name:
Anonymous2011-09-22 9:54
>>3
I'm pretty sure that I'll be missing some important instructions, so a few more bits of opcode headroom is a good idea. This is my first venture into instruction set design, after briefly studying the x86 and PowerPC instruction sets. Do you know of any 'holes' in my instruction set? For example, I saw a 'system call' instruction, mnemonic sc, in PowerPC. I don't understand how that works at all, but I can gather that it's fairly important.
Fucking terrible.
As I would expect, as this is my first design, and I know next to nothing about how things really work.
Have you even attempted to implement any nontrivial algorithm in it? Have you simulated it? Implementing a synthesizable Verilog/VHDL simulation would be educational for you.
That is a good idea.
Name:
Anonymous2011-09-22 10:00
>>4
Care to explain why it's ``fucking terrible''? I don't disagree with you, but more detail and elaboration would be appreciated.
>>5
Depends on what you plan on using the instruction set for. syscall instructions are usually used for dealing with privilege levels (security) and providing a simple way of calling kernel or hypervisor code.
I would also like an indirect jump (to a register) instruction.
Name:
Anonymous2011-09-22 10:13
>>8
The j instruction is an 'indirect' jump, to a register, as you describe. The address field in that instruction is a register reference, from which the address value is pulled.
linux on the intel uses an interrupt with a value of 80, I think. It provides user programs with a method for invoking services from the operating system, like reading and writing to files, opening a file, and the like. Using the interrupt, the user program triggers the interrupt with the value of 80, and then I think the interrupt stops everything running, backs up the state of the processor, goes to a table of code pointers for handling interrupts and executes the 80'th one, which is the system call handler. Then the system call handler looks are the values in the registers, and executes an appropriate service as the operating system. When it is over, the interrupt ends and the processor is restored to its previous state. I think return values are passed in the registers. I would have to double check though. It has been a while.
So I write s 0, 0, 255 to write out 2^255 bytes to memory. The processor takes an exception halfway through. How does it resume execution after the exception handler completes?
write out 2^255 bytes to memory. The processor takes an exception halfway through.
Considering how "halfway through" would occur long after the heat death of the universe, I doubt it will make any difference.
Could you compress instructions?
Eg while app X is running, cpu frequently gets instructions A followed by B, C, etc... so instruct 'a' -> A + B + C...?
Name:
Anonymous2011-09-23 0:19
...might make little difference?
Programmable instruction sets then?? ...build your own SSE-n?
>>22
There are CPUs that incorporate a degree of configurability, and there's always FPGAs, but those will always be slower and use more power than their hard-wired counterparts.
Name:
Anonymous2011-09-23 8:01
Hello again, /prog/.
After some rethinking, I've redesigned the instruction set architecture, this time with various changes, including
- instructions are now 16 bits long
- the opcode field is six bits long
- the register reference fields are five bits long
- for simplicity, ops like `A = B op C' are now `A = A op B'
- there is now a status register, currently only used for c/j
- none of that `[size]' bullshit anymore in the load/store/move ops
Overall, a hopefully cleaner and better designed instruction set.
>>25
Adding SIMD instructions, let alone any instruction that can be completed equally with a combination of other instructions, will defeat the idea of this architecture being RISC.
Name:
Anonymous2011-09-23 8:44
And now for an (untested) emulator in ~50 lines.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define MEM 67108864
#define BITS 64
#define uw uint64_t
#define sw int64_t
int main() {
uint8_t *mem = calloc(MEM, 1);
uint16_t *memi = (uint16_t *) mem, ins, insd, insa, insb;
uint32_t stat = 0;
uw *reg = calloc(32, BITS / 8), cia = 0, nia;
while (1) {
nia = cia + 1;
ins = memi[cia];
insd = ins & 0x3ff;
insa = insd >> 5;
insb = insd & 0x1f;
switch (ins >> 10) {
case 0: break;
case 1: mem[reg[insa]] = mem[reg[insb]]; break;
case 2: reg[insa] = ((reg[insa] >> 8) << 8) | mem[reg[insb]]; break;
case 3: mem[reg[insa]] = reg[insb]; break;
case 4: reg[insa] = (insb >> 1) << ((insb & 1) ? 4 : 0); break;
case 5: reg[insa] = ~reg[insa]; break;
case 6: reg[insa] &= reg[insb]; break;
case 7: reg[insa] |= reg[insb]; break;
case 8: reg[insa] ^= reg[insb]; break;
case 9: reg[insa] += reg[insb]; break;
case 10: reg[insa] -= reg[insb]; break;
case 11: reg[insa] <<= reg[insb]; break;
case 12: reg[insa] >>= reg[insb]; break;
case 13: reg[insa] = (uw) (((sw) (reg[insa])) >> reg[insb]); break;
case 14:
stat = (stat >> 3) << 3;
if (reg[insa] == reg[insb])
stat |= 1;
else if (reg[insa] < reg[insb])
stat |= 2;
else
stat |= 4;
case 15:
if (((insb >> 1) & 7) & (stat & 7))
nia = reg[insa] + ((insb & 1) ? cia : 0);
}
cia = nia;
if (cia > MEM / 2 - 1)
break;
}
free(mem);
free(reg);
return 0;
}
It takes 12 instructions to load 0x12345678 into the first register.
Process
0. load the value 0x8 into the second register
1. load the value 0x1 into the high half of the lowest byte of the first register
2. load the value 0x2 into the low half of the lowest byte of the first register
3. shift the first register left by the second register (8)
4. load the value 0x3 into the high half of the lowest byte of the first register
5. load the value 0x4 into the low half of the lowest byte of the first register
6. shift the first register left by the second register (8)
7. load the value 0x5 into the high half of the lowest byte of the first register
8. load the value 0x6 into the low half of the lowest byte of the first register
9. shift the first register left by the second register (8)
10. load the value 0x7 into the high half of the lowest byte of the first register
11. load the value 0x8 into the low half of the lowest byte of the first register
You can't even copy the value of one register into another. Instead, you have to write the first register out to memory one byte at a time, read the data back into the register one byte at a time and then read the data into the target register one byte at a time.
Also, no way of detecting overflow/underflow in arithmetic operations, or perform bit rotation etc. etc.
>>31
Except Thumb was designed by people who had a fucking clue.
You can't even copy the value of one register into another. Instead, you have to write the first register out to memory one byte at a time, read the data back into the register one byte at a time and then read the data into the target register one byte at a time.
Oh, shit. That's a gaping implementation hole.
Also, no way of detecting overflow/underflow in arithmetic operations, or perform bit rotation etc. etc.
Those are good ideas. How common are their use? Should they be included?
Name:
Anonymous2011-09-23 22:21
>>34
Go download and read through a bunch of CPU datasheets for as many architectures you can find. That should give you an idea of what practical instruction sets look like.
Name:
Anonymous2011-09-23 22:30
>>35
Wouldn't I just end up creating a large instruction set like the rest? Even PowerPC's ``RISC'' ISA seems very large.
>>34
As I said earlier, try implementing some nontrivial algorithms and you'll notice what's missing and what's just badly designed.
Also, the goal of RISC is to have simple instructions that can be executed quickly and without micro-code. Having a small number of instructions is a fallacy.