diff --git a/8086_sim/Makefile b/8086_sim/Makefile new file mode 100644 index 0000000..e9addcf --- /dev/null +++ b/8086_sim/Makefile @@ -0,0 +1,8 @@ +CC=clang++ +CFLAGS=-g -O0 -Wall -Wextra +LIBS=-Wl,-rpath,./lib -L./lib -lsim86 +SRC=*.cpp +OUT=sim86 + +all: + $(CC) $(CFLAGS) $(LIBS) $(SRC) -o $(OUT) diff --git a/8086_sim/include/aliases.h b/8086_sim/include/aliases.h new file mode 100644 index 0000000..68592a2 --- /dev/null +++ b/8086_sim/include/aliases.h @@ -0,0 +1,46 @@ +#ifndef ALIASES_H +#define ALIASES_H + +#include + +#ifndef u8 +#define u8 uint8_t +#endif // !u8 + +#ifndef u16 +#define u16 uint16_t +#endif // !u16 + +#ifndef u32 +#define u32 uint32_t +#endif // !u32 + +#ifndef u64 +#define u64 uint64_t +#endif // !u64 + +#ifndef i8 +#define i8 int8_t +#endif // !i8 + +#ifndef i16 +#define i16 int16_t +#endif // !i16 + +#ifndef i32 +#define i32 int32_t +#endif // !i32 + +#ifndef i64 +#define i64 int64_t +#endif // !i64 + +#ifndef f32 +#define f32 float +#endif // !f32 + +#ifndef f64 +#define f64 double +#endif // !f64 + +#endif // !ALIASES_H diff --git a/8086_sim/include/reg_access.h b/8086_sim/include/reg_access.h new file mode 100644 index 0000000..d6a3d1a --- /dev/null +++ b/8086_sim/include/reg_access.h @@ -0,0 +1,11 @@ +#ifndef REG_ACCESS_H +#define REG_ACCESS_H + +#include "aliases.h" +#include "sim86_instruction.h" + +void set_register(register_access reg, u16 new_value); +u16 get_register(register_access reg); +const char *get_register_name(register_access reg); + +#endif // !REG_ACCESS_H diff --git a/8086_sim/include/sim86.h b/8086_sim/include/sim86.h new file mode 100644 index 0000000..891194c --- /dev/null +++ b/8086_sim/include/sim86.h @@ -0,0 +1,54 @@ +/* ======================================================================== + + (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Please see https://computerenhance.com for more information + + ======================================================================== */ + +#ifndef SIM86_H +#define SIM86_H + +#ifndef u8 +typedef char unsigned u8; +#endif // !u8 + +#ifndef u16 +typedef short unsigned u16; +#endif // !u16 + +#ifndef u32 +typedef int unsigned u32; +#endif // !u32 + +#ifndef u64 +typedef long long unsigned u64; +#endif // u64 + +#ifndef s8 +typedef char s8; +#endif // !s8 + +#ifndef s16 +typedef short s16; +#endif // !s16 + +#ifndef s32 +typedef int s32; +#endif // !s32 + +#ifndef s64 +typedef long long s64; +#endif // !s64 + +typedef s32 b32; + +#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0])) + +static u32 const SIM86_VERSION = 3; + +#endif // !SIM86_H diff --git a/8086_sim/include/sim86_instruction.h b/8086_sim/include/sim86_instruction.h new file mode 100644 index 0000000..6de2c6e --- /dev/null +++ b/8086_sim/include/sim86_instruction.h @@ -0,0 +1,92 @@ +/* ======================================================================== + + (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Please see https://computerenhance.com for more information + + ======================================================================== */ + +#ifndef SIM86_INST_H +#define SIM86_INST_H + +#include "sim86.h" + +enum operation_type : u32 { + Op_None, + +#define INST(Mnemonic, ...) Op_##Mnemonic, +#define INSTALT(...) +#include "sim86_instruction_table.inl" + + Op_Count, +}; + +enum instruction_flag : u32 { + Inst_Lock = 0x1, + Inst_Rep = 0x2, + Inst_Segment = 0x4, + Inst_Wide = 0x8, + Inst_Far = 0x10, +}; + +struct register_access { + u32 Index; // Index in the register table + u32 Offset; // High vs Low bits + u32 Count; // How many bytes are accessed +}; + +struct effective_address_term { + register_access Register; + s32 Scale; +}; + +enum effective_address_flag : u32 { + Address_ExplicitSegment = 0x1, +}; +struct effective_address_expression { + effective_address_term Terms[2]; + u32 ExplicitSegment; + s32 Displacement; + u32 Flags; +}; + +enum immediate_flag : u32 { + Immediate_RelativeJumpDisplacement = 0x1, +}; +struct immediate { + s32 Value; + u32 Flags; +}; + +enum operand_type : u32 { + Operand_None, + Operand_Register, + Operand_Memory, + Operand_Immediate, +}; +struct instruction_operand { + operand_type Type; + union { + effective_address_expression Address; + register_access Register; + immediate Immediate; + }; +}; + +struct instruction { + u32 Address; + u32 Size; + + operation_type Op; + u32 Flags; + + instruction_operand Operands[2]; + + u32 SegmentOverride; +}; + +#endif // !SIM86_INST_H diff --git a/8086_sim/include/sim86_instruction_table.h b/8086_sim/include/sim86_instruction_table.h new file mode 100644 index 0000000..045e4b0 --- /dev/null +++ b/8086_sim/include/sim86_instruction_table.h @@ -0,0 +1,65 @@ +/* ======================================================================== + + (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Please see https://computerenhance.com for more information + + ======================================================================== */ + +#include "sim86.h" +#include "sim86_instruction.h" + +enum instruction_bits_usage : u8 { + Bits_End, // NOTE(casey): The 0 value, indicating the end of the instruction + // encoding array + + Bits_Literal, // NOTE(casey): These are opcode bits that identify instructions + + // NOTE(casey): These bits correspond directly to the 8086 instruction manual + Bits_D, + Bits_S, + Bits_W, + Bits_V, + Bits_Z, + Bits_MOD, + Bits_REG, + Bits_RM, + Bits_SR, + Bits_Disp, + Bits_Data, + + Bits_DispAlwaysW, // NOTE(casey): Tag for instructions where the displacement + // is always 16 bits + Bits_WMakesDataW, // NOTE(casey): Tag for instructions where SW=01 makes the + // data field become 16 bits + Bits_RMRegAlwaysW, // NOTE(casey): Tag for instructions where the register + // encoded in RM is always 16-bit width + Bits_RelJMPDisp, // NOTE(casey): Tag for instructions that require address + // adjustment to go through NASM properly + Bits_Far, // NOTE(casey): Tag for instructions that require a "far" keyword in + // their ASM to select the right opcode + + Bits_Count, +}; + +struct instruction_bits { + instruction_bits_usage Usage; + u8 BitCount; + u8 Shift; + u8 Value; +}; + +struct instruction_encoding { + operation_type Op; + instruction_bits Bits[16]; +}; + +struct instruction_table { + instruction_encoding *Encodings; + u32 EncodingCount; + u32 MaxInstructionByteCount; +}; diff --git a/8086_sim/include/sim86_instruction_table.inl b/8086_sim/include/sim86_instruction_table.inl new file mode 100644 index 0000000..1323b95 --- /dev/null +++ b/8086_sim/include/sim86_instruction_table.inl @@ -0,0 +1,250 @@ +/* ======================================================================== + + (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Please see https://computerenhance.com for more information + + ======================================================================== */ + +/* + NOTE(casey): This instruction table is a direct translation of table 4-12 in the Intel 8086 manual. + The macros are designed to allow direct transcription, without changing the order or manner + of specification in the table in any way. Additional "implicit" versions of the macros are provided + so that hard-coded fields can be supplied uniformly. + + The table is also designed to allow you to include it multiple times to "pull out" other things + from the table, such as opcode mnemonics as strings or enums, etc. +*/ + +#ifndef INST +#define INST(Mnemonic, Encoding, ...) {Op_##Mnemonic, Encoding, __VA_ARGS__}, +#endif + +#ifndef INSTALT +#define INSTALT INST +#endif + +#define B(Bits) {Bits_Literal, sizeof(#Bits)-1, 0, 0b##Bits} +#define D {Bits_D, 1} +#define S {Bits_S, 1} +#define W {Bits_W, 1} +#define V {Bits_V, 1} +#define Z {Bits_Z, 1} + +#define XXX {Bits_Data, 3, 0} +#define YYY {Bits_Data, 3, 3} +#define RM {Bits_RM, 3} +#define MOD {Bits_MOD, 2} +#define REG {Bits_REG, 3} +#define SR {Bits_SR, 2} + +#define ImpW(Value) {Bits_W, 0, 0, Value} +#define ImpREG(Value) {Bits_REG, 0, 0, Value} +#define ImpMOD(Value) {Bits_MOD, 0, 0, Value} +#define ImpRM(Value) {Bits_RM, 0, 0, Value} +#define ImpD(Value) {Bits_D, 0, 0, Value} +#define ImpS(Value) {Bits_S, 0, 0, Value} + +#define DISP {Bits_Disp, 0, 0, 0} +#define ADDR {Bits_Disp, 0, 0, 0}, {Bits_DispAlwaysW, 0, 0, 1} +#define DATA {Bits_Data, 0, 0, 0} +#define DATA_IF_W {Bits_WMakesDataW, 0, 0, 1} +#define Flags(F) {F, 0, 0, 1} + +INST(mov, {B(100010), D, W, MOD, REG, RM}) +INSTALT(mov, {B(1100011), W, MOD, B(000), RM, DATA, DATA_IF_W, ImpD(0)}) +INSTALT(mov, {B(1011), W, REG, DATA, DATA_IF_W, ImpD(1)}) +INSTALT(mov, {B(1010000), W, ADDR, ImpREG(0), ImpMOD(0), ImpRM(0b110), ImpD(1)}) +INSTALT(mov, {B(1010001), W, ADDR, ImpREG(0), ImpMOD(0), ImpRM(0b110), ImpD(0)}) +INSTALT(mov, {B(100011), D, B(0), MOD, B(0), SR, RM, ImpW(1)}) // NOTE(casey): This collapses 2 entries in the 8086 table by adding an explicit D bit + +INST(push, {B(11111111), MOD, B(110), RM, ImpW(1)}) +INSTALT(push, {B(01010), REG, ImpW(1)}) +INSTALT(push, {B(000), SR, B(110), ImpW(1)}) + +INST(pop, {B(10001111), MOD, B(000), RM, ImpW(1)}) +INSTALT(pop, {B(01011), REG, ImpW(1)}) +INSTALT(pop, {B(000), SR, B(111), ImpW(1)}) + +INST(xchg, {B(1000011), W, MOD, REG, RM, ImpD(1)}) +INSTALT(xchg, {B(10010), REG, ImpMOD(0b11), ImpW(1), ImpRM(0)}) + +INST(in, {B(1110010), W, DATA, ImpREG(0), ImpD(1)}) +INSTALT(in, {B(1110110), W, ImpREG(0), ImpD(1), ImpMOD(0b11), ImpRM(2), Flags(Bits_RMRegAlwaysW)}) +INST(out, {B(1110011), W, DATA, ImpREG(0), ImpD(0)}) +INSTALT(out, {B(1110111), W, ImpREG(0), ImpD(0), ImpMOD(0b11), ImpRM(2), Flags(Bits_RMRegAlwaysW)}) + +INST(xlat, {B(11010111)}) +INST(lea, {B(10001101), MOD, REG, RM, ImpD(1), ImpW(1)}) +INST(lds, {B(11000101), MOD, REG, RM, ImpD(1), ImpW(1)}) +INST(les, {B(11000100), MOD, REG, RM, ImpD(1), ImpW(1)}) +INST(lahf, {B(10011111)}) +INST(sahf, {B(10011110)}) +INST(pushf, {B(10011100)}) +INST(popf, {B(10011101)}) + +INST(add, {B(000000), D, W, MOD, REG, RM}) +INSTALT(add, {B(100000), S, W, MOD, B(000), RM, DATA, DATA_IF_W}) +INSTALT(add, {B(0000010), W, DATA, DATA_IF_W, ImpREG(0), ImpD(1)}) + +INST(adc, {B(000100), D, W, MOD, REG, RM}) +INSTALT(adc, {B(100000), S, W, MOD, B(010), RM, DATA, DATA_IF_W}) +INSTALT(adc, {B(0001010), W, DATA, DATA_IF_W, ImpREG(0), ImpD(1)}) + +INST(inc, {B(1111111), W, MOD, B(000), RM}) +INSTALT(inc, {B(01000), REG, ImpW(1)}) + +INST(aaa, {B(00110111)}) +INST(daa, {B(00100111)}) + +INST(sub, {B(001010), D, W, MOD, REG, RM}) +INSTALT(sub, {B(100000), S, W, MOD, B(101), RM, DATA, DATA_IF_W}) +INSTALT(sub, {B(0010110), W, DATA, DATA_IF_W, ImpREG(0), ImpD(1)}) + +INST(sbb, {B(000110), D, W, MOD, REG, RM}) +INSTALT(sbb, {B(100000), S, W, MOD, B(011), RM, DATA, DATA_IF_W}) +INSTALT(sbb, {B(0001110), W, DATA, DATA_IF_W, ImpREG(0), ImpD(1)}) + +INST(dec, {B(1111111), W, MOD, B(001), RM}) +INSTALT(dec, {B(01001), REG, ImpW(1)}) + +INST(neg, {B(1111011), W, MOD, B(011), RM}) + +INST(cmp, {B(001110), D, W, MOD, REG, RM}) +INSTALT(cmp, {B(100000), S, W, MOD, B(111), RM, DATA, DATA_IF_W}) +INSTALT(cmp, {B(0011110), W, DATA, DATA_IF_W, ImpREG(0), ImpD(1)}) // NOTE(casey): The manual table suggests this data is only 8-bit, but wouldn't it be 16 as well? + +INST(aas, {B(00111111)}) +INST(das, {B(00101111)}) +INST(mul, {B(1111011), W, MOD, B(100), RM, ImpS(0)}) +INST(imul, {B(1111011), W, MOD, B(101), RM, ImpS(1)}) +INST(aam, {B(11010100), B(00001010)}) // NOTE(casey): The manual says this has a DISP... but how could it? What for?? +INST(div, {B(1111011), W, MOD, B(110), RM, ImpS(0)}) +INST(idiv, {B(1111011), W, MOD, B(111), RM, ImpS(1)}) +INST(aad, {B(11010101), B(00001010)}) +INST(cbw, {B(10011000)}) +INST(cwd, {B(10011001)}) + +INST(not, {B(1111011), W, MOD, B(010), RM}) +INST(shl, {B(110100), V, W, MOD, B(100), RM}) +INST(shr, {B(110100), V, W, MOD, B(101), RM}) +INST(sar, {B(110100), V, W, MOD, B(111), RM}) +INST(rol, {B(110100), V, W, MOD, B(000), RM}) +INST(ror, {B(110100), V, W, MOD, B(001), RM}) +INST(rcl, {B(110100), V, W, MOD, B(010), RM}) +INST(rcr, {B(110100), V, W, MOD, B(011), RM}) + +INST(and, {B(001000), D, W, MOD, REG, RM}) +INSTALT(and, {B(1000000), W, MOD, B(100), RM, DATA, DATA_IF_W}) +INSTALT(and, {B(0010010), W, DATA, DATA_IF_W, ImpREG(0), ImpD(1)}) + +INST(test, {B(1000010), W, MOD, REG, RM}) // NOTE(casey): The manual suggests there is a D flag here, but it doesn't appear to be true (it would conflict with xchg if it did) +INSTALT(test, {B(1111011), W, MOD, B(000), RM, DATA, DATA_IF_W}) +INSTALT(test, {B(1010100), W, DATA, DATA_IF_W, ImpREG(0), ImpD(1)}) // NOTE(casey): The manual table suggests this data is only 8-bit, but it seems like it could be 16 too? + +INST(or, {B(000010), D, W, MOD, REG, RM}) +INSTALT(or, {B(1000000), W, MOD, B(001), RM, DATA, DATA_IF_W}) +INSTALT(or, {B(0000110), W, DATA, DATA_IF_W, ImpREG(0), ImpD(1)}) + +INST(xor, {B(001100), D, W, MOD, REG, RM}) +INSTALT(xor, {B(1000000), W, MOD, B(110), RM, DATA, DATA_IF_W}) // NOTE(casey): The manual has conflicting information about this encoding, but I believe this is the correct binary pattern. +INSTALT(xor, {B(0011010), W, DATA, DATA_IF_W, ImpREG(0), ImpD(1)}) + +INST(rep, {B(1111001), Z}) +INST(movs, {B(1010010), W}) +INST(cmps, {B(1010011), W}) +INST(scas, {B(1010111), W}) +INST(lods, {B(1010110), W}) +INST(stos, {B(1010101), W}) + +INST(call, {B(11101000), ADDR, Flags(Bits_RelJMPDisp)}) +INSTALT(call, {B(11111111), MOD, B(010), RM, ImpW(1)}) +INSTALT(call, {B(10011010), ADDR, DATA, DATA_IF_W, ImpW(1)}) +INSTALT(call, {B(11111111), MOD, B(011), RM, ImpW(1), Flags(Bits_Far)}) + +INST(jmp, {B(11101001), ADDR, Flags(Bits_RelJMPDisp)}) +INSTALT(jmp, {B(11101011), DISP, Flags(Bits_RelJMPDisp)}) +INSTALT(jmp, {B(11111111), MOD, B(100), RM, ImpW(1)}) +INSTALT(jmp, {B(11101010), ADDR, DATA, DATA_IF_W, ImpW(1)}) +INSTALT(jmp, {B(11111111), MOD, B(101), RM, ImpW(1), Flags(Bits_Far)}) + +// NOTE(casey): The actual Intel manual does not distinguish mnemonics RET and RETF, +// but NASM needs this to reassemble properly, so we do. +INST(ret, {B(11000011)}) +INSTALT(ret, {B(11000010), DATA, DATA_IF_W, ImpW(1)}) +INST(retf, {B(11001011)}) +INSTALT(retf, {B(11001010), DATA, DATA_IF_W, ImpW(1)}) + +INST(je, {B(01110100), DISP, Flags(Bits_RelJMPDisp)}) +INST(jl, {B(01111100), DISP, Flags(Bits_RelJMPDisp)}) +INST(jle, {B(01111110), DISP, Flags(Bits_RelJMPDisp)}) +INST(jb, {B(01110010), DISP, Flags(Bits_RelJMPDisp)}) +INST(jbe, {B(01110110), DISP, Flags(Bits_RelJMPDisp)}) +INST(jp, {B(01111010), DISP, Flags(Bits_RelJMPDisp)}) +INST(jo, {B(01110000), DISP, Flags(Bits_RelJMPDisp)}) +INST(js, {B(01111000), DISP, Flags(Bits_RelJMPDisp)}) +INST(jne, {B(01110101), DISP, Flags(Bits_RelJMPDisp)}) +INST(jnl, {B(01111101), DISP, Flags(Bits_RelJMPDisp)}) +INST(jg, {B(01111111), DISP, Flags(Bits_RelJMPDisp)}) +INST(jnb, {B(01110011), DISP, Flags(Bits_RelJMPDisp)}) +INST(ja, {B(01110111), DISP, Flags(Bits_RelJMPDisp)}) +INST(jnp, {B(01111011), DISP, Flags(Bits_RelJMPDisp)}) +INST(jno, {B(01110001), DISP, Flags(Bits_RelJMPDisp)}) +INST(jns, {B(01111001), DISP, Flags(Bits_RelJMPDisp)}) +INST(loop, {B(11100010), DISP, Flags(Bits_RelJMPDisp)}) +INST(loopz, {B(11100001), DISP, Flags(Bits_RelJMPDisp)}) +INST(loopnz, {B(11100000), DISP, Flags(Bits_RelJMPDisp)}) +INST(jcxz, {B(11100011), DISP, Flags(Bits_RelJMPDisp)}) + +INST(int, {B(11001101), DATA}) +INST(int3, {B(11001100)}) // TODO(casey): The manual does not suggest that this intrinsic has an "int3" mnemonic, but NASM thinks so + +INST(into, {B(11001110)}) +INST(iret, {B(11001111)}) + +INST(clc, {B(11111000)}) +INST(cmc, {B(11110101)}) +INST(stc, {B(11111001)}) +INST(cld, {B(11111100)}) +INST(std, {B(11111101)}) +INST(cli, {B(11111010)}) +INST(sti, {B(11111011)}) +INST(hlt, {B(11110100)}) +INST(wait, {B(10011011)}) +INST(esc, {B(11011), XXX, MOD, YYY, RM}) +INST(lock, {B(11110000)}) +INST(segment, {B(001), SR, B(110)}) + +#undef INST +#undef INSTALT + +#undef B +#undef D +#undef S +#undef W +#undef V +#undef Z + +#undef XXX +#undef YYY +#undef RM +#undef MOD +#undef REG +#undef SR + +#undef ImpW +#undef ImpREG +#undef ImpMOD +#undef ImpRM +#undef ImpD +#undef ImpS + +#undef DISP +#undef ADDR +#undef DATA +#undef DATA_IF_W +#undef Flags diff --git a/8086_sim/include/sim86_lib.h b/8086_sim/include/sim86_lib.h new file mode 100644 index 0000000..0ce1fe6 --- /dev/null +++ b/8086_sim/include/sim86_lib.h @@ -0,0 +1,21 @@ +/* ======================================================================== + + (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Please see https://computerenhance.com for more information + + ======================================================================== */ + +#include "sim86.h" +#include "sim86_instruction.h" +#include "sim86_instruction_table.h" + +extern "C" u32 Sim86_GetVersion(void); +extern "C" void Sim86_Decode8086Instruction(u32 SourceSize, u8 *Source, instruction *Dest); +extern "C" char const *Sim86_RegisterNameFromOperand(register_access *RegAccess); +extern "C" char const *Sim86_MnemonicFromOperationType(operation_type Type); +extern "C" void Sim86_Get8086InstructionTable(instruction_table *Dest); \ No newline at end of file diff --git a/8086_sim/lib/libsim86.so b/8086_sim/lib/libsim86.so new file mode 100644 index 0000000..47e0f28 Binary files /dev/null and b/8086_sim/lib/libsim86.so differ diff --git a/8086_sim/listing_0043_immediate_movs b/8086_sim/listing_0043_immediate_movs new file mode 100644 index 0000000..a965538 Binary files /dev/null and b/8086_sim/listing_0043_immediate_movs differ diff --git a/8086_sim/listing_0043_immediate_movs.asm b/8086_sim/listing_0043_immediate_movs.asm new file mode 100644 index 0000000..475afaf --- /dev/null +++ b/8086_sim/listing_0043_immediate_movs.asm @@ -0,0 +1,27 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 43 +; ======================================================================== + +bits 16 + +mov ax, 1 +mov bx, 2 +mov cx, 3 +mov dx, 4 + +mov sp, 5 +mov bp, 6 +mov si, 7 +mov di, 8 diff --git a/8086_sim/listing_0044_register_movs b/8086_sim/listing_0044_register_movs new file mode 100644 index 0000000..346ff45 Binary files /dev/null and b/8086_sim/listing_0044_register_movs differ diff --git a/8086_sim/listing_0044_register_movs.asm b/8086_sim/listing_0044_register_movs.asm new file mode 100644 index 0000000..58988fe --- /dev/null +++ b/8086_sim/listing_0044_register_movs.asm @@ -0,0 +1,32 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 44 +; ======================================================================== + +bits 16 + +mov ax, 1 +mov bx, 2 +mov cx, 3 +mov dx, 4 + +mov sp, ax +mov bp, bx +mov si, cx +mov di, dx + +mov dx, sp +mov cx, bp +mov bx, si +mov ax, di diff --git a/8086_sim/listing_0045_challenge_register_movs b/8086_sim/listing_0045_challenge_register_movs new file mode 100644 index 0000000..40bf309 --- /dev/null +++ b/8086_sim/listing_0045_challenge_register_movs @@ -0,0 +1 @@ +¸""»DD¹ffºˆˆŽÐŽÛŽÁ \ No newline at end of file diff --git a/8086_sim/listing_0045_challenge_register_movs.asm b/8086_sim/listing_0045_challenge_register_movs.asm new file mode 100644 index 0000000..9e25fda --- /dev/null +++ b/8086_sim/listing_0045_challenge_register_movs.asm @@ -0,0 +1,43 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 45 +; ======================================================================== + +bits 16 + +mov ax, 0x2222 +mov bx, 0x4444 +mov cx, 0x6666 +mov dx, 0x8888 + +mov ss, ax +mov ds, bx +mov es, cx + +mov al, 0x11 +mov bh, 0x33 +mov cl, 0x55 +mov dh, 0x77 + +mov ah, bl +mov cl, dh + +mov ss, ax +mov ds, bx +mov es, cx + +mov sp, ss +mov bp, ds +mov si, es +mov di, dx diff --git a/8086_sim/reg_access.cpp b/8086_sim/reg_access.cpp new file mode 100644 index 0000000..113953a --- /dev/null +++ b/8086_sim/reg_access.cpp @@ -0,0 +1,52 @@ +#include "include/reg_access.h" +#include "include/aliases.h" +#include + +#define REGISTER_COUNT 13 + +static u16 registers[REGISTER_COUNT] = {0}; + +void set_register(register_access reg, u16 new_value) { + if (reg.Count == 2) { + registers[reg.Index] = new_value; + return; + } + + u16 shift = (u16)(reg.Offset) * (u16)sizeof(u8); + u16 mask = 0xff00; + + registers[reg.Index] &= (mask >> shift); + registers[reg.Index] |= (new_value << shift); +} + +u16 get_register(register_access reg) { + if (reg.Count == 2) { + return registers[reg.Index]; + } + + // TODO (Abdelrahman): Implement this + return 0; +} + +const char *get_register_name(register_access reg) { + // clang-format off + static const char *register_names[REGISTER_COUNT][3] = { + {"NONE", "NONE", "NONE"}, + {"al", "ah", "ax"}, + {"bl", "bh", "bx"}, + {"cl", "ch", "cx"}, + {"dl", "dh", "dx"}, + {"sp", "sp", "sp"}, + {"bp", "bp", "bp"}, + {"si", "si", "si"}, + {"di", "di", "di"}, + {"es", "es", "es"}, + {"cs", "cs", "cs"}, + {"ss", "ss", "ss"}, + {"ds", "ds", "ds"}, + }; + // clang-format on + + return register_names[reg.Index] + [(reg.Count == 2) ? 2 : (reg.Offset & reg.Count)]; +} diff --git a/8086_sim/sim86 b/8086_sim/sim86 new file mode 100644 index 0000000..30946de Binary files /dev/null and b/8086_sim/sim86 differ diff --git a/8086_sim/sim86.cpp b/8086_sim/sim86.cpp new file mode 100644 index 0000000..9229eec --- /dev/null +++ b/8086_sim/sim86.cpp @@ -0,0 +1,97 @@ +#include "include/aliases.h" +#include "include/reg_access.h" +#include "include/sim86_lib.h" +#include +#include +#include + +void decode_operand(instruction_operand operand); +void mov_to_register(const register_access ®, + const instruction_operand &source); + +int main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: sim86 BINARY_FILE\n"); + return 1; + } + + const char *filename = argv[1]; + + printf("Filename: %s\n", filename); + + FILE *fp = fopen(filename, "rb"); + if (!fp) { + printf("Failed to open file %s\n", filename); + } + + fseek(fp, 0, SEEK_END); + + u32 size = ftell(fp); + + fseek(fp, 0, SEEK_SET); + + u8 buffer[size + 1]; + memset((void *)buffer, 0, size + 1); + + fread((void *)buffer, sizeof(u8), size, fp); + + fclose(fp); + + instruction_table table; + Sim86_Get8086InstructionTable(&table); + + u32 offset = 0; + + while (offset < size) { + instruction decoded; + Sim86_Decode8086Instruction(size - offset, buffer + offset, &decoded); + + if (decoded.Op) { + offset += decoded.Size; + + if (decoded.Op == Op_mov) { + instruction_operand dest = decoded.Operands[0]; + instruction_operand source = decoded.Operands[1]; + + if (dest.Type == Operand_Register) { + mov_to_register(dest.Register, source); + printf("%s: 0x%04x\n", get_register_name(dest.Register), + get_register(dest.Register)); + } + } + } + } + + return 0; +} + +void decode_operand(instruction_operand operand) { + switch (operand.Type) { + case Operand_Register: + printf("Register operand: %d, %d, %d\n", operand.Register.Index, + operand.Register.Offset, operand.Register.Count); + break; + case Operand_Memory: + // printf("Memory operand\n"); + break; + case Operand_Immediate: + // printf("Immediate operand\n"); + break; + default: + break; + } +} + +void mov_to_register(const register_access ®, + const instruction_operand &source) { + switch (source.Type) { + case Operand_Immediate: + set_register(reg, source.Immediate.Value); + break; + case Operand_Register: + set_register(reg, get_register(source.Register)); + break; + default: + break; + } +} diff --git a/8086_sim/test b/8086_sim/test new file mode 100644 index 0000000..bcf8407 Binary files /dev/null and b/8086_sim/test differ diff --git a/8086_sim/test.asm b/8086_sim/test.asm new file mode 100644 index 0000000..f2c7474 --- /dev/null +++ b/8086_sim/test.asm @@ -0,0 +1,33 @@ +bits 16 + +mov al, 0 +mov ah, 0 +mov ax, 0 + +mov bl, 0 +mov bh, 0 +mov bx, 0 + +mov cl, 0 +mov ch, 0 +mov cx, 0 + +mov dl, 0 +mov dh, 0 +mov dx, 0 + +mov sp, 0 + +mov bp, 0 + +mov si, 0 + +mov di, 0 + +mov es, ax + +mov cs, ax + +mov ss, ax + +mov ds, ax