Add Segment Register command, add Modeline, &c
This commit is contained in:
parent
ef98f1e243
commit
8e8f85fc53
4 changed files with 85 additions and 41 deletions
|
@ -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]]
|
||||||
|
|
23
src/cpu.zig
23
src/cpu.zig
|
@ -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),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
85
src/main.zig
85
src/main.zig
|
@ -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")) {
|
std.debug.print(
|
||||||
if (it.next()) |address| {
|
\\
|
||||||
const addr = try std.fmt.parseUnsigned(u8, address, 10);
|
\\IP : {x:0>8}
|
||||||
const value = try memory.readByte(addr);
|
\\EAX: {x:0>8} EBX: {x:0>8} ECX: {x:0>8} EDX: {x:0>8}
|
||||||
std.debug.print(
|
\\ESP: {x:0>8} EBP: {x:0>8} ESI: {x:0>8} EDI: {x:0>8}
|
||||||
\\MEM @ {}: {}
|
\\
|
||||||
\\
|
, .{
|
||||||
, .{ addr, value });
|
cpu.instruction_pointer,
|
||||||
}
|
cpu.registers.get(.EAX),
|
||||||
} else if (std.mem.eql(u8, next_argument, "write")) {
|
cpu.registers.get(.EBX),
|
||||||
const maybe_addr = it.next();
|
cpu.registers.get(.ECX),
|
||||||
const maybe_value = it.next();
|
cpu.registers.get(.EDX),
|
||||||
if (maybe_addr == null or maybe_value == null) {
|
//
|
||||||
std.debug.print(
|
cpu.registers.get(.ESP),
|
||||||
\\Invalid arguments. Usage: mem write <addr> <value>
|
cpu.registers.get(.EBP),
|
||||||
\\
|
cpu.registers.get(.ESI),
|
||||||
, .{});
|
cpu.registers.get(.EDI),
|
||||||
} else {
|
});
|
||||||
const addr = try std.fmt.parseUnsigned(u8, maybe_addr.?, 10);
|
std.debug.print("> ", .{});
|
||||||
const value = try std.fmt.parseUnsigned(u8, maybe_value.?, 10);
|
}
|
||||||
_ = try memory.writeByte(addr, value);
|
|
||||||
}
|
fn printSr(cpu: *cpu_.Cpu) void {
|
||||||
} else {
|
std.debug.print(
|
||||||
std.debug.print(
|
\\Segment Registers:
|
||||||
\\Invalid argument '{s}'. Usage:
|
\\CS: {x:0>4} DS: {x:0>4} SS: {x:0>4}
|
||||||
\\ mem read <addr>
|
\\ES: {x:0>4} FS: {x:0>4} GS: {x:0>4}
|
||||||
\\ mem write <adrr> <value>
|
\\
|
||||||
\\
|
, .{
|
||||||
, .{next_argument});
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue