diff --git a/README.org b/README.org index e68133c..581811f 100644 --- a/README.org +++ b/README.org @@ -10,6 +10,7 @@ The intent behind this project--beyond learning x86 assembly--is to fully emulat Currently there are no dependencies for Miharu. To build and run the CLI REPL, simply: #+begin_src shell + guix shell --pure -m=manifest.scm zig build run #+end_src @@ -33,5 +34,7 @@ Type `?` for help. Type `exit` to quit. > #+end_src -* Links +* References - [[http://www.c-jump.com/CIS77/reference/Instructions_by_Opcode.html][Opcode Reference]] +- [[https://pdos.csail.mit.edu/archive/6.097/readings/intelv2.pdf][Intel Reference Manual]] +- [[https://en.wikipedia.org/wiki/X86_instruction_listings][x86 Instructions By Architecture]] diff --git a/src/cpu.zig b/src/cpu.zig index 658aec8..b719a95 100644 --- a/src/cpu.zig +++ b/src/cpu.zig @@ -19,9 +19,9 @@ const mem = @import("memory.zig"); pub const Register = enum { EAX, + EBX, ECX, EDX, - EBX, // ESP, EBP, @@ -29,10 +29,27 @@ pub const Register = enum { EDI, }; +pub const SegmentRegister = enum { + CS, + DS, + SS, + ES, + FS, + GS, +}; + pub const Cpu = struct { registers: std.EnumArray(Register, u32), + segmentRegisters: std.EnumArray(SegmentRegister, u16), instruction_pointer: u32, //EIP - pub fn execute(self: *Cpu, memory: *mem.Memory, opcode: u8, reg1: Register, reg2: Register) void { - switch (opcode) {} + + pub fn init() Cpu { + return Cpu{ + .instruction_pointer = 0, + .segmentRegisters = std.EnumArray(SegmentRegister, u16) + .initFill(0x0000), + .registers = std.EnumArray(Register, u32) + .initFill(0x00000000), + }; } }; diff --git a/src/instructions.zig b/src/instructions.zig index 77101be..ae6c29a 100644 --- a/src/instructions.zig +++ b/src/instructions.zig @@ -44,9 +44,18 @@ pub const Instruction = struct { }; pub const Opcode = enum { - /// Move family + // MovRegToRegMem_8 = 0x88, MovRegToRegMem_16_32 = 0x89, MovRegMemToMem_8 = 0x8A, - MovRegMemToReg_16_32 = 0xBB, + MovRegMemToReg_16_32 = 0x8B, + MovRegMemToSeg_16 = 0x8C, + LoadEffectiveAddr_16_32 = 0x8D, + MovMemToSeg_16 = 0x8E, + // + JmpNear_16_32 = 0xE9, + JmpFar_16_32 = 0xEA, + JmpShort_8 = 0xEB, + // + MultiByte = 0xFF, }; diff --git a/src/main.zig b/src/main.zig index 88455b9..c45a7f6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -16,9 +16,11 @@ const std = @import("std"); const mem = @import("memory.zig"); +const cpu_ = @import("cpu.zig"); pub fn main() !void { var memory = mem.Memory.init(); + var cpu = cpu_.Cpu.init(); var input = std.io.getStdIn().reader(); var output = std.io.getStdOut().writer(); //Switch to new buffer @@ -41,15 +43,15 @@ pub fn main() !void { , .{}); var buffer: [256]u8 = undefined; while (true) { - std.debug.print("> ", .{}); + modeLine(&cpu, &memory); const line = try input.readUntilDelimiterOrEof(&buffer, '\n'); const clean = std.mem.trim(u8, line.?, " \n\r"); var it = std.mem.splitSequence(u8, clean, " "); if (it.next()) |first_argument| { if (std.mem.eql(u8, first_argument, "exit")) { break; - } else if (std.mem.eql(u8, first_argument, "mem")) { - try handleMemoryCommand(&memory, &it); + } else if (std.mem.eql(u8, first_argument, "sr")) { + try handleSegmentRegisterCommand(&cpu, &it); } } else { // noop @@ -62,37 +64,50 @@ pub fn main() !void { _ = try output.writeAll("\x1b[?25h"); } -fn handleMemoryCommand(memory: *mem.Memory, it: anytype) !void { - if (it.next()) |next_argument| { - if (std.mem.eql(u8, next_argument, "read")) { - if (it.next()) |address| { - const addr = try std.fmt.parseUnsigned(u8, address, 10); - const value = try memory.readByte(addr); - std.debug.print( - \\MEM @ {}: {} - \\ - , .{ addr, value }); - } - } else if (std.mem.eql(u8, next_argument, "write")) { - const maybe_addr = it.next(); - const maybe_value = it.next(); - if (maybe_addr == null or maybe_value == null) { - std.debug.print( - \\Invalid arguments. Usage: mem write - \\ - , .{}); - } else { - const addr = try std.fmt.parseUnsigned(u8, maybe_addr.?, 10); - const value = try std.fmt.parseUnsigned(u8, maybe_value.?, 10); - _ = try memory.writeByte(addr, value); - } - } else { - std.debug.print( - \\Invalid argument '{s}'. Usage: - \\ mem read - \\ mem write - \\ - , .{next_argument}); - } +fn modeLine(cpu: *cpu_.Cpu, memory: *mem.Memory) void { + _ = memory; + std.debug.print( + \\ + \\IP : {x:0>8} + \\EAX: {x:0>8} EBX: {x:0>8} ECX: {x:0>8} EDX: {x:0>8} + \\ESP: {x:0>8} EBP: {x:0>8} ESI: {x:0>8} EDI: {x:0>8} + \\ + , .{ + cpu.instruction_pointer, + cpu.registers.get(.EAX), + cpu.registers.get(.EBX), + cpu.registers.get(.ECX), + cpu.registers.get(.EDX), + // + cpu.registers.get(.ESP), + cpu.registers.get(.EBP), + cpu.registers.get(.ESI), + cpu.registers.get(.EDI), + }); + std.debug.print("> ", .{}); +} + +fn printSr(cpu: *cpu_.Cpu) void { + std.debug.print( + \\Segment Registers: + \\CS: {x:0>4} DS: {x:0>4} SS: {x:0>4} + \\ES: {x:0>4} FS: {x:0>4} GS: {x:0>4} + \\ + , .{ + cpu.segmentRegisters.get(.CS), + cpu.segmentRegisters.get(.DS), + cpu.segmentRegisters.get(.SS), + // + cpu.segmentRegisters.get(.ES), + cpu.segmentRegisters.get(.FS), + cpu.segmentRegisters.get(.GS), + }); +} + +fn handleSegmentRegisterCommand(cpu: *cpu_.Cpu, it: anytype) !void { + if (it.next()) |_| { + std.debug.print("Wrong number of arguments.\n", .{}); + } else { + printSr(cpu); } }