diff options
Diffstat (limited to 'src/sim86/sim86.cpp')
| -rw-r--r-- | src/sim86/sim86.cpp | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/src/sim86/sim86.cpp b/src/sim86/sim86.cpp new file mode 100644 index 0000000..7c444bd --- /dev/null +++ b/src/sim86/sim86.cpp @@ -0,0 +1,535 @@ +#include <stdio.h> +#include <string.h> + +#include "./libs/reference_decoder/sim86_lib.cpp" + +#include "sim86.h" +#include "clocks_table.inl" +#include "generated/generated.cpp" + +global_variable u8 GlobalMemory[1*1024*1024] = {}; + +internal void +SetOrUnsetFlag(u32 *FlagsRegister, b32 Condition, flags_8086 Flag) +{ + if(Condition) + { + *FlagsRegister |= Flag; + } + else + { + *FlagsRegister &= (~Flag); + } +} + +internal u32 +FlagsToString(char *Buffer, u32 Flags) +{ + u32 Length = 0; + + for(s32 MappingIndex = 0; + MappingIndex < flags_8086_strings_count; + MappingIndex++) + { + u8 Char = flags_8086_strings[MappingIndex][0]; + b32 IsBitSet = (Flags & 1); + Flags >>= 1; + if(IsBitSet) + { + Buffer[Length++] = Char; + } + } + + return Length; +} + +// Sets flags by checking the destination value of the register. +internal void +FlagsFromValue(u32 *FlagsRegister, u32 InstructionFlags, s32 Value) +{ + u32 OldFlagsRegister = *FlagsRegister; + + u32 SignMask = (1 << ((InstructionFlags & Inst_Wide) ? 15 : 7)); + SetOrUnsetFlag(FlagsRegister, (Value & SignMask), Flag_Sign); + SetOrUnsetFlag(FlagsRegister, (Value == 0), Flag_Zero); + + // NOTE(luca): Parity flag is set when in lower 8 bits have an even number of set bits. + u32 OneBitsCount = 0; + for(u32 BitsIndex = 0; + BitsIndex < 8; + BitsIndex++) + { + OneBitsCount += (Value & 1); + Value >>= 1; + } + SetOrUnsetFlag(FlagsRegister, (!(OneBitsCount & 1)), Flag_Parity); + + // TODO(luca): Overflow flag + // Were we adding positive numbers but produced a negative number? + + // TODO(luca): Carry flag + // When twot numbers are added and the 17th bit would be set? + + // TODO(luca): Auxiliary carry flag + // Carry for bottom 8 bits + if(*FlagsRegister != OldFlagsRegister) + { + char OldFlagsString[ArrayCount(flags_8086_strings)] = {}; + char FlagsString[ArrayCount(flags_8086_strings)] = {}; + FlagsToString(OldFlagsString, OldFlagsRegister); + FlagsToString(FlagsString, *FlagsRegister); + + printf(" flags:%s->%s", OldFlagsString, FlagsString); + } +} + +s32 GetCompleteDisplacement(s32 *Registers, instruction_operand *Operand) +{ + s32 CompleteDisplacement = Operand->Address.Displacement; + + u32 Count = Operand->Address.Terms[0].Register.Count; + u32 Mask = ((u32)((-1)) >> (16 + (16 - Count*8))); + CompleteDisplacement += + (Registers[Operand->Address.Terms[0].Register.Index] & Mask) + + (Registers[Operand->Address.Terms[1].Register.Index] & Mask); + + return CompleteDisplacement; +} + +internal s32 * +OperandToValue(s32 *Registers, u8 *Memory, instruction_operand *Operand) +{ + s32 *Result = 0; + + if(0) {} + else if(Operand->Type == Operand_Register) + { + Result = Registers + Operand->Register.Index; + } + else if(Operand->Type == Operand_Memory) + { + s32 CompleteDisplacement = GetCompleteDisplacement(Registers, Operand); + Result = (s32 *)((u8 *)Memory + CompleteDisplacement); + } + else if(Operand->Type == Operand_Immediate) + { + Result = &Operand->Immediate.Value; + } + else if(Operand->Type != Operand_None) + { + Assert(0); + } + + return Result; +} + +b32 IsAccumulator(instruction_operand *Operand) +{ + b32 Result = ((Operand->Type == Operand_Register) && + (Operand->Register.Index == Register_a)); + return Result; +} + +b32 IsMatchingOp(instruction_operand *Operand, instruction_clocks_operand_type Type) +{ + b32 Matching = false; + + Matching = Matching || (Type == InstructionClocksOperand_Memory && Operand->Type == Operand_Memory); + Matching = Matching || (Type == InstructionClocksOperand_Register && Operand->Type == Operand_Register); + Matching = Matching || (Type == InstructionClocksOperand_Accumulator && IsAccumulator(Operand)); + Matching = Matching || (Type == InstructionClocksOperand_Immediate && Operand->Type == Operand_Immediate); + + return Matching; +} + +internal void +Run8086(psize MemorySize, u8 *Memory) +{ + s32 Registers[Register_count] = {}; + u32 FlagsRegister = 0; + u32 IPRegister = 0; + u32 ElapsedClocks = 0; + + while(IPRegister < MemorySize) + { + instruction Decoded; + Sim86_Decode8086Instruction(MemorySize - IPRegister, Memory + IPRegister, &Decoded); + if(Decoded.Op) + { + u32 OldIPRegister = IPRegister; + +#if SIM86_INTERNAL + printf("%s ;", Sim86_MnemonicFromOperationType(Decoded.Op)); +#endif + + instruction_operand *DestinationOperand = Decoded.Operands + 0; + instruction_operand *SourceOperand = Decoded.Operands + 1; + + u32 AddedClocks = 0; + for(u32 ClocksIndex = 0; + ClocksIndex < ArrayCount(ClocksTable); + ClocksIndex++) + { + instruction_clocks *Clocks = ClocksTable + ClocksIndex; + + b32 Matching = Decoded.Op == Clocks->Op; + Matching = Matching && IsMatchingOp(DestinationOperand, Clocks->Operands[0]); + Matching = Matching && IsMatchingOp(SourceOperand, Clocks->Operands[1]); + if(Matching) + { + AddedClocks += Clocks->Clocks; + + if(Clocks->EffectiveAddress) + { + instruction_operand *MemoryOperand = ((DestinationOperand->Type == Operand_Memory) ? DestinationOperand : SourceOperand); + u32 FirstIndex = MemoryOperand->Address.Terms[0].Register.Index; + u32 SecondIndex = MemoryOperand->Address.Terms[1].Register.Index; + + // Only displacement + if(FirstIndex == 0 && SecondIndex == 0) + { + AddedClocks += 6; + } + // Base or index + else if(FirstIndex == 0 || SecondIndex == 0) + { + // Base or index only + if(MemoryOperand->Address.Displacement == 0) + { + AddedClocks += 5; + } + // Base or index + displacement + else + { + AddedClocks += 9; + } + } + // Base + index + else if(MemoryOperand->Address.Displacement == 0) + { + /* + bp+di bx+si 7 + bp+si bx+di 8 + */ + if((FirstIndex == Register_bp && SecondIndex == Register_di) || + (FirstIndex == Register_b && SecondIndex == Register_si)) + { + AddedClocks += 7; + } + else + { + AddedClocks += 8; + } + } + // Base + index + displacement + else + { + /* + bp+di bx+si 11 + bp+si bx+di 12 + */ + if((FirstIndex == Register_bp && SecondIndex == Register_di) || + (FirstIndex == Register_b && SecondIndex == Register_si)) + { + AddedClocks += 11; + } + else + { + AddedClocks += 12; + } + } + + } + + // Add transfer penalty + if(Clocks->Transfers && (Decoded.Flags & Inst_Wide)) + { + instruction_operand *MemoryOperand = ((DestinationOperand->Type == Operand_Memory) ? DestinationOperand : SourceOperand); + s32 Displacement = GetCompleteDisplacement(Registers, MemoryOperand); + if(Displacement & 1) + { + AddedClocks += 4*Clocks->Transfers; + } + } + + break; + } + } + +#if 0 + Assert(AddedClocks); +#endif + + ElapsedClocks += AddedClocks; + printf(" clocks: +%d = %d", AddedClocks, ElapsedClocks); + + s32 *Destination = OperandToValue(Registers, Memory, DestinationOperand); + s32 *Source = OperandToValue(Registers, Memory, SourceOperand); + + if(0) {} + else if(Decoded.Op == Op_int3) + { + Assert(0); + } + else if(Decoded.Op == Op_mov) + { + s32 Old = *Destination; + if(Decoded.Flags & Inst_Wide) + { + *(u16 *)Destination = *(u16 *)Source; + } + else + { + Assert((SourceOperand->Type == Operand_Immediate || + SourceOperand->Type == Operand_Memory) && + (SourceOperand->Register.Offset == 0)); + Assert((DestinationOperand->Type == Operand_Immediate || DestinationOperand->Type == Operand_Memory) && (DestinationOperand->Register.Offset == 0)); + + u8 *SourceByte = (u8 *)Source + SourceOperand->Register.Offset; + u8 *DestByte = (u8 *)Destination + DestinationOperand->Register.Offset; + + *DestByte = *SourceByte; + } + +#if SIM86_INTERNAL + if(DestinationOperand->Type == Operand_Register) + { + printf(" %s:0x%x->0x%x", Sim86_RegisterNameFromOperand(&DestinationOperand->Register), + Old, *Destination); + } +#endif + } + else if(Decoded.Op == Op_ret) + { + printf("\n"); + printf("STOPONRET: Return encountered at address %d.\n", IPRegister); + + break; + } + else if(Decoded.Op == Op_inc) + { + Assert(DestinationOperand->Type == Operand_Register); + Assert(SourceOperand->Type == Operand_None); + *Destination += 1; + } + else if(Decoded.Op == Op_test) + { + + Assert(DestinationOperand->Type == Operand_Register); + Assert(SourceOperand->Type == Operand_Register || SourceOperand->Type == Operand_Immediate); + + s32 Value =((Decoded.Flags & Inst_Wide) ? + (u16)((u16)*Destination & ((u16)*Source)) : + (u8)((u8)*Destination & ((u8)*Source))); + FlagsFromValue(&FlagsRegister, Decoded.Flags, Value); + } + else if(Decoded.Op == Op_xor) + { + + Assert(DestinationOperand->Type == Operand_Register); + Assert(SourceOperand->Type == Operand_Register || SourceOperand->Type == Operand_Immediate); + + s32 Value =((Decoded.Flags & Inst_Wide) ? + (u16)((u16)*Destination ^ ((u16)*Source)) : + (u8)((u8)*Destination ^ ((u8)*Source))); + FlagsFromValue(&FlagsRegister, Decoded.Flags, Value); + *Destination = Value; + } + else if(Decoded.Op == Op_cmp) + { + Assert(DestinationOperand->Type == Operand_Register); + Assert(SourceOperand->Type == Operand_Register || SourceOperand->Type == Operand_Immediate); + + s32 Value = ((Decoded.Flags & Inst_Wide) ? + (u16)((u16)*Destination - ((u16)*Source)) : + (u8)((u8)*Destination - ((u8)*Source))); + + FlagsFromValue(&FlagsRegister, Decoded.Flags, Value); + } + else if(Decoded.Op == Op_sub) + { + Assert(DestinationOperand->Type == Operand_Register); + Assert(SourceOperand->Type == Operand_Register || SourceOperand->Type == Operand_Immediate); + + s32 Old = *Destination; + *Destination = ((Decoded.Flags & Inst_Wide) ? + (u16)((u16)*Destination - ((u16)*Source)) : + (u8)((u8)*Destination - ((u8)*Source))); + + printf(" %s:0x%x->0x%x", + Sim86_RegisterNameFromOperand(&DestinationOperand->Register), + Old, *Destination); + + FlagsFromValue(&FlagsRegister, Decoded.Flags, *Destination); + + } + else if(Decoded.Op == Op_add) + { + s32 Old = *Destination; + + *Destination = ((Decoded.Flags & Inst_Wide) ? + (u16)((u16)*Destination + ((u16)*Source)) : + (u8)((u8)*Destination + ((u8)*Source))); + + printf(" %s:0x%x->0x%x", + Sim86_RegisterNameFromOperand(&DestinationOperand->Register), + Old, *Destination); + + FlagsFromValue(&FlagsRegister, Decoded.Flags, *Destination); + } + else if(Decoded.Op == Op_jne) + { + if(!(FlagsRegister & Flag_Zero)) + { + IPRegister += *Destination; + } + } + else if(Decoded.Op == Op_je) + { + if((FlagsRegister & Flag_Zero)) + { + IPRegister += *Destination; + } + } + else + { + Assert(0 && "Op not implemented yet."); + } + + IPRegister += Decoded.Size; + +#if SIM86_INTERNAL + printf(" ip:0x%x->0x%x", OldIPRegister, IPRegister); +#endif + + } + else + { + printf("Unrecognized instruction\n"); + break; + } + +#if SIM86_INTERNAL + printf("\n"); +#endif + + } + + printf("\nFinal registers:\n"); + for(u32 RegisterIndex = Register_a; + RegisterIndex < Register_ds + 1; + RegisterIndex++) + { + register_access Register = {}; + Register.Index = RegisterIndex; + Register.Offset = 0; + Register.Count = 2; + + u32 Value = Registers[RegisterIndex]; + if(Value > 0) + { + printf(" %s: 0x%0x (%d)\n", + Sim86_RegisterNameFromOperand(&Register), + Value, Value); + } + } + printf(" ip: 0x%04x (%d)\n", IPRegister, IPRegister); + + if(FlagsRegister) + { + char FlagsString[ArrayCount(flags_8086_strings)] = {}; + FlagsToString(FlagsString, FlagsRegister); + printf(" flags: %s\n", FlagsString); + } +} + +void PrintUsage(char *ExePath) +{ + printf("usage: %s [-exec] <assembly>\n", ExePath); +} + +int main(int ArgsCount, char *Args[]) +{ + u32 Version = Sim86_GetVersion(); + +#if SIM86_INTERNAL + printf("Sim86 Version: %u (expected %u)\n", Version, SIM86_VERSION); +#endif + + if(Version != SIM86_VERSION) + { + printf("ERROR: Header file version doesn't match DLL.\n"); + return -1; + } + + instruction_table Table; + Sim86_Get8086InstructionTable(&Table); + +#if SIM86_INTERNAL + printf("8086 Instruction Instruction Encoding Count: %u\n", Table.EncodingCount); +#endif + + // print (default) + // -exec (also execute the disassembled instructinos) + + b32 Execute = false; + b32 Dump = false; + char *FileName = 0; + for(s32 ArgsIndex = 1; + ArgsIndex < ArgsCount; + ArgsIndex++) + { + char *Command = Args[ArgsIndex]; + if(0) {} + else if(!strcmp(Command, "-exec")) + { + Execute = true; + } + else if(!strcmp(Command, "-dump")) + { + Dump = true; + } + else + { + FileName = Command; + } + } + + if(FileName) + { + FILE *File = fopen(FileName, "rb"); + if(File) + { + psize BytesWritten = fread(GlobalMemory, 1, sizeof(GlobalMemory), File); + fclose(File); + + if(Execute) + { + printf("--- %s execution ---\n", FileName); + + Run8086(BytesWritten, GlobalMemory); + + if(Dump) + { + // NOTE(luca): We have to add ".data" or Gimp will throw an error. + FILE *DumpFile = fopen("sim86_memory_0.data", "wb"); + fwrite(GlobalMemory, 1, sizeof(GlobalMemory), DumpFile); + fclose(DumpFile); + } + + } + else + { + printf("ERROR: Disassembling not implemented yet.\n"); + } + + } + else + { + printf("ERROR: Unable to open %s.\n", FileName); + PrintUsage(Args[0]); + } + } + + return 0; +} |
