diff options
Diffstat (limited to 'usr.bin/oemu')
-rw-r--r-- | usr.bin/oemu/cpu.c | 157 | ||||
-rw-r--r-- | usr.bin/oemu/include/oemu/cpu.h | 14 | ||||
-rw-r--r-- | usr.bin/oemu/include/oemu/osmx64.h | 2 | ||||
-rw-r--r-- | usr.bin/oemu/include/oemu/types.h | 3 |
4 files changed, 175 insertions, 1 deletions
diff --git a/usr.bin/oemu/cpu.c b/usr.bin/oemu/cpu.c index 9b8c622..07ddc7b 100644 --- a/usr.bin/oemu/cpu.c +++ b/usr.bin/oemu/cpu.c @@ -123,6 +123,108 @@ cpu_add(struct oemu_cpu *cpu, inst_t *inst) } /* + * Decode the INST_SUB instruction + * + * @cpu: CPU that is executing + * @inst: Instruction dword + */ +static void +cpu_sub(struct oemu_cpu *cpu, inst_t *inst) +{ + struct cpu_regs *regs = &cpu->regs; + imm_t imm; + + if (inst->rd > NELEM(regs->xreg)) { + printf("bad register operand for 'sub'\n"); + return; + } + + imm = regs->xreg[inst->rd]; + regs->xreg[inst->rd] -= inst->imm; + printf("%d - %d -> X%d, new=%d\n", + imm, inst->imm, inst->rd, regs->xreg[inst->rd]); +} + +/* + * Decode the INST_MUL instruction + * + * @cpu: CPU that is executing + * @inst: Instruction dword + */ +static void +cpu_mul(struct oemu_cpu *cpu, inst_t *inst) +{ + struct cpu_regs *regs = &cpu->regs; + imm_t imm; + + if (inst->rd > NELEM(regs->xreg)) { + printf("bad register operand for 'mul'\n"); + return; + } + + imm = regs->xreg[inst->rd]; + regs->xreg[inst->rd] *= inst->imm; + printf("%d * %d -> X%d, new=%d\n", + imm, inst->imm, inst->rd, regs->xreg[inst->rd]); +} + +/* + * Decode the INST_DIV instruction + * + * @cpu: CPU that is executing + * @inst: Instruction dword + */ +static void +cpu_div(struct oemu_cpu *cpu, inst_t *inst) +{ + struct cpu_regs *regs = &cpu->regs; + imm_t imm; + + if (inst->rd > NELEM(regs->xreg)) { + printf("bad register operand for 'div'\n"); + return; + } + + imm = regs->xreg[inst->rd]; + if (imm == 0) { + /* TODO: Some sort of interrupt */ + printf("** DIVIDE BY ZERO **\n"); + return; + } + + regs->xreg[inst->rd] /= inst->imm; + printf("%d / %d -> X%d, new=%d\n", + imm, inst->imm, inst->rd, regs->xreg[inst->rd]); +} + +/* + * Decode the INST_DIV instruction + */ +static void +cpu_br(struct oemu_cpu *cpu, inst_t *inst) +{ + struct cpu_regs *regs = &cpu->regs; + imm_t imm; + addr_t br_to; + + if (inst->rd > NELEM(regs->xreg)) { + printf("bad register operand for 'br'\n"); + return; + } + + /* + * If we are branching to the reset vector, might + * as well reset all state. + */ + br_to = regs->xreg[inst->rd]; + if (br_to == 0) { + cpu_reset(cpu); + } + + regs->ip = br_to; +} + +/* * Reset a CPU to a default state */ void @@ -130,11 +232,46 @@ cpu_reset(struct oemu_cpu *cpu) { struct cpu_regs *regs; + /* + * When an OSMX64 processor first starts up, it will + * initially be executing in supervisor mode with all + * of its registeres initialized to zeros. + */ regs = &cpu->regs; regs->ip = 0; + regs->sr_state = CPU_SRS_SV; + regs->blr = 0x0; + regs->ilr = 0x0; memset(regs->xreg, 0x0, sizeof(regs->xreg)); } +void +cpu_regdump(struct oemu_cpu *cpu) +{ + struct cpu_regs *regs; + + regs = &cpu->regs; + printf( + "X0=%p, X1=%p, X2=%p\n" + "X3=%p, X4=%p, X5=%p\n" + "X6=%p, X7=%p, X8=%p\n" + "X9=%p, X10=%p, X11=%p\n" + "X12=%p, X13=%p, X14=%p\n" + "X15=%p, IP=%p, SRS=%p\n" + "BLR=%p, ILR=%p\n", + regs->xreg[0], regs->xreg[1], + regs->xreg[2], regs->xreg[3], + regs->xreg[4], regs->xreg[5], + regs->xreg[6], regs->xreg[7], + regs->xreg[8], regs->xreg[9], + regs->xreg[10], regs->xreg[11], + regs->xreg[12], regs->xreg[13], + regs->xreg[14], regs->xreg[15], + regs->ip, regs->sr_state, + regs->blr, regs->ilr + ); +} + /* * Main instruction execution loop. */ @@ -161,6 +298,24 @@ cpu_kick(struct oemu_cpu *cpu, struct sysmem *mem) case INST_ADD: cpu_add(cpu, inst); break; + case INST_SUB: + cpu_sub(cpu, inst); + break; + case INST_MUL: + cpu_mul(cpu, inst); + break; + case INST_DIV: + cpu_div(cpu, inst); + break; + case INST_BR: + cpu_br(cpu, inst); + break; + } + + /* Is this a halt instruction? */ + if (inst->opcode == INST_HLT) { + printf("HALTED\n"); + break; } if (regs->ip >= MEMORY_SIZE) { @@ -169,4 +324,6 @@ cpu_kick(struct oemu_cpu *cpu, struct sysmem *mem) regs->ip += sizeof(*inst); } + + cpu_regdump(cpu); } diff --git a/usr.bin/oemu/include/oemu/cpu.h b/usr.bin/oemu/include/oemu/cpu.h index df4cc80..882fe93 100644 --- a/usr.bin/oemu/include/oemu/cpu.h +++ b/usr.bin/oemu/include/oemu/cpu.h @@ -31,6 +31,7 @@ #define _OEMU_CPU_H_ #include <sys/types.h> +#include <sys/param.h> #include <stdint.h> #include <stddef.h> #include <oemu/types.h> @@ -38,6 +39,12 @@ #define MEMORY_SIZE 512 /* + * Processor state register + */ +#define CPU_SRS_SV BIT(1) /* Supervisor flag */ +#define CPU_SRS_CARRY BIT(2) /* Carry flag */ + +/* * System memory * * @mem: Data @@ -53,16 +60,23 @@ struct sysmem { * * @xreg: X<n> * @ip: Instruction pointer + * @sr_state: Processor state register + * @blr: Branch link register + * @ilr: Interrupt link register */ struct cpu_regs { reg_t xreg[16]; reg_t ip; + reg_t sr_state; + reg_t blr; + reg_t ilr; }; struct oemu_cpu { struct cpu_regs regs; }; +void cpu_regdump(struct oemu_cpu *cpu); void cpu_reset(struct oemu_cpu *cpu); void cpu_kick(struct oemu_cpu *cpu, struct sysmem *mem); diff --git a/usr.bin/oemu/include/oemu/osmx64.h b/usr.bin/oemu/include/oemu/osmx64.h index d7ea8b1..b1df5d3 100644 --- a/usr.bin/oemu/include/oemu/osmx64.h +++ b/usr.bin/oemu/include/oemu/osmx64.h @@ -47,6 +47,8 @@ #define INST_SLL 0x11 /* Shift left logical operation */ #define INST_SRL 0x12 /* Shift right logical operation */ #define INST_MOV_IMM 0x13 /* Data move operation from IMM */ +#define INST_HLT 0x14 /* Halt */ +#define INST_BR 0x15 /* Branch */ /* Registers */ #define REG_X0 0x00 diff --git a/usr.bin/oemu/include/oemu/types.h b/usr.bin/oemu/include/oemu/types.h index 0769c84..caf6e9b 100644 --- a/usr.bin/oemu/include/oemu/types.h +++ b/usr.bin/oemu/include/oemu/types.h @@ -33,7 +33,8 @@ #include <sys/types.h> typedef uint64_t reg_t; -typedef uintptr_t paddr_t; +typedef uintptr_t addr_t; typedef uint16_t imm_t; +typedef addr_t paddr_t; #endif /* !_OEMU_TYPES_H_ */ |