Skip to content

Instantly share code, notes, and snippets.

@clausecker
Created November 7, 2011 20:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clausecker/1346119 to your computer and use it in GitHub Desktop.
Save clausecker/1346119 to your computer and use it in GitHub Desktop.
Pretty printer for MMIX opcodes
#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;
}
}
#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