96256d0f76045c879ba8bd57db149e26b59e1c7c
[ned1] / neddis / neddis.c
/*
* © 2018 Aaron Taylor <ataylor at subgeniuskitty dot com>
* See LICENSE.txt file for copyright and license details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define VERSION 1
enum syllables {
MVSTCK = 0b00001111,
JMP = 0b00001110,
SWAP = 0b00001101,
ADD = 0b00001100,
XOR = 0b00001011,
NOT = 0b00001010,
OR = 0b00001001,
AND = 0b00001000,
BRZ = 0b00000111,
TEST = 0b00000110,
CMPSWP = 0b00000101,
SHIFT = 0b00000100,
STORE = 0b00000011,
LOAD = 0b00000010,
NOP = 0b00000001,
HALT = 0b00000000
};
#define WIDTH_MNEMONICS 14
/*
* Output format:
* 10 characters for address in hexadecimal
* 4 spaces
* 10 characters for hex dump of 32-bit word
* 4 spaces
* 40 characters for binary representation of 32-bit word
* 4 spaces
* remainder of line for mnemonics
*/
void
print_header(void)
{
printf(" Offset || Hex || Binary "
" || Description\n"
"============================================================"
"============================================================"
"===================\n");
}
void
print_usage(char ** argv)
{
printf( "NED Disassembler v%d (www.subgeniuskitty.com)\n"
"Usage: %s -i <file>\n"
" -h Help (prints this message)\n"
" -i <file> Specify a binary image file to disassemble.\n"
, VERSION, argv[0]
);
}
void
print_formatA_binary(uint32_t word)
{
printf("1 ");
int chunk_length = 0;
for (int bit_index = 30; bit_index >= 0; bit_index--) {
/* Insert space every 8 bits. Leading space is intentional. */
if ((chunk_length++ % 8) == 0) printf(" ");
if ((word >> bit_index) & 0b1) {
printf("1");
} else {
printf("0");
}
}
printf(" ");
}
void
print_formatA_mnemonics(uint32_t word)
{
int position;
printf("WORD =====>%n", &position);
while (position++ != WIDTH_MNEMONICS) printf(" ");
printf("0x%x%n", ((word & 0b01111111111111111111111111111111) << 1), &position);
while (position++ != WIDTH_MNEMONICS) printf(" ");
printf("0%o%n", ((word & 0b01111111111111111111111111111111) << 1), &position);
while (position++ != WIDTH_MNEMONICS) printf(" ");
printf("%u%n", ((word & 0b01111111111111111111111111111111) << 1), &position);
while (position++ != WIDTH_MNEMONICS) printf(" ");
}
uint8_t
extract_syllable_from_word(uint32_t word, uint8_t index)
{
uint32_t mask = 0b111111 << 6*(4-index);
return (word & mask) >> 6*(4-index);
}
void
print_formatC_binary(uint32_t word)
{
printf("00 ");
for (int syllable_index = 0; syllable_index < 5; syllable_index++) {
uint8_t syllable = extract_syllable_from_word(word, syllable_index);
for (int i = 5; i >= 0; i--) {
if (((syllable >> i) & 0b1) == 1) {
printf("1");
} else {
printf("0");
}
}
printf(" ");
}
printf(" ");
}
void
print_formatC_mnemonics(uint32_t word)
{
for (int syllable_index = 0; syllable_index < 5; syllable_index++) {
int position = 0;
uint8_t syllable = extract_syllable_from_word(word, syllable_index);
if (syllable & 0b100000) { /* Check the first bit of the syllable. 1 means IM_x. */
printf("IM_%d%n", (syllable & 0b11111), &position);
} else if (syllable & 0b10000) { /* 1 in 2nd bit means LDSP+x or STSP+x instruction. */
if (syllable & 0b1000) { /* LDSP+x */
printf("LDSP+%d%n", (syllable & 0b111), &position);
} else { /* STSP+x */
printf("STSP+%d%n", (syllable & 0b111), &position);
}
} else {
switch (syllable) {
case AND: printf("AND%n", &position); break;
case OR: printf("OR%n", &position); break;
case NOT: printf("NOT%n", &position); break;
case XOR: printf("XOR%n", &position); break;
case ADD: printf("ADD%n", &position); break;
case MVSTCK: printf("MVSTCK%n", &position); break;
case SHIFT: printf("SHIFT%n", &position); break;
case CMPSWP: printf("CMPSWP%n", &position); break;
case TEST: printf("TEST%n", &position); break;
case BRZ: printf("BRZ%n", &position); break;
case LOAD: printf("LOAD%n", &position); break;
case STORE: printf("STORE%n", &position); break;
case NOP: printf("NOP%n", &position); break;
case HALT: printf("HALT%n", &position); break;
case JMP: printf("JMP%n", &position); break;
case SWAP: printf("SWAP%n", &position); break;
default: printf("?ERR?%n", &position); break;
}
}
while (position++ != WIDTH_MNEMONICS) printf(" ");
}
}
int
main(int argc, char ** argv)
{
/*
* Process command line arguments
*/
int c;
FILE * input = NULL;
while ((c = getopt(argc,argv,"i:h")) != -1) {
switch (c) {
case 'i':
if ((input = fopen(optarg, "r")) == NULL) {
fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
}
break;
case 'h':
print_usage(argv);
exit(EXIT_SUCCESS);
break;
default:
break;
}
}
if (input == NULL) {
fprintf(stderr, "ERROR: Must specify a binary image file with -i flag.\n");
print_usage(argv);
exit(EXIT_FAILURE);
}
/*
* Main Loop
*/
print_header();
uint32_t word;
uint32_t offset = 0;
/* Since all NED instructions are one word (4 bytes) wide, read in one word increments. */
while (fread(&word, 4, 1, input)) {
printf("0x%08x", offset);
printf(" ");
printf("0x%08x", word);
printf(" ");
if (word & (0b1 << 31)) { /* Format A instruction word */
print_formatA_binary(word);
printf(" ");
print_formatA_mnemonics(word);
} else if ((word & (0b11 << 30)) == 0) { /* Format C instruction word */
print_formatC_binary(word);
printf(" ");
print_formatC_mnemonics(word);
} else {
fprintf(stderr, "ERROR: Malformed instruction word: %o\n", word);
exit(EXIT_FAILURE);
}
printf("\n");
offset += 4; /* Increment by one word (4 bytes). */
}
exit(EXIT_SUCCESS);
}