summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/apexc/apexcdsm.c
blob: 25a48f8a5316279539a8f3a465cbbee47eef044c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
    cpu/apexc/apexcsm.c : APE(X)C CPU disassembler

    By Raphael Nabet

    see cpu/apexc.c for background and tech info
*/


#include "emu.h"
#include "debugger.h"

#include "apexc.h"

/*
    Here is the format used for debugger output.

    Since the only assembler for the APEXC that I know of uses numerical data
    (yes, mnemonics are numbers), I do not know if there is an official way of writing
    APEXC assembly on a text terminal.  The format I chose is closely inspired by
    the assembly format found in Booth, but was slightly adapted to accommodate
    the lack of subscripts and of a 'greater or equal' character.

        Printed format                      Name
    0         1         2
    012345678901234567890123456
    Stop                (##/##)         one_address
    I                   (##/##)         one_address
    P                   (##/##)         one_address
    B        <(##/##) >=(##/##)         branch
    l (##)              (##/##)         shiftl
    r (##)              (##/##)         shiftr
    Illegal             (##/##)         one_address
    X (##)    (##)      (##/##)         multiply
    X         (##)      (##/##)         multiply
    +c        (##/##)   (##/##)         two_address
    -c        (##/##)   (##/##)         two_address
    +         (##/##)   (##/##)         two_address
    -         (##/##)   (##/##)         two_address
    T         (##/##)   (##/##)         two_address
    R  (1-##) (##/##)   (##/##)         store
    R (##-32) (##/##)   (##/##)         store
    R         (##/##)   (##/##)         store
    A  (1-##) (##/##)   (##/##)         store
    A (##-32) (##/##)   (##/##)         store
    A         (##/##)   (##/##)         store
    S         (##)      (##/##)         swap
    +--------++--------++-----+
    mnemonic   X field  Y field
     field

    For vector instructions, replace the first space on the right of the mnemonic
    with a 'v'.

    01-Feb-2010 (Robbbert):
    I've added the actual address, (as shown in the extreme left of the debugger
    output), so that you can see much easier how the program will flow. Example:

    +C  XXX(##/##)   XXX(##/##)

    The X value shows where the data word is located, and the Y value is the
    address of the next instruction.
*/
enum format_type {branch, shiftl, shiftr, multiply, store, swap, one_address, two_address};

struct instr_desc
{
	const char *mnemonic;
	format_type format;	/* -> X and Y are format */
};

static const instr_desc instructions[16] =
{
	{ "Stop",	one_address },	{ "I",		one_address },
	{ "P",		one_address },	{ "B",		branch },
	{ "l",		shiftl },		{ "r",		shiftr },
	{ "Illegal",one_address },	{ "X",		multiply },
	{ "+c",		two_address },	{ "-c",		two_address },
	{ "+",		two_address },	{ "-",		two_address },
	{ "T",		two_address },	{ "R",		store },
	{ "A",		store },		{ "S",		swap }
};

CPU_DISASSEMBLE( apexc )
{
	UINT32 instruction;			/* 32-bit machine instruction */
	int x, y, function, c6, vector;	/* instruction fields */
	int n;						/* 'friendly', instruction-dependant interpretation of C6 */
	const instr_desc *the_desc;	/* pointer to the revelant entry in the instructions array */
	char mnemonic[9];			/* storage for generated mnemonic */

	/* read the instruction to disassemble */
	instruction = oprom[0] << 24 | oprom[1] << 16 | oprom[2] << 8 | oprom[3];

	/* isolate the instruction fields */
	x = (instruction >> 22) & 0x3FF;
	y = (instruction >> 12) & 0x3FF;
	function = (instruction >> 7) & 0x1F;
	c6 = (instruction >> 1) & 0x3F;
	vector = instruction & 1;

	/* get the revelant entry in instructions */
	the_desc = & instructions[function >> 1];

	/* generate mnemonic : append a 'v' to the basic mnemonic if it is a vector instruction */
	sprintf(mnemonic, "%.*s%c", (int)sizeof(mnemonic)-2, the_desc->mnemonic, vector ? 'v' : ' ');

	/* print mnemonic and n immediate */
	switch (the_desc->format)
	{
	case one_address:
	case two_address:
	case branch:
	case swap:
		buffer += sprintf(buffer, "   %-10s", mnemonic);	/* 10 chars*/
		break;

	case shiftl:
	case shiftr:
		if (the_desc->format == shiftl)
			n = c6;
		else
			n = 64-c6;
		buffer += sprintf(buffer, "   %-2s(%2d)    ", mnemonic, n);	/* 10 chars */
		break;

	case multiply:
		n = 33-c6;
		if (n == 32)
			/* case "32" : do not show bit specifier */
			buffer += sprintf(buffer, "   %-10s", mnemonic);	/* 10 chars */
		else
			buffer += sprintf(buffer, "   %-2s(%2d)    ", mnemonic, n);	/* 10 chars */
		break;

	case store:
		if (c6 == 0)
		{	/* case "1-32" : do not show bit specifier */
			buffer += sprintf(buffer, "   %-10s", mnemonic);	/* 10 chars*/
		}
		else if (c6 & 0x20)
		{	/* case "1-n" */
			n = c6-32;
			buffer += sprintf(buffer, "   %-2s (1-%02d) ", mnemonic, n);	/* 10 chars */
		}
		else
		{	/* case "n-32" */
			n = c6+1;
			buffer += sprintf(buffer, "   %-2s(%02d-32) ", mnemonic, n);	/* 8 chars */
		}
	}

	/* print X address */
	switch (the_desc->format)
	{
	case branch:
		buffer--;	/* eat last char */
		buffer += sprintf(buffer, "<%03X(%02d/%02d) >=", x<<2, (x >> 5) & 0x1f, x & 0x1f);	/* 10+1 chars */
		break;

	case multiply:
	case swap:
		buffer += sprintf(buffer, "   (%02d)      ", (x >> 5) & 0x1f);	/* 10 chars */
		break;

	case one_address:
	case shiftl:
	case shiftr:
		buffer += sprintf(buffer, "             ");	/* 10 chars */
		break;

	case two_address:
	case store:
		buffer += sprintf(buffer, "%03X(%02d/%02d)   ", x<<2, (x >> 5) & 0x1f, x & 0x1f);	/* 10 chars */
		break;
	}

	/* print Y address */
	buffer += sprintf(buffer, "%03X(%02d/%02d)", y<<2, (y >> 5) & 0x1f, y & 0x1f);	/* 7 chars */

	return 4;
}