From aa4bfe45dcb21444ccb54da5c90661410be36676 Mon Sep 17 00:00:00 2001 From: Raymaekers Luca Date: Sat, 25 Oct 2025 15:58:31 +0200 Subject: checkpoint --- build/sim86 | Bin 65872 -> 61656 bytes build/sim86_meta | Bin 181968 -> 177464 bytes computerenhance.md | 7 +- .../listing_0056_estimating_cycles | Bin 0 -> 55 bytes .../listing_0056_estimating_cycles.asm | 41 ++++++ .../listing_0056_estimating_cycles.txt | 72 ++++++++++ .../listing_0057_challenge_cycles | 2 + .../listing_0057_challenge_cycles.asm | 42 ++++++ .../listing_0057_challenge_cycles.txt | 71 ++++++++++ project.4coder | 1 + src/build.sh | 7 +- src/clocks_table.inl | 51 +++++++ src/generated/generated.cpp | 13 -- src/sim86.cpp | 153 ++++++++++++++++++--- src/sim86.h | 23 ---- src/sim86.mdesk | 22 +-- src/sim86_meta.c | 7 + 17 files changed, 443 insertions(+), 69 deletions(-) create mode 100644 data/estimating_cycles/listing_0056_estimating_cycles create mode 100644 data/estimating_cycles/listing_0056_estimating_cycles.asm create mode 100644 data/estimating_cycles/listing_0056_estimating_cycles.txt create mode 100644 data/estimating_cycles/listing_0057_challenge_cycles create mode 100644 data/estimating_cycles/listing_0057_challenge_cycles.asm create mode 100644 data/estimating_cycles/listing_0057_challenge_cycles.txt create mode 100644 src/clocks_table.inl diff --git a/build/sim86 b/build/sim86 index 4e86ddf..08e2c7c 100755 Binary files a/build/sim86 and b/build/sim86 differ diff --git a/build/sim86_meta b/build/sim86_meta index 8226ed8..c7b2e28 100755 Binary files a/build/sim86_meta and b/build/sim86_meta differ diff --git a/computerenhance.md b/computerenhance.md index 3df3bda..1733704 100644 --- a/computerenhance.md +++ b/computerenhance.md @@ -732,11 +732,16 @@ Calling conventions and ABIs are rules so code can operate with other code when You can spot memory access by brackets '[]'. Either a load/store or LEA or prefetch. LEA does a load with a temp registers. You can use the stack as regular memory by saving `sp` (stack pointer) to a register and offsetting from it. -A stack frame is a context view of a "call". +A stack frame is the part of the stack created by a function. # 36. [Performance Excuses Debunked](https://www.computerenhance.com/p/performance-excuses-debunked) # 37. [Estimating Cycles](https://www.computerenhance.com/p/estimating-cycles) +By using estimation you can know what your performance *should* be. +clocks=cycles + # 38. [Monday Q&A #10 (2023-05-08)](https://www.computerenhance.com/p/monday-q-and-a-10-2023-05-08) +With SIMD using smaller numbers will be faster. + # 39. [From 8086 to x64](https://www.computerenhance.com/p/from-8086-to-x64) # 40. [8086 Internals Poll](https://www.computerenhance.com/p/8086-internals-poll) # 41. [How to Play Trinity](https://www.computerenhance.com/p/how-to-play-trinity) diff --git a/data/estimating_cycles/listing_0056_estimating_cycles b/data/estimating_cycles/listing_0056_estimating_cycles new file mode 100644 index 0000000..bb15fc7 Binary files /dev/null and b/data/estimating_cycles/listing_0056_estimating_cycles differ diff --git a/data/estimating_cycles/listing_0056_estimating_cycles.asm b/data/estimating_cycles/listing_0056_estimating_cycles.asm new file mode 100644 index 0000000..3a28ddd --- /dev/null +++ b/data/estimating_cycles/listing_0056_estimating_cycles.asm @@ -0,0 +1,41 @@ +; ======================================================================== +; +; (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 56 +; ======================================================================== + +bits 16 + +mov bx, 1000 +mov bp, 2000 +mov si, 3000 +mov di, 4000 + +mov cx, bx +mov dx, 12 + +mov dx, [1000] + +mov cx, [bx] +mov cx, [bp] +mov [si], cx +mov [di], cx + +mov cx, [bx + 1000] +mov cx, [bp + 1000] +mov [si + 1000], cx +mov [di + 1000], cx + +add cx, dx +add [di + 1000], cx +add dx, 50 diff --git a/data/estimating_cycles/listing_0056_estimating_cycles.txt b/data/estimating_cycles/listing_0056_estimating_cycles.txt new file mode 100644 index 0000000..6997cec --- /dev/null +++ b/data/estimating_cycles/listing_0056_estimating_cycles.txt @@ -0,0 +1,72 @@ +************** +**** 8086 **** +************** + +WARNING: Clocks reported by this utility are strictly from the 8086 manual. +They will be inaccurate, both because the manual clocks are estimates, and because +some of the entries in the manual look highly suspicious and are probably typos. + +--- test\listing_0056_estimating_cycles execution --- +mov bx, 1000 ; Clocks: +4 = 4 | bx:0x0->0x3e8 ip:0x0->0x3 +mov bp, 2000 ; Clocks: +4 = 8 | bp:0x0->0x7d0 ip:0x3->0x6 +mov si, 3000 ; Clocks: +4 = 12 | si:0x0->0xbb8 ip:0x6->0x9 +mov di, 4000 ; Clocks: +4 = 16 | di:0x0->0xfa0 ip:0x9->0xc +mov cx, bx ; Clocks: +2 = 18 | cx:0x0->0x3e8 ip:0xc->0xe +mov dx, 12 ; Clocks: +4 = 22 | dx:0x0->0xc ip:0xe->0x11 +mov dx, [+1000] ; Clocks: +14 = 36 (8 + 6ea) | dx:0xc->0x0 ip:0x11->0x15 +mov cx, [bx] ; Clocks: +13 = 49 (8 + 5ea) | cx:0x3e8->0x0 ip:0x15->0x17 +mov cx, [bp] ; Clocks: +13 = 62 (8 + 5ea) | ip:0x17->0x1a +mov word [si], cx ; Clocks: +14 = 76 (9 + 5ea) | ip:0x1a->0x1c +mov word [di], cx ; Clocks: +14 = 90 (9 + 5ea) | ip:0x1c->0x1e +mov cx, [bx+1000] ; Clocks: +17 = 107 (8 + 9ea) | ip:0x1e->0x22 +mov cx, [bp+1000] ; Clocks: +17 = 124 (8 + 9ea) | ip:0x22->0x26 +mov word [si+1000], cx ; Clocks: +18 = 142 (9 + 9ea) | ip:0x26->0x2a +mov word [di+1000], cx ; Clocks: +18 = 160 (9 + 9ea) | ip:0x2a->0x2e +add cx, dx ; Clocks: +3 = 163 | ip:0x2e->0x30 flags:->PZ +add word [di+1000], cx ; Clocks: +25 = 188 (16 + 9ea) | ip:0x30->0x34 +add dx, 50 ; Clocks: +4 = 192 | dx:0x0->0x32 ip:0x34->0x37 flags:PZ-> + +Final registers: + bx: 0x03e8 (1000) + dx: 0x0032 (50) + bp: 0x07d0 (2000) + si: 0x0bb8 (3000) + di: 0x0fa0 (4000) + ip: 0x0037 (55) + + +************** +**** 8088 **** +************** + +WARNING: Clocks reported by this utility are strictly from the 8086 manual. +They will be inaccurate, both because the manual clocks are estimates, and because +some of the entries in the manual look highly suspicious and are probably typos. + +--- test\listing_0056_estimating_cycles execution --- +mov bx, 1000 ; Clocks: +4 = 4 | bx:0x0->0x3e8 ip:0x0->0x3 +mov bp, 2000 ; Clocks: +4 = 8 | bp:0x0->0x7d0 ip:0x3->0x6 +mov si, 3000 ; Clocks: +4 = 12 | si:0x0->0xbb8 ip:0x6->0x9 +mov di, 4000 ; Clocks: +4 = 16 | di:0x0->0xfa0 ip:0x9->0xc +mov cx, bx ; Clocks: +2 = 18 | cx:0x0->0x3e8 ip:0xc->0xe +mov dx, 12 ; Clocks: +4 = 22 | dx:0x0->0xc ip:0xe->0x11 +mov dx, [+1000] ; Clocks: +18 = 40 (8 + 6ea + 4p) | dx:0xc->0x0 ip:0x11->0x15 +mov cx, [bx] ; Clocks: +17 = 57 (8 + 5ea + 4p) | cx:0x3e8->0x0 ip:0x15->0x17 +mov cx, [bp] ; Clocks: +17 = 74 (8 + 5ea + 4p) | ip:0x17->0x1a +mov word [si], cx ; Clocks: +18 = 92 (9 + 5ea + 4p) | ip:0x1a->0x1c +mov word [di], cx ; Clocks: +18 = 110 (9 + 5ea + 4p) | ip:0x1c->0x1e +mov cx, [bx+1000] ; Clocks: +21 = 131 (8 + 9ea + 4p) | ip:0x1e->0x22 +mov cx, [bp+1000] ; Clocks: +21 = 152 (8 + 9ea + 4p) | ip:0x22->0x26 +mov word [si+1000], cx ; Clocks: +22 = 174 (9 + 9ea + 4p) | ip:0x26->0x2a +mov word [di+1000], cx ; Clocks: +22 = 196 (9 + 9ea + 4p) | ip:0x2a->0x2e +add cx, dx ; Clocks: +3 = 199 | ip:0x2e->0x30 flags:->PZ +add word [di+1000], cx ; Clocks: +33 = 232 (16 + 9ea + 8p) | ip:0x30->0x34 +add dx, 50 ; Clocks: +4 = 236 | dx:0x0->0x32 ip:0x34->0x37 flags:PZ-> + +Final registers: + bx: 0x03e8 (1000) + dx: 0x0032 (50) + bp: 0x07d0 (2000) + si: 0x0bb8 (3000) + di: 0x0fa0 (4000) + ip: 0x0037 (55) diff --git a/data/estimating_cycles/listing_0057_challenge_cycles b/data/estimating_cycles/listing_0057_challenge_cycles new file mode 100644 index 0000000..59b206e --- /dev/null +++ b/data/estimating_cycles/listing_0057_challenge_cycles @@ -0,0 +1,2 @@ +»è½Ð¾¸ ¿ ‹ ‰‹ +‰ ‹‹è‰ˆè‹Šè‰‰è’èƒL’é•çƒK \ No newline at end of file diff --git a/data/estimating_cycles/listing_0057_challenge_cycles.asm b/data/estimating_cycles/listing_0057_challenge_cycles.asm new file mode 100644 index 0000000..4a9adb0 --- /dev/null +++ b/data/estimating_cycles/listing_0057_challenge_cycles.asm @@ -0,0 +1,42 @@ +; ======================================================================== +; +; (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 57 +; ======================================================================== + +bits 16 + +mov bx, 1000 +mov bp, 2000 +mov si, 3000 +mov di, 4000 + +mov cx, [bp + di] +mov [bx + si], cx + +mov cx, [bp + si] +mov [bx + di], cx + +mov cx, [bp + di + 1000] +mov [bx + si + 1000], cx + +mov cx, [bp + si + 1000] +mov [bx + di + 1000], cx + +add dx, [bp + si + 1000] + +add word [bp + si], 76 + +add dx, [bp + si + 1001] +add [di + 999], dx +add word [bp + si], 75 diff --git a/data/estimating_cycles/listing_0057_challenge_cycles.txt b/data/estimating_cycles/listing_0057_challenge_cycles.txt new file mode 100644 index 0000000..51cceb4 --- /dev/null +++ b/data/estimating_cycles/listing_0057_challenge_cycles.txt @@ -0,0 +1,71 @@ +************** +**** 8086 **** +************** + +WARNING: Clocks reported by this utility are strictly from the 8086 manual. +They will be inaccurate, both because the manual clocks are estimates, and because +some of the entries in the manual look highly suspicious and are probably typos. + +--- test\listing_0057_challenge_cycles execution --- +mov bx, 1000 ; Clocks: +4 = 4 | bx:0x0->0x3e8 ip:0x0->0x3 +mov bp, 2000 ; Clocks: +4 = 8 | bp:0x0->0x7d0 ip:0x3->0x6 +mov si, 3000 ; Clocks: +4 = 12 | si:0x0->0xbb8 ip:0x6->0x9 +mov di, 4000 ; Clocks: +4 = 16 | di:0x0->0xfa0 ip:0x9->0xc +mov cx, [bp+di] ; Clocks: +15 = 31 (8 + 7ea) | ip:0xc->0xe +mov word [bx+si], cx ; Clocks: +16 = 47 (9 + 7ea) | ip:0xe->0x10 +mov cx, [bp+si] ; Clocks: +16 = 63 (8 + 8ea) | ip:0x10->0x12 +mov word [bx+di], cx ; Clocks: +17 = 80 (9 + 8ea) | ip:0x12->0x14 +mov cx, [bp+di+1000] ; Clocks: +19 = 99 (8 + 11ea) | ip:0x14->0x18 +mov word [bx+si+1000], cx ; Clocks: +20 = 119 (9 + 11ea) | ip:0x18->0x1c +mov cx, [bp+si+1000] ; Clocks: +20 = 139 (8 + 12ea) | ip:0x1c->0x20 +mov word [bx+di+1000], cx ; Clocks: +21 = 160 (9 + 12ea) | ip:0x20->0x24 +add dx, [bp+si+1000] ; Clocks: +21 = 181 (9 + 12ea) | ip:0x24->0x28 flags:->PZ +add word [bp+si], 76 ; Clocks: +25 = 206 (17 + 8ea) | ip:0x28->0x2b flags:PZ-> +add dx, [bp+si+1001] ; Clocks: +25 = 231 (9 + 12ea + 4p) | ip:0x2b->0x2f flags:->PZ +add word [di+999], dx ; Clocks: +33 = 264 (16 + 9ea + 8p) | ip:0x2f->0x33 flags:PZ->P +add word [bp+si], 75 ; Clocks: +25 = 289 (17 + 8ea) | ip:0x33->0x36 flags:P->A + +Final registers: + bx: 0x03e8 (1000) + bp: 0x07d0 (2000) + si: 0x0bb8 (3000) + di: 0x0fa0 (4000) + ip: 0x0036 (54) + flags: A + + + +************** +**** 8088 **** +************** + +WARNING: Clocks reported by this utility are strictly from the 8086 manual. +They will be inaccurate, both because the manual clocks are estimates, and because +some of the entries in the manual look highly suspicious and are probably typos. + +--- test\listing_0057_challenge_cycles execution --- +mov bx, 1000 ; Clocks: +4 = 4 | bx:0x0->0x3e8 ip:0x0->0x3 +mov bp, 2000 ; Clocks: +4 = 8 | bp:0x0->0x7d0 ip:0x3->0x6 +mov si, 3000 ; Clocks: +4 = 12 | si:0x0->0xbb8 ip:0x6->0x9 +mov di, 4000 ; Clocks: +4 = 16 | di:0x0->0xfa0 ip:0x9->0xc +mov cx, [bp+di] ; Clocks: +19 = 35 (8 + 7ea + 4p) | ip:0xc->0xe +mov word [bx+si], cx ; Clocks: +20 = 55 (9 + 7ea + 4p) | ip:0xe->0x10 +mov cx, [bp+si] ; Clocks: +20 = 75 (8 + 8ea + 4p) | ip:0x10->0x12 +mov word [bx+di], cx ; Clocks: +21 = 96 (9 + 8ea + 4p) | ip:0x12->0x14 +mov cx, [bp+di+1000] ; Clocks: +23 = 119 (8 + 11ea + 4p) | ip:0x14->0x18 +mov word [bx+si+1000], cx ; Clocks: +24 = 143 (9 + 11ea + 4p) | ip:0x18->0x1c +mov cx, [bp+si+1000] ; Clocks: +24 = 167 (8 + 12ea + 4p) | ip:0x1c->0x20 +mov word [bx+di+1000], cx ; Clocks: +25 = 192 (9 + 12ea + 4p) | ip:0x20->0x24 +add dx, [bp+si+1000] ; Clocks: +25 = 217 (9 + 12ea + 4p) | ip:0x24->0x28 flags:->PZ +add word [bp+si], 76 ; Clocks: +33 = 250 (17 + 8ea + 8p) | ip:0x28->0x2b flags:PZ-> +add dx, [bp+si+1001] ; Clocks: +25 = 275 (9 + 12ea + 4p) | ip:0x2b->0x2f flags:->PZ +add word [di+999], dx ; Clocks: +33 = 308 (16 + 9ea + 8p) | ip:0x2f->0x33 flags:PZ->P +add word [bp+si], 75 ; Clocks: +33 = 341 (17 + 8ea + 8p) | ip:0x33->0x36 flags:P->A + +Final registers: + bx: 0x03e8 (1000) + bp: 0x07d0 (2000) + si: 0x0bb8 (3000) + di: 0x0fa0 (4000) + ip: 0x0036 (54) + flags: A diff --git a/project.4coder b/project.4coder index c06e98e..24c2c82 100644 --- a/project.4coder +++ b/project.4coder @@ -2,6 +2,7 @@ version(2); project_name = "sim8086"; patterns = { "*.c", + "*.mdesk", "*.cpp", "*.h", "*.m", diff --git a/src/build.sh b/src/build.sh index 8cfb982..7726aee 100755 --- a/src/build.sh +++ b/src/build.sh @@ -28,17 +28,14 @@ WarningFlags=" -Wno-write-strings " -Libs="./libs/reference_decoder/sim86_lib.cpp" - printf '[metadata generation]\n' -Source="sim86_meta.c" $Compiler $CompilerFlags $WarningFlags \ -o ../build/sim86_meta \ - $Source + sim86_meta.c ../build/sim86_meta ./sim86.mdesk > ./generated/generated.cpp printf '[%s build]\n' "$Compiler" Source="sim86.cpp" $Compiler $CompilerFlags $WarningFlags \ -o ../build/sim86 \ - $Libs $Source + sim86.cpp diff --git a/src/clocks_table.inl b/src/clocks_table.inl new file mode 100644 index 0000000..2c07bb3 --- /dev/null +++ b/src/clocks_table.inl @@ -0,0 +1,51 @@ + +enum instruction_clocks_operand_type +{ + InstructionClocksOperand_None = 0, + InstructionClocksOperand_Memory, + InstructionClocksOperand_Immediate, + InstructionClocksOperand_Accumulator, + InstructionClocksOperand_Register, + InstructionClocksOperand_Count +}; + +struct instruction_clocks +{ + operation_type Op; + instruction_clocks_operand_type Operands[2]; + u32 Clocks; + u32 Transfers; + b32 EffectiveAddress; +}; + +#define Memory InstructionClocksOperand_Memory +#define Immediate InstructionClocksOperand_Immediate +#define Accumulator InstructionClocksOperand_Accumulator +#define Register InstructionClocksOperand_Register +#define None InstructionClocksOperand_None + +// NOTE(luca): Instructions containing accumulator should be put first so they have precedence +// on instructions with registers (accumulator is a register). +instruction_clocks ClocksTable[] = +{ + { Op_mov, { Memory, Accumulator }, 10, 1, false }, + { Op_mov, { Accumulator, Memory }, 10, 1, false }, + { Op_mov, { Register, Register }, 2, 0, false }, + { Op_mov, { Register, Memory }, 8, 1, true }, + { Op_mov, { Memory, Register }, 9, 1, true }, + { Op_mov, { Register, Immediate }, 4, 0, false }, + { Op_mov, { Memory, Immediate }, 10, 1, true }, + + { Op_add, { Accumulator, Immediate }, 4, 0, false }, + { Op_add, { Register, Register }, 3, 0, false }, + { Op_add, { Register, Memory }, 9, 1, true }, + { Op_add, { Memory, Register }, 16, 2, true }, + { Op_add, { Register, Immediate }, 4, 0, false }, + { Op_add, { Memory, Immediate }, 17, 2, true }, +}; + +#undef Memory +#undef Register +#undef None +#undef Accumulator +#undef Immediate \ No newline at end of file diff --git a/src/generated/generated.cpp b/src/generated/generated.cpp index 1ad803c..0f457a1 100644 --- a/src/generated/generated.cpp +++ b/src/generated/generated.cpp @@ -1,16 +1,3 @@ -enum flags_songs -{ - Flag_French = (1 << 0), - Flag_Russian = (1 << 1), -}; - -int songs_strings_count = 2; -char *songs_strings[] = -{ - "French Blues", - "Russian Blues", -}; - enum flags_8086 { Flag_Carry = (1 << 0), diff --git a/src/sim86.cpp b/src/sim86.cpp index ba9e252..e5480d7 100644 --- a/src/sim86.cpp +++ b/src/sim86.cpp @@ -1,9 +1,10 @@ #include #include -#include "sim86.h" -#include "sim86_shared.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] = {}; @@ -82,6 +83,19 @@ FlagsFromValue(u32 *FlagsRegister, u32 InstructionFlags, s32 Value) } } +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) { @@ -94,16 +108,7 @@ OperandToValue(s32 *Registers, u8 *Memory, instruction_operand *Operand) } else if(Operand->Type == Operand_Memory) { - s32 CompleteDisplacement = Operand->Address.Displacement; - Assert(Operand->Address.Terms[0].Register.Count == Operand->Address.Terms[1].Register.Count); - - 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); - + s32 CompleteDisplacement = GetCompleteDisplacement(Registers, Operand); Result = (s32 *)((u8 *)Memory + CompleteDisplacement); } else if(Operand->Type == Operand_Immediate) @@ -118,12 +123,32 @@ OperandToValue(s32 *Registers, u8 *Memory, instruction_operand *Operand) 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) { @@ -135,12 +160,110 @@ Run8086(psize MemorySize, u8 *Memory) IPRegister += Decoded.Size; #if SIM86_INTERNAL - printf("Size:%u Op:%s Flags:0x%x ;", Decoded.Size, Sim86_MnemonicFromOperationType(Decoded.Op), Decoded.Flags); + 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); @@ -207,8 +330,6 @@ Run8086(psize MemorySize, u8 *Memory) } else if(Decoded.Op == Op_add) { - Assert(DestinationOperand->Type == Operand_Register); - s32 Old = *Destination; *Destination = ((Decoded.Flags & Inst_Wide) ? @@ -257,7 +378,7 @@ Run8086(psize MemorySize, u8 *Memory) } - printf("Final registers:\n"); + printf("\nFinal registers:\n"); for(u32 RegisterIndex = Register_a; RegisterIndex < Register_ds + 1; RegisterIndex++) diff --git a/src/sim86.h b/src/sim86.h index d24cb70..24068e2 100644 --- a/src/sim86.h +++ b/src/sim86.h @@ -12,27 +12,4 @@ typedef size_t psize; #define Assert(Expression) if(!(Expression)) { __asm__ volatile("int3"); } #define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0])) -//~ Stolen from the decoder. -enum register_mapping_8086 -{ - Register_none, - - Register_a, - Register_b, - Register_c, - Register_d, - Register_sp, - Register_bp, - Register_si, - Register_di, - Register_es, - Register_cs, - Register_ss, - Register_ds, - Register_ip, - Register_flags, - - Register_count, -}; - #endif //SIM86_H diff --git a/src/sim86.mdesk b/src/sim86.mdesk index 6de46fc..0635110 100644 --- a/src/sim86.mdesk +++ b/src/sim86.mdesk @@ -1,4 +1,3 @@ - @table(name, str) sim86_flags_mapping: { { Carry, "C", } @@ -12,21 +11,22 @@ { Trap, "T", } } -@table(name, title) songs: -{ - { French, "French Blues" }, - { Russian, "Russian Blues" }, -} - -@table_gen_enum_flags(songs, name) flags_songs -@table_gen_data(songs, `char *`, title) songs_strings - @table_gen_enum_flags(sim86_flags_mapping, name) flags_8086 @table_gen_data(sim86_flags_mapping, `char *`, str) flags_8086_strings +// TODO: @table_gen_enum sim86_enum: { @expand(sim86_flags_mapping mapping) `Sim86_$(mapping.name),` `Sim86_Count` -} \ No newline at end of file +} + +@table(mnemonic, encoding, clocks, name) instructions_table: +{ + { mov, [ B:100010, D, W, MOD, REG, RM ], 4, "Register/memory to/from register" } + { mov, [ B:1100011, W, MOD, B:000, RM, ImpD:0, DATA, DATA_IF_W ], 5, "Immediate to register/memory" } + { mov, [ B:1011, W, REG, ImpD:1 ], 3, "Immediate to register" } +} + + diff --git a/src/sim86_meta.c b/src/sim86_meta.c index f5046a7..c8fe8f3 100644 --- a/src/sim86_meta.c +++ b/src/sim86_meta.c @@ -123,6 +123,13 @@ int main(int ArgsCount, char *Args[]) MD_S8ListPush(Arena, &Stream, MD_S8Lit("};\n\n")); } +#if 0 + if(MD_NodeHasTag(Node, MD_S8Lit("table"), 0)) + { + Assert(0); + } +#endif + if(MD_NodeHasTag(Node, MD_S8Lit("table_gen_enum"), 0)) { // Header -- cgit v1.2.3-70-g09d2