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:
#+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]]

View file

@ -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),
};
}
};

View file

@ -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,
};

View file

@ -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 <addr> <value>
\\
, .{});
} 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 <addr>
\\ mem write <adrr> <value>
\\
, .{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);
}
}