1 /**
2 Copyright: Copyright (c) 2013-2014 Andrey Penechko.
3 License: a$(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module emulator.dcpu.disassembler;
8 
9 import std.algorithm : joiner;
10 import std.conv : to;
11 import std..string : format;
12 import std.range : repeat;
13 
14 import emulator.dcpu.constants;
15 import emulator.dcpu.instruction;
16 import emulator.dcpu.memoryanalyzer;
17 
18 enum indentStr = "    ";
19 
20 string[] disassembleSome(ushort[] memory, MemoryMap memMap, ushort location = 0, ushort count = 0)
21 {
22 	uint pointer = location;
23 	ushort numInstructions = 0;
24 
25 	ushort nextWord()
26 	{
27 		if (pointer >= memory.length)
28 			return 0;
29 		else 
30 			return memory[pointer++];
31 	}
32 
33 	string[] lines;
34 
35 	ushort prevInstr = 0;
36 
37 	uint indentLevel;
38 	uint conditionIndentLevel;
39 
40 	auto indent()
41 	{
42 		return indentStr.repeat(indentLevel + conditionIndentLevel).joiner;
43 	}
44 
45 	void processInstr()
46 	{
47 		string instrStr;
48 
49 		uint address = pointer;
50 		ushort instr = memory[pointer++];
51 
52 		string literalDecoder(ushort literal)
53 		{
54 			if (auto transition = find!"a.from == b"(memMap.transitions, address))
55 			{
56 				if (transition.length && transition[0].target.position == literal)
57 				{
58 					return to!string(*(transition[0].target));
59 				}
60 			}
61 
62 			return plainLitDecoder(literal);
63 		}
64 
65 		// Place label if there is at current position
66 		if (auto labels = find!"(*a).position == b"(memMap.labels, address))
67 		{
68 			if (labels.length)
69 			{
70 				lines ~= "";
71 				lines ~= format("%04x  %s:", address, *labels[0]);
72 
73 				indentLevel = 1;
74 			}
75 		}
76 
77 		if (instr == 0)
78 		{
79 			prevInstr = 0;
80 			indentLevel = 0;
81 			conditionIndentLevel = 0;
82 			return;
83 		}
84 
85 		if (prevInstr >= 0x10 && prevInstr <= 0x17)
86 		{
87 			++conditionIndentLevel;
88 		}
89 
90 		if ((instr & 0x1F) != 0)
91 		{
92 			string a = decodeOperand!true(instr >> 10, nextWord(), &literalDecoder);
93 			string b = decodeOperand!false((instr >> 5) & 0x1F, nextWord(), &literalDecoder);
94 			
95 			instrStr = format("%04x  %s%s  %s, %s", address, indent, basicOpcodeNames[instr & 0x1F], b, a);
96 
97 			prevInstr = instr & 0x1F;
98 		}
99 		else if (((instr >> 5) & 0x1F) != 0)
100 		{
101 			instrStr = format("%04x  %s%s  %s", address,
102 				indent,
103 				specialOpcodeNames[(instr >> 5) & 0x1F],
104 				decodeOperand!true(instr >> 10, nextWord(), &literalDecoder));
105 			
106 			prevInstr = 0;
107 		}
108 		else
109 		{
110 			instrStr = format("%04x  %s%#02x %#02x, %#02x", address, indent, instr & 0x1F, (instr >> 5) & 0x1F, instr >> 10);
111 			
112 			prevInstr = 0;
113 		}
114 
115 		if (prevInstr < 0x10 || prevInstr > 0x17)
116 		{
117 			conditionIndentLevel = 0;
118 		}
119 
120 		lines ~= instrStr;
121 		++numInstructions;
122 	}
123 
124 	if (count > 0)
125 	{
126 		while(numInstructions < count && pointer < memory.length)
127 		{
128 			processInstr();
129 		}
130 	}
131 	else
132 	{
133 		while(pointer < memory.length)
134 		{
135 			processInstr();
136 		}
137 	}
138 
139 	return lines;
140 }