mirror of
https://github.com/Ed94/perfaware.git
synced 2024-12-21 22:44:46 -08:00
Finished the first hw.
On to the second...
This commit is contained in:
parent
5b230d5653
commit
9be706b28d
19
.vscode/launch.json
vendored
Normal file
19
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "(Windows) Launch",
|
||||||
|
"type": "cppvsdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceRoot}/part_1/build/sim_8086.exe",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceRoot}/part_1",
|
||||||
|
"environment": [],
|
||||||
|
"console": "externalTerminal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"*.rmd": "markdown",
|
"*.rmd": "markdown",
|
||||||
"zpl.h": "c"
|
"zpl.h": "c",
|
||||||
|
"cstddef": "cpp",
|
||||||
|
"xtr1common": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
111
part_1/bloat.hpp
Normal file
111
part_1/bloat.hpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#if __clang__
|
||||||
|
# pragma clang diagnostic ignored "-Wunused-const-variable"
|
||||||
|
# pragma clang diagnostic ignored "-Wswitch"
|
||||||
|
# pragma clang diagnostic ignored "-Wunused-variable"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#pragma region ZPL INCLUDE
|
||||||
|
|
||||||
|
#if __clang__
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wmissing-braces"
|
||||||
|
# pragma clang diagnostic ignored "-Wbraced-scalar-init"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ZPL_IMPLEMENTATION
|
||||||
|
// # define ZPL_HEAP_ANALYSIS
|
||||||
|
# define ZPL_NO_MATH_H
|
||||||
|
# define ZPL_CUSTOM_MODULES
|
||||||
|
# define ZPL_MODULE_ESSENTIALS
|
||||||
|
# define ZPL_MODULE_CORE
|
||||||
|
# define ZPL_MODULE_TIMER
|
||||||
|
// # define ZPL_MODULE_HASHING
|
||||||
|
// # define ZPL_MODULE_REGEX
|
||||||
|
// # define ZPL_MODULE_EVENT
|
||||||
|
// # define ZPL_MODULE_DLL
|
||||||
|
// # define ZPL_MODULE_OPTS
|
||||||
|
// # define ZPL_MODULE_PROCESS
|
||||||
|
// # define ZPL_MODULE_MATH
|
||||||
|
// # define ZPL_MODULE_THREADING
|
||||||
|
// # define ZPL_MODULE_JOBS
|
||||||
|
// # define ZPL_MODULE_PARSER
|
||||||
|
extern "C" {
|
||||||
|
#include "zpl.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef cast
|
||||||
|
|
||||||
|
#pragma endregion ZPL INCLUDE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define bit( Value_ ) ( 1 << Value_ )
|
||||||
|
#define bitfield_is_equal( Field_, Mask_ ) ( ( Mask_ & Field_ ) == Mask_ )
|
||||||
|
#define cast( Type_ , Value_ ) ( ( Type_ )( Value_ ) )
|
||||||
|
#define ct constexpr
|
||||||
|
#define gen( ... ) template< __VA_ARGS__ >
|
||||||
|
#define forceinline ZPL_ALWAYS_INLINE
|
||||||
|
#define print_nl( _) zpl_printf("\n")
|
||||||
|
#define Msg_Invalid_Value "INVALID VALUE PROVIDED"
|
||||||
|
#define scast static_cast
|
||||||
|
#define rcast reinterpret_cast
|
||||||
|
|
||||||
|
using u8 = zpl_u8;
|
||||||
|
using u16 = zpl_u16;
|
||||||
|
using u32 = zpl_u32;
|
||||||
|
using uw = zpl_usize;
|
||||||
|
using sw = zpl_isize;
|
||||||
|
|
||||||
|
ct inline
|
||||||
|
char char_binary( u8 value, u8 pos )
|
||||||
|
{
|
||||||
|
u8 mask = 1 << pos ;
|
||||||
|
|
||||||
|
return ( (1 << pos) & value) == mask ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void str_binary( char* result, u8 value )
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
result[0] = char_binary( value, 0);
|
||||||
|
result[1] = char_binary( value, 1);
|
||||||
|
result[2] = char_binary( value, 2);
|
||||||
|
result[3] = char_binary( value, 3);
|
||||||
|
result[4] = char_binary( value, 4);
|
||||||
|
result[5] = char_binary( value, 5);
|
||||||
|
result[6] = char_binary( value, 6);
|
||||||
|
result[7] = char_binary( value, 7);
|
||||||
|
#else
|
||||||
|
result[0] = char_binary( value, 7);
|
||||||
|
result[1] = char_binary( value, 6);
|
||||||
|
result[2] = char_binary( value, 5);
|
||||||
|
result[3] = char_binary( value, 4);
|
||||||
|
result[4] = char_binary( value, 3);
|
||||||
|
result[5] = char_binary( value, 2);
|
||||||
|
result[6] = char_binary( value, 1);
|
||||||
|
result[7] = char_binary( value, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void print_as_binary( u8* data, uw size, char const* byte_term )
|
||||||
|
{
|
||||||
|
char
|
||||||
|
binary_string[9];
|
||||||
|
binary_string[8] = '\0';
|
||||||
|
|
||||||
|
while ( size-- )
|
||||||
|
{
|
||||||
|
str_binary( binary_string, data[0]);
|
||||||
|
|
||||||
|
printf( "%s%s", binary_string, byte_term );
|
||||||
|
|
||||||
|
data += 1;
|
||||||
|
}
|
||||||
|
}
|
@ -4,4 +4,16 @@ if not exist build\nul (
|
|||||||
meson setup build
|
meson setup build
|
||||||
)
|
)
|
||||||
|
|
||||||
|
echo:
|
||||||
|
if not exist tests\listing_0037_single_register_mov (
|
||||||
|
echo Assembling: listing_0037_single_register_mov.asm
|
||||||
|
call nasm ".\tests\listing_0037_single_register_mov.asm"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist tests\listing_0038_many_register_mov (
|
||||||
|
echo Assembling: listing_0038_many_register_mov.asm
|
||||||
|
call nasm ".\tests\listing_0038_many_register_mov.asm"
|
||||||
|
)
|
||||||
|
|
||||||
|
echo:
|
||||||
ninja -C build
|
ninja -C build
|
BIN
part_1/debug.rdbg
Normal file
BIN
part_1/debug.rdbg
Normal file
Binary file not shown.
@ -2,4 +2,12 @@ project( 'sim_8086', 'c', 'cpp', default_options : ['buildtype=debug'] )
|
|||||||
|
|
||||||
include_thirdparty = include_directories( '../thirdparty' )
|
include_thirdparty = include_directories( '../thirdparty' )
|
||||||
|
|
||||||
|
# add_global_arguments('-E', language : 'cpp')
|
||||||
|
|
||||||
|
if get_option('buildtype').startswith('debug')
|
||||||
|
|
||||||
|
add_project_arguments('-DBuild_Debug', language : 'cpp')
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
executable( 'sim_8086', 'sim_8086.cpp', include_directories : include_thirdparty )
|
executable( 'sim_8086', 'sim_8086.cpp', include_directories : include_thirdparty )
|
||||||
|
@ -1,149 +1,42 @@
|
|||||||
#if __clang__
|
#include "bloat.hpp"
|
||||||
#pragma clang diagnostic ignored "-Wunused-const-variable"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
zpl_arena BlobArena {};
|
||||||
|
#define allocator zpl_arena_allocator( & BlobArena)
|
||||||
|
|
||||||
#pragma region ZPL INCLUDE
|
void setup()
|
||||||
|
{
|
||||||
|
zpl_arena_init_from_allocator( & BlobArena, zpl_heap(), zpl_megabytes(10) );
|
||||||
|
|
||||||
#if __clang__
|
if ( BlobArena.total_size == 0 )
|
||||||
#pragma clang diagnostic push
|
{
|
||||||
#pragma clang diagnostic ignored "-Wmissing-braces"
|
zpl_assert_crash( "Failed to reserve memory for Tests:: BLobArena" );
|
||||||
#pragma clang diagnostic ignored "-Wbraced-scalar-init"
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
#define ZPL_IMPLEMENTATION
|
void cleanup()
|
||||||
#include "zpl.h"
|
{
|
||||||
|
zpl_arena_free( & BlobArena);
|
||||||
|
}
|
||||||
|
|
||||||
#if __clang__
|
// Binary formatting for literals is used heavily as that its
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#pragma endregion ZPL INCLUDE
|
|
||||||
|
|
||||||
|
|
||||||
// This has me screwing around with generating lookup tables.
|
|
||||||
// Going to measure the difference between them and jump tables instructions at some point...
|
|
||||||
|
|
||||||
// Binary formatting for literals is used heavily as that is
|
|
||||||
// how the encoding is conveyed in the hardware reference from intel.
|
// how the encoding is conveyed in the hardware reference from intel.
|
||||||
|
|
||||||
|
|
||||||
#define bit( value ) ( 1 << value )
|
|
||||||
#define bitfield_is_equal( field_, mask_ ) ( ( mask_ & field_ ) == mask_ )
|
|
||||||
#define ct constexpr
|
|
||||||
#define forceinline ZPL_ALWAYS_INLINE
|
|
||||||
#define MSG_INVALID_VALUE "INVALID VALUE PROVIDED"
|
|
||||||
|
|
||||||
|
|
||||||
using u8 = unsigned char;
|
|
||||||
using u16 = unsigned short;
|
|
||||||
using u32 = unsigned long;
|
|
||||||
|
|
||||||
// using bytecode = u8;
|
|
||||||
|
|
||||||
|
|
||||||
inline
|
|
||||||
char char_binary( u8 value, u8 pos )
|
|
||||||
{
|
|
||||||
constexpr u8 baseline = 1;
|
|
||||||
u8 mask = baseline << pos;
|
|
||||||
|
|
||||||
return ( (baseline << pos) & value) == mask ? '1' : '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
void str_binary( char* result, u8 value )
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
result[0] = char_binary( value, 0);
|
|
||||||
result[1] = char_binary( value, 1);
|
|
||||||
result[2] = char_binary( value, 2);
|
|
||||||
result[3] = char_binary( value, 3);
|
|
||||||
result[4] = char_binary( value, 4);
|
|
||||||
result[5] = char_binary( value, 5);
|
|
||||||
result[6] = char_binary( value, 6);
|
|
||||||
result[7] = char_binary( value, 7);
|
|
||||||
#else
|
|
||||||
result[0] = char_binary( value, 7);
|
|
||||||
result[1] = char_binary( value, 6);
|
|
||||||
result[2] = char_binary( value, 5);
|
|
||||||
result[3] = char_binary( value, 4);
|
|
||||||
result[4] = char_binary( value, 3);
|
|
||||||
result[5] = char_binary( value, 2);
|
|
||||||
result[6] = char_binary( value, 1);
|
|
||||||
result[7] = char_binary( value, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define USE_LOOKUP_TABLE 0
|
|
||||||
namespace Op
|
namespace Op
|
||||||
{
|
{
|
||||||
ct u8 Mask = 0b11111100;
|
|
||||||
|
|
||||||
#define D_Opcodes \
|
#define D_Opcodes \
|
||||||
D_Entry( mov_88 ) \
|
D_Entry( mov_88 ) \
|
||||||
D_Entry( mov_89 ) \
|
D_Entry( mov_89 ) \
|
||||||
|
|
||||||
using Type = u8;
|
enum Code : u8
|
||||||
enum
|
|
||||||
{
|
{
|
||||||
#if USE_LOOKUP_TABLE
|
Mask = 0b11111100,
|
||||||
#define D_Entry( Entry_ ) Entry_,
|
|
||||||
D_Opcodes
|
|
||||||
#undef D_Entry
|
|
||||||
|
|
||||||
#else
|
|
||||||
mov_88 = 0b10001000,
|
mov_88 = 0b10001000,
|
||||||
mov_89 = 0b11000100,
|
mov_89 = 0b11000100,
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Num = 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if USE_LOOKUP_TABLE
|
char const* str( Code type )
|
||||||
ct u8 code( Type type )
|
|
||||||
{
|
{
|
||||||
constexpr u8
|
|
||||||
type_to_code[ Num ] =
|
|
||||||
{
|
|
||||||
0b01000100, // mov_88
|
|
||||||
0b11000100, // mov_89
|
|
||||||
};
|
|
||||||
|
|
||||||
return type_to_code[ type ];
|
|
||||||
}
|
|
||||||
|
|
||||||
ct u8 type( u8 code )
|
|
||||||
{
|
|
||||||
switch ( code )
|
|
||||||
{
|
|
||||||
#define D_Entry
|
|
||||||
case 0b01000100:
|
|
||||||
return mov_88;
|
|
||||||
|
|
||||||
#undef D_Entry
|
|
||||||
}
|
|
||||||
|
|
||||||
return Num;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char const* str( Type type )
|
|
||||||
{
|
|
||||||
#if Op_USE_LOOKUP_TABLE
|
|
||||||
static char const*
|
|
||||||
type_to_str[ Num ] =
|
|
||||||
{
|
|
||||||
#define D_Entry( Entry_ ) #Entry_,
|
|
||||||
D_Opcodes
|
|
||||||
#undef D_Entry
|
|
||||||
};
|
|
||||||
|
|
||||||
return type_to_str[ type ];
|
|
||||||
|
|
||||||
#else
|
|
||||||
switch ( type )
|
switch ( type )
|
||||||
{
|
{
|
||||||
case mov_88:
|
case mov_88:
|
||||||
@ -152,11 +45,10 @@ namespace Op
|
|||||||
return "mov_89";
|
return "mov_89";
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_INVALID_VALUE;
|
return Msg_Invalid_Value;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ct char const* helper_meumonic( Type type )
|
ct char const* helper_meumonic( Code type )
|
||||||
{
|
{
|
||||||
switch ( type )
|
switch ( type )
|
||||||
{
|
{
|
||||||
@ -165,23 +57,11 @@ namespace Op
|
|||||||
return "mov";
|
return "mov";
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_INVALID_VALUE;
|
return Msg_Invalid_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* meumonic( Type type )
|
char const* meumonic( Code type )
|
||||||
{
|
{
|
||||||
#if USE_LOOKUP_TABLE
|
|
||||||
static char const*
|
|
||||||
type_to_meumonic[ Num ] =
|
|
||||||
{
|
|
||||||
#define D_Entry( Entry_ ) helper_meumonic( Entry_ ),
|
|
||||||
D_Opcodes
|
|
||||||
#undef D_Entry
|
|
||||||
};
|
|
||||||
|
|
||||||
return type_to_meumonic[ type ];
|
|
||||||
|
|
||||||
#else
|
|
||||||
switch ( type )
|
switch ( type )
|
||||||
{
|
{
|
||||||
case mov_88:
|
case mov_88:
|
||||||
@ -189,11 +69,10 @@ namespace Op
|
|||||||
return "mov";
|
return "mov";
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_INVALID_VALUE;
|
return Msg_Invalid_Value;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ct char const* helper_intuitive( Type type )
|
ct char const* helper_intuitive( Code type )
|
||||||
{
|
{
|
||||||
switch ( type )
|
switch ( type )
|
||||||
{
|
{
|
||||||
@ -202,24 +81,11 @@ namespace Op
|
|||||||
return "move";
|
return "move";
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_INVALID_VALUE;
|
return Msg_Invalid_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* intuitive( Type type )
|
char const* intuitive( Code type )
|
||||||
{
|
{
|
||||||
#if USE_LOOKUP_TABLE
|
|
||||||
static char const*
|
|
||||||
type_to_meumonic[ Num ] =
|
|
||||||
{
|
|
||||||
#define D_Entry( Entry_ ) helper_intuitive( Entry_ ),
|
|
||||||
D_Opcodes
|
|
||||||
#undef D_Entry
|
|
||||||
};
|
|
||||||
|
|
||||||
return type_to_meumonic[ type ];
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
switch ( type )
|
switch ( type )
|
||||||
{
|
{
|
||||||
case mov_88:
|
case mov_88:
|
||||||
@ -227,8 +93,7 @@ namespace Op
|
|||||||
return "move";
|
return "move";
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_INVALID_VALUE;
|
return Msg_Invalid_Value;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef D_Opcodes
|
#undef D_Opcodes
|
||||||
@ -236,51 +101,46 @@ namespace Op
|
|||||||
|
|
||||||
namespace Field
|
namespace Field
|
||||||
{
|
{
|
||||||
#if 0
|
// Effective Address offset
|
||||||
using Type = u8;
|
inline
|
||||||
enum
|
u8 effective_address( u8 reg )
|
||||||
{
|
|
||||||
Dir_REG_Dest = 0b00,
|
|
||||||
Dir_REG_Src = 0b10,
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
ct u8 Mask_Dir = 0b00000010;
|
|
||||||
ct u8 Mask_Width = 0b00000001;
|
|
||||||
ct u8 Mask_Mode = 0b11000000;
|
|
||||||
|
|
||||||
// Mask: Effective Address
|
|
||||||
inline u8 mask_reg_operand( u8 reg )
|
|
||||||
{
|
{
|
||||||
return reg << 3;
|
return reg << 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://i.imgur.com/drsyYnM.png
|
// https://i.imgur.com/drsyYnM.png
|
||||||
ct u8 Dir_REG_Src = 0b00;
|
enum Direction : u8
|
||||||
ct u8 Dir_REG_Dest = 0b10;
|
{
|
||||||
|
Mask_Dir = 0b00000010,
|
||||||
|
Dir_Src = 0b00,
|
||||||
|
Dir_Dest = 0b10,
|
||||||
|
};
|
||||||
|
|
||||||
inline
|
inline
|
||||||
char const* str_direction( u8 direction )
|
char const* str_direction( Direction direction )
|
||||||
{
|
{
|
||||||
switch ( direction )
|
switch ( direction )
|
||||||
{
|
{
|
||||||
case Dir_REG_Dest:
|
case Dir_Dest:
|
||||||
return "Destination";
|
return "Destination";
|
||||||
|
|
||||||
case Dir_REG_Src:
|
case Dir_Src:
|
||||||
return "Source";
|
return "Source";
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_INVALID_VALUE;
|
return Msg_Invalid_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://i.imgur.com/9Op8Lnd.png
|
// https://i.imgur.com/9Op8Lnd.png
|
||||||
ct u8 Width_Byte = 0b00;
|
enum Width : u8
|
||||||
ct u8 Width_Word = 0b01;
|
{
|
||||||
|
Mask_Width = 0b00000001,
|
||||||
|
Width_Byte = 0b00,
|
||||||
|
Width_Word = 0b01,
|
||||||
|
};
|
||||||
|
|
||||||
inline
|
inline
|
||||||
char const* str_width( u8 width )
|
char const* str_width( Width width )
|
||||||
{
|
{
|
||||||
switch ( width )
|
switch ( width )
|
||||||
{
|
{
|
||||||
@ -291,16 +151,20 @@ namespace Field
|
|||||||
return "Word";
|
return "Word";
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_INVALID_VALUE;
|
return Msg_Invalid_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://i.imgur.com/Job2oPd.png
|
// https://i.imgur.com/Job2oPd.png
|
||||||
ct u8 Mode_Mem = 0b00000000;
|
enum Mode : u8
|
||||||
ct u8 Mode_Mem8 = 0b01000000;
|
{
|
||||||
ct u8 Mode_Mem16 = 0b10000000;
|
Mask_Mode = 0b11000000,
|
||||||
ct u8 Mode_Reg = 0b11000000;
|
Mode_Mem = 0b00000000,
|
||||||
|
Mode_Mem8 = 0b01000000,
|
||||||
|
Mode_Mem16 = 0b10000000,
|
||||||
|
Mode_Reg = 0b11000000,
|
||||||
|
};
|
||||||
|
|
||||||
char const* str_mode( u8 mode )
|
char const* str_mode( Mode mode )
|
||||||
{
|
{
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
@ -317,7 +181,7 @@ namespace Field
|
|||||||
return "Register";
|
return "Register";
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSG_INVALID_VALUE;
|
return Msg_Invalid_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -352,10 +216,8 @@ namespace Register
|
|||||||
D_Entry( SI ) \
|
D_Entry( SI ) \
|
||||||
D_Entry( DI ) \
|
D_Entry( DI ) \
|
||||||
|
|
||||||
using Type = u8;
|
enum Type : u8
|
||||||
enum
|
|
||||||
{
|
{
|
||||||
// Endianness is prob wrong...
|
|
||||||
AL = 0b000,
|
AL = 0b000,
|
||||||
CL = 0b001,
|
CL = 0b001,
|
||||||
DL = 0b010,
|
DL = 0b010,
|
||||||
@ -415,7 +277,7 @@ namespace Register
|
|||||||
"Destination.Index",
|
"Destination.Index",
|
||||||
};
|
};
|
||||||
|
|
||||||
return Type_To_Intuitive[ type + 8 * Width ];
|
return Type_To_Intuitive[ type + Width * 7 + 1 ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,69 +296,75 @@ struct POD_Instruction
|
|||||||
|
|
||||||
struct Instruction : public POD_Instruction
|
struct Instruction : public POD_Instruction
|
||||||
{
|
{
|
||||||
|
using Code = Op::Code;
|
||||||
|
using Direction = Field::Direction;
|
||||||
|
using Mode = Field::Mode;
|
||||||
|
using Width = Field::Width;
|
||||||
|
using Reg = Register::Type;
|
||||||
|
|
||||||
inline
|
inline
|
||||||
u8 direction()
|
Direction direction()
|
||||||
{
|
{
|
||||||
u8 direction = Byte_1 & Field::Mask_Dir;
|
Direction
|
||||||
|
direction = cast(Direction, Byte_1 & Field::Mask_Dir);
|
||||||
|
|
||||||
return direction;
|
return direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
u8 mode()
|
Mode mode()
|
||||||
{
|
{
|
||||||
u8 mode = Byte_2 & Field::Mask_Mode;
|
Mode mode = cast( Mode, Byte_2 & Field::Mask_Mode );
|
||||||
|
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
u8 opcode()
|
Code opcode()
|
||||||
{
|
{
|
||||||
u8
|
Op::Code
|
||||||
opcode = Byte_1 & Op::Mask;
|
opcode = cast( Op::Code, Byte_1 & Op::Mask );
|
||||||
|
|
||||||
return opcode;
|
return opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
u8 operand_left()
|
Reg operand_left()
|
||||||
{
|
{
|
||||||
u8
|
u8
|
||||||
operand = Byte_2 & Register::Mask_Left;
|
operand = Byte_2 & Register::Mask_Left;
|
||||||
operand >>= 3;
|
operand >>= 3;
|
||||||
|
|
||||||
return operand;
|
return cast(Reg, operand);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
u8 operand_right()
|
Reg operand_right()
|
||||||
{
|
{
|
||||||
u8
|
u8 operand = Byte_2 & Register::Mask_Right;
|
||||||
operand = Byte_2 & Register::Mask_Right;
|
|
||||||
// operand <<= 1;
|
|
||||||
|
|
||||||
return operand;
|
return cast( Reg, operand );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
u8 width()
|
Width width()
|
||||||
{
|
{
|
||||||
u8 width = Byte_1 & Field::Mask_Width;
|
Width width = cast( Width, Byte_1 & Field::Mask_Width );
|
||||||
|
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disassemble()
|
void dissassemble( zpl_string* result_out )
|
||||||
{
|
{
|
||||||
using namespace Field;
|
using namespace Field;
|
||||||
using namespace Op;
|
using namespace Op;
|
||||||
using namespace Register;
|
using namespace Register;
|
||||||
|
|
||||||
u8 width_val = width();
|
Direction dir = direction();
|
||||||
|
Width width_val = width();
|
||||||
|
|
||||||
char const* opcode_str = Op::meumonic( opcode() );
|
char const* opcode_str = Op::meumonic( opcode() );
|
||||||
char const* direction_str = Field::str_direction( direction() );
|
char const* direction_str = Field::str_direction( dir );
|
||||||
char const* width_str = Field::str_width( width_val );
|
char const* width_str = Field::str_width( width_val );
|
||||||
char const* mode_str = Field::str_mode( mode() );
|
char const* mode_str = Field::str_mode( mode() );
|
||||||
char const* operand_left_str = Register::meumonic( operand_left(), width_val );
|
char const* operand_left_str = Register::meumonic( operand_left(), width_val );
|
||||||
@ -506,10 +374,11 @@ struct Instruction : public POD_Instruction
|
|||||||
binary_string[9];
|
binary_string[9];
|
||||||
binary_string[8] = '\0';
|
binary_string[8] = '\0';
|
||||||
|
|
||||||
|
#if Build_Debug
|
||||||
str_binary( binary_string, opcode() );
|
str_binary( binary_string, opcode() );
|
||||||
zpl_printf("\nOpcode : %s : %s", binary_string, opcode_str);
|
zpl_printf("\nOpcode : %s : %s", binary_string, opcode_str);
|
||||||
|
|
||||||
str_binary( binary_string, direction() );
|
str_binary( binary_string, dir );
|
||||||
zpl_printf("\nDirection : %s : %s", binary_string, direction_str);
|
zpl_printf("\nDirection : %s : %s", binary_string, direction_str);
|
||||||
|
|
||||||
str_binary( binary_string, width_val );
|
str_binary( binary_string, width_val );
|
||||||
@ -523,107 +392,124 @@ struct Instruction : public POD_Instruction
|
|||||||
|
|
||||||
str_binary( binary_string, operand_right() );
|
str_binary( binary_string, operand_right() );
|
||||||
zpl_printf("\nOperand EA : %s : %s", binary_string, operand_right_str);
|
zpl_printf("\nOperand EA : %s : %s", binary_string, operand_right_str);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( result_out == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( * result_out == nullptr )
|
||||||
|
* result_out = zpl_string_make_reserve( allocator, zpl_kilobytes(1) );
|
||||||
|
|
||||||
|
zpl_string assembly = zpl_string_make_reserve( allocator, 32);
|
||||||
|
|
||||||
|
assembly = zpl_string_sprintf( allocator, assembly, zpl_kilobytes(1) - 1, "\n%s %s, %s"
|
||||||
|
, opcode_str
|
||||||
|
, dir == Dir_Src ? operand_right_str : operand_left_str
|
||||||
|
, dir == Dir_Src ? operand_left_str : operand_right_str
|
||||||
|
);
|
||||||
|
|
||||||
|
* result_out = zpl_string_append( * result_out, assembly );
|
||||||
|
|
||||||
|
#if Build_Debug
|
||||||
|
zpl_printf("\n\nAssembly: %s\n\n", assembly);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Tests
|
namespace Tests
|
||||||
{
|
{
|
||||||
zpl_arena BlobArena {};
|
void try_mock_instruction()
|
||||||
void Init()
|
|
||||||
{
|
|
||||||
zpl_arena_init_from_allocator( & BlobArena, zpl_heap(), zpl_megabytes(1) );
|
|
||||||
|
|
||||||
if ( BlobArena.total_size == 0 )
|
|
||||||
{
|
|
||||||
zpl_assert_crash( "Failed to reserve memory for Tests:: BLobArena" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Try_MockInstruction()
|
|
||||||
{
|
{
|
||||||
using namespace Field;
|
using namespace Field;
|
||||||
using namespace Op;
|
using namespace Op;
|
||||||
using namespace Register;
|
using namespace Register;
|
||||||
|
|
||||||
Instruction
|
Instruction
|
||||||
mock; // mov AX, BX
|
mock; // mov CX, BX
|
||||||
#if USE_LOOKUP_TABLE
|
mock.Byte_1 = mov_88 | Dir_Src | Field::Width_Word;
|
||||||
mock.Byte_1 = Op::code(mov_88) | Dir_REG_Dest | Field::Width_Word;
|
mock.Byte_2 = Field::Mode_Reg | effective_address(BX) | CX;
|
||||||
#else
|
|
||||||
mock.Byte_1 = mov_88 | Dir_REG_Src | Field::Width_Word;
|
|
||||||
#endif
|
|
||||||
mock.Byte_2 = Field::Mode_Reg | Field::mask_reg_operand(BX) | CX;
|
|
||||||
|
|
||||||
zpl_printf("\n\nAttempting Mock Instruction: mov CX, BX");
|
zpl_printf("\n\nAttempting Mock Instruction: mov CX, BX");
|
||||||
|
|
||||||
char
|
print_nl();
|
||||||
binary_string[9];
|
print_as_binary( & mock.Byte_1, 1, " " );
|
||||||
binary_string[8] = '\0';
|
print_as_binary( & mock.Byte_2, 1, " " );
|
||||||
|
print_nl();
|
||||||
|
|
||||||
str_binary( binary_string, mock.Byte_1 );
|
zpl_string dissasembly = nullptr;
|
||||||
zpl_printf("\n%s", binary_string);
|
|
||||||
|
mock.dissassemble( & dissasembly);
|
||||||
str_binary( binary_string, mock.Byte_2 );
|
|
||||||
zpl_printf("\n%s", binary_string);
|
|
||||||
|
|
||||||
mock.disassemble();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Try_Blob_SingleRegisterMove()
|
void try_blob_single_instruction()
|
||||||
{
|
{
|
||||||
zpl_printf("\n\nAttempting to read blob: listing_0037_single_register_mov");
|
zpl_printf("\n\nAttempting to read blob: listing_0037_single_register_mov");
|
||||||
|
|
||||||
zpl_file_contents
|
zpl_file_contents
|
||||||
blob = zpl_file_read_contents( zpl_arena_allocator( & BlobArena), false,
|
blob = zpl_file_read_contents( allocator, false, "tests/listing_0037_single_register_mov" );
|
||||||
"tests/listing_0037_single_register_mov"
|
|
||||||
// "tests/listing_0038_many_register_mov"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (blob.data == nullptr )
|
if (blob.data == nullptr )
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
printf("\nContents:\n");
|
|
||||||
|
|
||||||
u32 left = blob.size;
|
u32 left = blob.size;
|
||||||
u8* data = cast(u8*)blob.data
|
u8* data = cast( u8*, blob.data );
|
||||||
// + blob.size - 1
|
|
||||||
;
|
|
||||||
|
|
||||||
char
|
print_nl();
|
||||||
binary_string[9];
|
print_as_binary( data, left, " " );
|
||||||
binary_string[8] = '\0';
|
print_nl();
|
||||||
|
|
||||||
while ( left-- )
|
zpl_string dissasembly = nullptr;
|
||||||
{
|
|
||||||
str_binary( binary_string, data[0]);
|
|
||||||
|
|
||||||
printf("%s\n", binary_string );
|
|
||||||
|
|
||||||
data += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
left = blob.size;
|
|
||||||
// data += blob.size;
|
|
||||||
data -= blob.size;
|
|
||||||
while ( left-- )
|
|
||||||
{
|
|
||||||
str_binary( binary_string, data[0]);
|
|
||||||
|
|
||||||
printf("%X", data[0] );
|
|
||||||
|
|
||||||
data += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instruction
|
Instruction
|
||||||
instr;
|
instr;
|
||||||
instr.Byte_1 = ((u8*)blob.data)[0];
|
instr.Byte_1 = data[0];
|
||||||
instr.Byte_2 = ((u8*)blob.data)[1];
|
instr.Byte_2 = data[1];
|
||||||
instr.disassemble();
|
instr.dissassemble( & dissasembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void try_blob_many_instructions()
|
||||||
|
{
|
||||||
|
zpl_printf("\n\nAttempting to read blob: listing_0038_many_register_mov");
|
||||||
|
|
||||||
|
zpl_file_contents
|
||||||
|
blob = zpl_file_read_contents( allocator, false, "tests/listing_0038_many_register_mov" );
|
||||||
|
|
||||||
|
if (blob.data == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
u32 left = blob.size;
|
||||||
|
u8* data = cast( u8*, blob.data );
|
||||||
|
|
||||||
|
print_nl();
|
||||||
|
print_as_binary( data, left, " " );
|
||||||
|
print_nl();
|
||||||
|
|
||||||
|
zpl_string dissasembly = zpl_string_make( allocator, "bits 16\n");
|
||||||
|
|
||||||
|
while ( left )
|
||||||
|
{
|
||||||
|
Instruction
|
||||||
|
instr;
|
||||||
|
instr.Byte_1 = data[0];
|
||||||
|
instr.Byte_2 = data[1];
|
||||||
|
instr.dissassemble( & dissasembly);
|
||||||
|
|
||||||
|
data += 2;
|
||||||
|
left -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
zpl_printf("\n\nDissassemlby:\n%s", dissasembly);
|
||||||
|
dissasembly = zpl_string_append_fmt( dissasembly, "\n" );
|
||||||
|
|
||||||
|
zpl_printf("\n\nSaving to file");
|
||||||
|
zpl_file_write_contents("tests/listing_0038_many_register_mov.out.asm"
|
||||||
|
, dissasembly
|
||||||
|
, zpl_string_length(dissasembly)
|
||||||
|
, nullptr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef allocator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -631,17 +517,23 @@ int main()
|
|||||||
{
|
{
|
||||||
zpl_printf("sim 8086!");
|
zpl_printf("sim 8086!");
|
||||||
|
|
||||||
Tests::Init();
|
setup();
|
||||||
|
|
||||||
zpl_f64 start = zpl_time_rel();
|
zpl_f64 start = zpl_time_rel();
|
||||||
|
|
||||||
Tests::Try_MockInstruction();
|
#if 0
|
||||||
Tests::Try_Blob_SingleRegisterMove();
|
Tests::try_mock_instruction();
|
||||||
|
Tests::try_blob_single_instruction();
|
||||||
|
#endif
|
||||||
|
Tests::try_blob_many_instructions();
|
||||||
|
|
||||||
zpl_f64 end = zpl_time_rel();
|
zpl_f64 end = zpl_time_rel();
|
||||||
|
zpl_f64 ms = (end - start) * 100;
|
||||||
|
|
||||||
printf("\n\nElapsed Time: %lf", end - start);
|
printf("\n\nElapsed Time: %lf ms", ms);
|
||||||
printf("\n\n");
|
printf("\n\n");
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
@echo off
|
|
||||||
|
|
||||||
echo Assembling: listing_0037_single_register_mov.asm
|
|
||||||
call nasm ".\tests\listing_0037_single_register_mov.asm"
|
|
||||||
|
|
||||||
|
|
||||||
echo Assembling: listing_0038_many_register_mov.asm
|
|
||||||
call nasm ".\tests\listing_0038_many_register_mov.asm"
|
|
13
part_1/tests/listing_0038_many_register_mov.out.asm
Normal file
13
part_1/tests/listing_0038_many_register_mov.out.asm
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
bits 16
|
||||||
|
|
||||||
|
mov CX, BX
|
||||||
|
mov DH, CH
|
||||||
|
mov DX, BX
|
||||||
|
mov SI, BX
|
||||||
|
mov BX, DI
|
||||||
|
mov CL, DL
|
||||||
|
mov DH, DH
|
||||||
|
mov BX, AX
|
||||||
|
mov BX, SI
|
||||||
|
mov SP, DI
|
||||||
|
mov BP, AX
|
Loading…
Reference in New Issue
Block a user