Add Segment Register command, add Modeline, &c

This commit is contained in:
Lynn Leichtle 2024-09-18 19:31:06 +02:00
parent ef98f1e243
commit 8e8f85fc53
Signed by: lynn
GPG key ID: 55E797F631DDA03C
4 changed files with 85 additions and 41 deletions

View file

@ -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: Currently there are no dependencies for Miharu. To build and run the CLI REPL, simply:
#+begin_src shell #+begin_src shell
guix shell --pure -m=manifest.scm
zig build run zig build run
#+end_src #+end_src
@ -33,5 +34,7 @@ Type `?` for help.
Type `exit` to quit. Type `exit` to quit.
> >
#+end_src #+end_src
* Links * References
- [[http://www.c-jump.com/CIS77/reference/Instructions_by_Opcode.html][Opcode Reference]] - [[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]]

View file

@ -19,9 +19,9 @@ const mem = @import("memory.zig");
pub const Register = enum { pub const Register = enum {
EAX, EAX,
EBX,
ECX, ECX,
EDX, EDX,
EBX,
// //
ESP, ESP,
EBP, EBP,
@ -29,10 +29,27 @@ pub const Register = enum {
EDI, EDI,
}; };
pub const SegmentRegister = enum {
CS,
DS,
SS,
ES,
FS,
GS,
};
pub const Cpu = struct { pub const Cpu = struct {
registers: std.EnumArray(Register, u32), registers: std.EnumArray(Register, u32),
segmentRegisters: std.EnumArray(SegmentRegister, u16),
instruction_pointer: u32, //EIP 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),
};
} }
}; };

View file

@ -44,9 +44,18 @@ pub const Instruction = struct {
}; };
pub const Opcode = enum { pub const Opcode = enum {
/// Move family //
MovRegToRegMem_8 = 0x88, MovRegToRegMem_8 = 0x88,
MovRegToRegMem_16_32 = 0x89, MovRegToRegMem_16_32 = 0x89,
MovRegMemToMem_8 = 0x8A, 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,
}; };

View file

@ -16,9 +16,11 @@
const std = @import("std"); const std = @import("std");
const mem = @import("memory.zig"); const mem = @import("memory.zig");
const cpu_ = @import("cpu.zig");
pub fn main() !void { pub fn main() !void {
var memory = mem.Memory.init(); var memory = mem.Memory.init();
var cpu = cpu_.Cpu.init();
var input = std.io.getStdIn().reader(); var input = std.io.getStdIn().reader();
var output = std.io.getStdOut().writer(); var output = std.io.getStdOut().writer();
//Switch to new buffer //Switch to new buffer
@ -41,15 +43,15 @@ pub fn main() !void {
, .{}); , .{});
var buffer: [256]u8 = undefined; var buffer: [256]u8 = undefined;
while (true) { while (true) {
std.debug.print("> ", .{}); modeLine(&cpu, &memory);
const line = try input.readUntilDelimiterOrEof(&buffer, '\n'); const line = try input.readUntilDelimiterOrEof(&buffer, '\n');
const clean = std.mem.trim(u8, line.?, " \n\r"); const clean = std.mem.trim(u8, line.?, " \n\r");
var it = std.mem.splitSequence(u8, clean, " "); var it = std.mem.splitSequence(u8, clean, " ");
if (it.next()) |first_argument| { if (it.next()) |first_argument| {
if (std.mem.eql(u8, first_argument, "exit")) { if (std.mem.eql(u8, first_argument, "exit")) {
break; break;
} else if (std.mem.eql(u8, first_argument, "mem")) { } else if (std.mem.eql(u8, first_argument, "sr")) {
try handleMemoryCommand(&memory, &it); try handleSegmentRegisterCommand(&cpu, &it);
} }
} else { } else {
// noop // noop
@ -62,37 +64,50 @@ pub fn main() !void {
_ = try output.writeAll("\x1b[?25h"); _ = try output.writeAll("\x1b[?25h");
} }
fn handleMemoryCommand(memory: *mem.Memory, it: anytype) !void { fn modeLine(cpu: *cpu_.Cpu, memory: *mem.Memory) void {
if (it.next()) |next_argument| { _ = memory;
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( std.debug.print(
\\MEM @ {}: {}
\\ \\
, .{ addr, value }); \\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("> ", .{});
} }
} else if (std.mem.eql(u8, next_argument, "write")) {
const maybe_addr = it.next(); fn printSr(cpu: *cpu_.Cpu) void {
const maybe_value = it.next();
if (maybe_addr == null or maybe_value == null) {
std.debug.print( std.debug.print(
\\Invalid arguments. Usage: mem write <addr> <value> \\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 { } else {
const addr = try std.fmt.parseUnsigned(u8, maybe_addr.?, 10); printSr(cpu);
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 <addr>
\\ mem write <adrr> <value>
\\
, .{next_argument});
}
} }
} }