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 ¶ms)
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