1 // license:BSD-3-Clause
2 // copyright-holders:Raphael Nabet
3 /*
4     cpu/apexc/apexcsm.c : APE(X)C CPU disassembler
5 
6     By Raphael Nabet
7 
8     see cpu/apexc.c for background and tech info
9 */
10 
11 
12 #include "emu.h"
13 #include "apexcdsm.h"
14 
15 /*
16     Here is the format used for debugger output.
17 
18     Since the only assembler for the APEXC that I know of uses numerical data
19     (yes, mnemonics are numbers), I do not know if there is an official way of writing
20     APEXC assembly on a text terminal.  The format I chose is closely inspired by
21     the assembly format found in Booth, but was slightly adapted to accommodate
22     the lack of subscripts and of a 'greater or equal' character.
23 
24         Printed format                      Name
25     0         1         2
26     012345678901234567890123456
27     Stop                (##/##)         one_address
28     I                   (##/##)         one_address
29     P                   (##/##)         one_address
30     B        <(##/##) >=(##/##)         branch
31     l (##)              (##/##)         shiftl
32     r (##)              (##/##)         shiftr
33     Illegal             (##/##)         one_address
34     X (##)    (##)      (##/##)         multiply
35     X         (##)      (##/##)         multiply
36     +c        (##/##)   (##/##)         two_address
37     -c        (##/##)   (##/##)         two_address
38     +         (##/##)   (##/##)         two_address
39     -         (##/##)   (##/##)         two_address
40     T         (##/##)   (##/##)         two_address
41     R  (1-##) (##/##)   (##/##)         store
42     R (##-32) (##/##)   (##/##)         store
43     R         (##/##)   (##/##)         store
44     A  (1-##) (##/##)   (##/##)         store
45     A (##-32) (##/##)   (##/##)         store
46     A         (##/##)   (##/##)         store
47     S         (##)      (##/##)         swap
48     +--------++--------++-----+
49     mnemonic   X field  Y field
50      field
51 
52     For vector instructions, replace the first space on the right of the mnemonic
53     with a 'v'.
54 
55     01-Feb-2010 (Robbbert):
56     I've added the actual address, (as shown in the extreme left of the debugger
57     output), so that you can see much easier how the program will flow. Example:
58 
59     +C  XXX(##/##)   XXX(##/##)
60 
61     The X value shows where the data word is located, and the Y value is the
62     address of the next instruction.
63 */
64 
65 const apexc_disassembler::instr_desc apexc_disassembler::instructions[16] =
66 {
67 	{ "Stop",   one_address },  { "I",      one_address },
68 	{ "P",      one_address },  { "B",      branch },
69 	{ "l",      shiftl },       { "r",      shiftr },
70 	{ "Illegal",one_address },  { "X",      multiply },
71 	{ "+c",     two_address },  { "-c",     two_address },
72 	{ "+",      two_address },  { "-",      two_address },
73 	{ "T",      two_address },  { "R",      store },
74 	{ "A",      store },        { "S",      swap }
75 };
76 
opcode_alignment() const77 u32 apexc_disassembler::opcode_alignment() const
78 {
79 	return 4;
80 }
81 
disassemble(std::ostream & stream,offs_t pc,const data_buffer & opcodes,const data_buffer & params)82 offs_t apexc_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
83 {
84 	uint32_t instruction;         /* 32-bit machine instruction */
85 	int x, y, function, c6, vector; /* instruction fields */
86 	int n;                      /* 'friendly', instruction-dependant interpretation of C6 */
87 	const instr_desc *the_desc; /* pointer to the relevant entry in the instructions array */
88 	char mnemonic[9];           /* storage for generated mnemonic */
89 
90 	/* read the instruction to disassemble */
91 	instruction = opcodes.r32(pc);
92 
93 	/* isolate the instruction fields */
94 	x = (instruction >> 22) & 0x3FF;
95 	y = (instruction >> 12) & 0x3FF;
96 	function = (instruction >> 7) & 0x1F;
97 	c6 = (instruction >> 1) & 0x3F;
98 	vector = instruction & 1;
99 
100 	/* get the relevant entry in instructions */
101 	the_desc = & instructions[function >> 1];
102 
103 	/* generate mnemonic : append a 'v' to the basic mnemonic if it is a vector instruction */
104 	sprintf(mnemonic, "%.*s%c", (int)sizeof(mnemonic)-2, the_desc->mnemonic, vector ? 'v' : ' ');
105 
106 	/* print mnemonic and n immediate */
107 	switch (the_desc->format)
108 	{
109 	case one_address:
110 	case two_address:
111 	case branch:
112 	case swap:
113 		util::stream_format(stream, "   %-10s", mnemonic);    /* 10 chars*/
114 		break;
115 
116 	case shiftl:
117 	case shiftr:
118 		if (the_desc->format == shiftl)
119 			n = c6;
120 		else
121 			n = 64-c6;
122 		util::stream_format(stream, "   %-2s(%2d)    ", mnemonic, n); /* 10 chars */
123 		break;
124 
125 	case multiply:
126 		n = 33-c6;
127 		if (n == 32)
128 			/* case "32" : do not show bit specifier */
129 			util::stream_format(stream, "   %-10s", mnemonic);    /* 10 chars */
130 		else
131 			util::stream_format(stream, "   %-2s(%2d)    ", mnemonic, n); /* 10 chars */
132 		break;
133 
134 	case store:
135 		if (c6 == 0)
136 		{   /* case "1-32" : do not show bit specifier */
137 			util::stream_format(stream, "   %-10s", mnemonic);    /* 10 chars*/
138 		}
139 		else if (c6 & 0x20)
140 		{   /* case "1-n" */
141 			n = c6-32;
142 			util::stream_format(stream, "   %-2s (1-%02d) ", mnemonic, n);    /* 10 chars */
143 		}
144 		else
145 		{   /* case "n-32" */
146 			n = c6+1;
147 			util::stream_format(stream, "   %-2s(%02d-32) ", mnemonic, n);    /* 8 chars */
148 		}
149 	}
150 
151 	/* print X address */
152 	switch (the_desc->format)
153 	{
154 	case branch:
155 		stream.seekp(-1, std::ios_base::cur);   /* eat last char */
156 		util::stream_format(stream, "<%03X(%02d/%02d) >=", x<<2, (x >> 5) & 0x1f, x & 0x1f);  /* 10+1 chars */
157 		break;
158 
159 	case multiply:
160 	case swap:
161 		util::stream_format(stream, "   (%02d)      ", (x >> 5) & 0x1f);  /* 10 chars */
162 		break;
163 
164 	case one_address:
165 	case shiftl:
166 	case shiftr:
167 		util::stream_format(stream, "             "); /* 10 chars */
168 		break;
169 
170 	case two_address:
171 	case store:
172 		util::stream_format(stream, "%03X(%02d/%02d)   ", x<<2, (x >> 5) & 0x1f, x & 0x1f);   /* 10 chars */
173 		break;
174 	}
175 
176 	/* print Y address */
177 	util::stream_format(stream, "%03X(%02d/%02d)", y<<2, (y >> 5) & 0x1f, y & 0x1f);  /* 7 chars */
178 	return 4;
179 }
180