Created
November 7, 2011 20:47
-
-
Save clausecker/1346119 to your computer and use it in GitHub Desktop.
Pretty printer for MMIX opcodes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <inttypes.h> | |
#include "pretty_print.h" | |
const char *opcodes[256] = { | |
"trap","fcmp","fun","feql","fadd","fix","fsub","fixu", /* 0x0# */ | |
"flot","flot","flotu","flotu","sflot","sflot","sflotu","sflotu", | |
"fmul","fcmpe","fune","feqle","fdiv","fsqrt","frem","fint", /* 0x1# */ | |
"mul","mul","mulu","mulu","div","div","divu","divu", | |
"add","add","addu","addu","sub","sub","subu","subu", /* 0x2# */ | |
"2addu","2addu","4addu","4addu","8addu","8addu","16addu","16addu", | |
"cmp","cmp","cmpu","cmpu","neg","neg","negu","negu", /* 0x3# */ | |
"sl","sl","slu","slu","sr","sr","sru","sru", | |
"bn","bn","bz","bz","bp","bp","bod","bod", /* 0x4# */ | |
"bnn","bnn","bnz","bnz","bnp","bnp","bev","bev", | |
"pbn","pbn","pbz","pbz","pbp","pbp","pbod","pbod", /* 0x5# */ | |
"pbnn","pbnn","pbnz","pbnz","pbnp","pbnp","pbev","pbev", | |
"csn","csn","csz","csz","csp","csp","csod","csod", /* 0x6# */ | |
"csnn","csnn","csnz","csnz","csnp","csnp","csev","csev", | |
"zsn","zsn","zsz","zsz","zsp","zsp","zsod","zsod", /* 0x7# */ | |
"zsnn","zsnn","zsnz","zsnz","zsnp","zsnp","zsev","zsev", | |
"ldb","ldb","ldbu","ldbu","ldw","ldw","ldwu","ldwu", /* 0x8# */ | |
"ldt","ldt","ldtu","ldtu","ldo","ldo","ldou","ldou", | |
"ldsf","ldsf","ldht","ldht","cswap","cswap","ldunc","ldunc", /* 0x9# */ | |
"ldvts","ldvts","preld","preld","prego","prego","go","go", | |
"stb","stb","stbu","stbu","stw","stw","stwu","stwu", /* 0xA# */ | |
"stt","stt","sttu","sttu","sto","sto","stou","stou", | |
"stsf","stsf","stht","stht","stco","stco","stunc","stunc", /* 0xB# */ | |
"syncd","syncd","prest","prest","syncid","syncid","pushgo","pushgo", | |
"or","or","orn","orn","nor","nor","xor","xor", /* 0xC# */ | |
"and","and","andn","andn","nand","nand","nxor","nxor", | |
"bdif","bdif","wdif","wdif","tdif","tdif","odif","odif", /* 0xD# */ | |
"mux","mux","sadd","sadd","mor","mor","mxor","mxor", | |
"seth","setmh","setml","setl","inch","incmh","incml","incl", /* 0xE# */ | |
"orh","ormh","orml","orl","andnh","andnmh","andnml","andnl", | |
"jmp","jmp","pushj","pushj","geta","geta","put","put", /* 0xF# */ | |
"pop","resume","save","unsave","sync","swym","get","trip" | |
}; | |
/* kinds of arguments and format strings | |
* S#: register number, e.g. $123 | |
* #: 8-bit unsigned, e.g. #1F | |
* ##: the same, 16 Bit, e.g. #1337 | |
* ###: the same, 24 Bit, e.g. #1F2E3D | |
* F##: relative 16-bit adress, forwards, e.g.. @+4*#1234 | |
* B##: the same, backwards, z.B. @-4*#1234 | |
* F###, B###: the same, 24 Bit | |
* R#: special register, z.B. rH | |
* ROUND: rounding mode, string contains comma | |
*/ | |
enum op_type { | |
OP_SX_SY_SZ, | |
OP_SX_SY_Z, | |
OP_SX_Y_SZ, | |
OP_SX_Y_Z, | |
OP_X_SY_SZ, | |
OP_X_SY_Z, | |
/* OP_X_Y_SZ, */ | |
/* OP_X_Y_Z, */ | |
OP_SX_YZ, | |
OP_XYZ, | |
#define IS_SIMPLE_ARGF(x) ((x) <= OP_XYZ) | |
/* complicated argument formats */ | |
OP_SX_ROUND_SZ, | |
OP_SX_ROUND_Z, | |
OP_SX_FYZ, | |
OP_SX_BYZ, | |
OP_FXYZ, | |
OP_BXYZ, | |
OP_RX_SZ, | |
OP_RX_Z, | |
OP_SX, | |
OP_SZ, | |
OP_SX_RZ, | |
/* failback mode, if illegal argument format. Never occurs in argformats */ | |
OP_SX_Z, | |
OP_X_SZ, | |
OP_X_Z | |
}; | |
static const char *opfstrings[] = { | |
[OP_SX_SY_SZ] = "$%hu,$%hu,$%hu\n", | |
[OP_SX_SY_Z] = "$%hu,$%hu,#%02hx\n", | |
[OP_SX_Y_SZ] = "$%hu,#%02hx,$%hu\n", | |
[OP_SX_Y_Z] = "$%hu,#%02hx,#%02hx\n", | |
[OP_X_SY_SZ] = "#%02hx,$%hu,$%hu\n", | |
[OP_X_SY_Z] = "#%02hx,$%hu,#%02hx\n", | |
/* [OP_X_Y_SZ] = "#%02hx,#%02hx,$%hu\n", */ | |
/* [OP_X_Y_Z] = "#%02hx,#%02hx,#%02hx\n", */ | |
[OP_SX_YZ] = "$%hu,#%02hx%02hx\n", | |
[OP_XYZ] = "#%02hx%02hx%02hx\n", | |
[OP_SX_ROUND_SZ] = "$%hu,%s$%hu\n", | |
[OP_SX_ROUND_Z] = "$%hu,%s%02hx\n", | |
/* x, abs(yz), absolute adress */ | |
[OP_SX_FYZ] = "$%hu,@+4*#%04" PRIx64 " <%016" PRIx64 ">\n", | |
[OP_SX_BYZ] = "$%hu,@-4*#%04" PRIx64" <%016" PRIx64 ">\n", | |
[OP_FXYZ] = "@+4*#%06" PRIx64" <%016" PRIx64 ">\n", | |
[OP_BXYZ] = "@-4*#%06" PRIx64" <%016" PRIx64 ">\n", | |
[OP_RX_SZ] = "%s,$%hu\n", | |
[OP_RX_Z] = "%s,#%02hx\n", | |
[OP_SX] = "$%hu\n", | |
[OP_SZ] = "$%hu\n", | |
[OP_SX_RZ] = "$%hu,%s\n", | |
[OP_SX_Z] = "$%hu,#%02hx\n", | |
[OP_X_SZ] = "#%02hx,$%hu\n", | |
[OP_X_Z] = "#%02hx,%02hx\n" | |
}; | |
/* helpful macros */ | |
#define OP_ROUND_PAIR OP_SX_ROUND_SZ, OP_SX_ROUND_Z, | |
#define OP_STD_PAIR OP_SX_SY_SZ, OP_SX_SY_Z, | |
#define OP_STD_ROW OP_STD_PAIR OP_STD_PAIR OP_STD_PAIR OP_STD_PAIR | |
#define OP_BR_PAIR OP_SX_FYZ, OP_SX_BYZ, | |
#define OP_BR_ROW OP_BR_PAIR OP_BR_PAIR OP_BR_PAIR OP_BR_PAIR | |
#define OP_SX_YZ_ROW OP_SX_YZ, OP_SX_YZ, OP_SX_YZ, OP_SX_YZ, \ | |
OP_SX_YZ, OP_SX_YZ, OP_SX_YZ, OP_SX_YZ, | |
/* argument formats to the opcodes, grouped by 32 opcodes */ | |
static const unsigned char argformats[256] = { | |
/* trap */ OP_XYZ, | |
/* fcmp */ OP_SX_SY_SZ, | |
/* fun */ OP_SX_SY_SZ, | |
/* feql */ OP_SX_SY_SZ, | |
/* fadd */ OP_SX_SY_SZ, | |
/* fix */ OP_SX_ROUND_SZ, | |
/* fsub */ OP_SX_SY_SZ, | |
/* fixu */ OP_SX_ROUND_SZ, | |
/* flot */ OP_ROUND_PAIR | |
/* flotu */ OP_ROUND_PAIR | |
/* sflot */ OP_ROUND_PAIR | |
/* sflotu */ OP_ROUND_PAIR | |
/* fmul */ OP_SX_SY_SZ, | |
/* fcmpe */ OP_SX_SY_SZ, | |
/* fune */ OP_SX_SY_SZ, | |
/* feqle */ OP_SX_SY_SZ, | |
/* fdiv */ OP_SX_SY_SZ, | |
/* fsqrt */ OP_SX_ROUND_SZ, | |
/* frem */ OP_SX_SY_SZ, | |
/* fint */ OP_SX_ROUND_SZ, | |
/* mul - divu */ OP_STD_ROW | |
/* add - 16addu */ OP_STD_ROW OP_STD_ROW | |
/* cmp */ OP_STD_PAIR | |
/* cmpu */ OP_STD_PAIR | |
/* neg */ OP_SX_Y_SZ, OP_SX_Y_Z, | |
/* negu */ OP_SX_Y_SZ, OP_SX_Y_Z, | |
/* sl - sru */ OP_STD_ROW | |
/* bn - bev */ OP_BR_ROW OP_BR_ROW | |
/* pbn - pbev */ OP_BR_ROW OP_BR_ROW | |
/* csn - csev */ OP_STD_ROW OP_STD_ROW | |
/* zsn - zsev */ OP_STD_ROW OP_STD_ROW | |
/* ldb - ldou */ OP_STD_ROW OP_STD_ROW | |
/* ldsf - go */ OP_STD_ROW OP_STD_ROW | |
/* stb - stou */ OP_STD_ROW OP_STD_ROW | |
/* stsf */ OP_STD_PAIR | |
/* stht */ OP_STD_PAIR | |
/* stco */ OP_X_SY_SZ, OP_X_SY_Z, | |
/* stunc */ OP_STD_PAIR | |
/* syncd - pushgo */ OP_STD_ROW | |
/* or - nxor */ OP_STD_ROW OP_STD_ROW | |
/* bdif - mxor */ OP_STD_ROW OP_STD_ROW | |
/* seth - andnl */ OP_SX_YZ_ROW OP_SX_YZ_ROW | |
/* jmp */ OP_FXYZ, OP_BXYZ, | |
/* pushj */ OP_BR_PAIR | |
/* geta */ OP_BR_PAIR | |
/* put */ OP_RX_SZ, OP_RX_Z, | |
/* pop */ OP_SX_YZ, | |
/* resume */ OP_XYZ, | |
/* save */ OP_SX, | |
/* unsave */ OP_SZ, | |
/* sync */ OP_XYZ, | |
/* swym */ OP_XYZ, | |
/* get */ OP_SX_RZ, | |
/* trip */ OP_XYZ | |
}; | |
const char *special_regs[NUM_SPECIAL_REGS] = { | |
"rB","rD","rE","rH","rJ","rM","rR","rBB", | |
"rC","rN","rO","rS","rI","rT","rTT","rK", | |
"rQ","rU","rV","rG","rL","rA","rF","rP", | |
"rW","rX","rY","rZ","rWW","rXX","rYY","rZZ" | |
}; | |
const char *rounding_modes[NUM_ROUNDING_MODES] = { | |
",", | |
"ROUND_OFF,", | |
"ROUND_UP,", | |
"ROUND_DOWN,", | |
"ROUND_NEAR," | |
}; | |
extern void printOp(const char *buffer,uint64_t address) { | |
unsigned char opcode = buffer[0], | |
x = buffer[1], | |
y = buffer[2], | |
z = buffer[3], | |
argf = argformats[opcode]; | |
int64_t offset; | |
printf("#%016" PRIx64 " %02hx%02hx%02hx%02hx %-6s ", | |
address,opcode,x,y,z,opcodes[opcode]); | |
if (IS_SIMPLE_ARGF(argf)) | |
printf(opfstrings[argf],x,y,z); | |
else switch (argf) { | |
case OP_SX_ROUND_SZ: | |
case OP_SX_ROUND_Z: | |
if (y >= NUM_ROUNDING_MODES) { | |
argf = argf == OP_SX_ROUND_SZ ? OP_SX_Y_SZ : OP_SX_Y_Z; | |
printf(opfstrings[argf],x,y,z); | |
} else | |
printf(opfstrings[argf],x,rounding_modes[y],z); | |
break; | |
case OP_SX: | |
case OP_SZ: printf(opfstrings[argf],(argf == OP_SX ? x : z)); break; | |
case OP_SX_RZ: | |
if (z >= NUM_SPECIAL_REGS) printf(opfstrings[OP_SX_Z],x,z); | |
else printf(opfstrings[argf],x,special_regs[z]); break; | |
case OP_RX_SZ: | |
case OP_RX_Z: | |
if (x >= NUM_SPECIAL_REGS) | |
printf(opfstrings[argf == OP_RX_Z ? OP_X_Z : OP_X_SZ],x,z); | |
else | |
printf(opfstrings[argf],special_regs[x],z); | |
break; | |
case OP_SX_FYZ: | |
case OP_SX_BYZ: | |
offset = (y << 8) + z; | |
offset = argf == OP_SX_FYZ ? offset : (1 << 16) - offset; | |
printf(opfstrings[argf],x, | |
(uint64_t)offset < 0 ? -offset : offset, | |
address + 4*offset); | |
break; | |
case OP_FXYZ: | |
case OP_BXYZ: | |
offset = (x << 16) + (y << 8) + z; | |
offset = argf == OP_FXYZ ? offset : (1 << 24) - offset; | |
printf(opfstrings[argf], | |
(uint64_t)offset < 0 ? -offset : offset, | |
address + 4*offset); | |
break; | |
} | |
} | |
extern void printCode(const char* buffer, size_t count,uint64_t address) { | |
while(count > 4) { | |
printOp(buffer,address); | |
buffer += 4; | |
address += 4; | |
count -= 4; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef PRETTY_PRINT_H | |
#define PRETTY_PRINT_H | |
#include <stdint.h> | |
/* Pretty printer for mmix assembly instructions */ | |
/* reads exactly four bytes. No check against NULL */ | |
extern void printOp(const char*,uint64_t); | |
extern void printCode(const char*,size_t,uint64_t); | |
/* table containing opcode names */ | |
extern const char *opcodes[256]; | |
/* table containing special register's names */ | |
#define NUM_SPECIAL_REGS 32 | |
extern const char *special_regs[NUM_SPECIAL_REGS]; | |
/* table containg rounding modes */ | |
#define NUM_ROUNDING_MODES 5 | |
extern const char *rounding_modes[NUM_ROUNDING_MODES]; | |
#endif /* PRETTY_PRINT_H */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment