summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/palm/palmd.cpp
blob: d0ce461f4b0996bc6100a6b4bfaff54834ca97ce (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
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay

#include "emu.h"
#include "palmd.h"

static const char *const r[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
static const char *const jm[] = { "le", "lo", "eq", "no", "all", "allm", "nom", "ham", "hi", "he", "hl", "sb", "sn", "snm", "sm", "hsnm" };
static const char *const im[] = { "+1", "+2", "+3", "+4", "-1", "-2", "-3", "-4" };

// helper for IBM bit numbering
template <typename T, typename U, typename V> constexpr T IBIT(T x, U n, V w)
{
	return BIT(x, sizeof(T) * 8 - n - w, w);
}

// instruction field shorthand
#define Rx  IBIT(op, 4, 4)
#define Ry  IBIT(op, 8, 4)
#define DA  IBIT(op, 4, 4)
#define IMM IBIT(op, 8, 8)
#define MOD IBIT(op, 12, 4)

offs_t palm_disassembler::disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const &params)
{
	u16 const op = opcodes.r16(pc);
	u32 flags = 0;

	pc += 2;

	switch (IBIT(op, 0, 4))
	{
	case 0x0:
		switch (MOD)
		{
		case 0x0:
			if (IBIT(op, 4, 8))
				// move minus 2
				util::stream_format(stream, "mvm2  %s,%s", r[Rx], r[Ry]);
			else
				// synthetic halt (branch to self)
				util::stream_format(stream, "halt");
			break;
		case 0x1: util::stream_format(stream, "mvm1  %s,%s", r[Rx], r[Ry]); break; // move minus 1
		case 0x2: util::stream_format(stream, "mvp1  %s,%s", r[Rx], r[Ry]); break; // move plus 1
		case 0x3: util::stream_format(stream, "mvp2  %s,%s", r[Rx], r[Ry]); break; // move plus 2
		case 0x4:
			if (Rx)
				// move register
				util::stream_format(stream, "move  %s,%s", r[Rx], r[Ry]);
			else if (Ry)
			{
				// synthetic jump to register
				util::stream_format(stream, "jump  %s", r[Ry]);
				flags |= STEP_COND;
			}
			else // synthetic no operation
				util::stream_format(stream, "noop");
			break;
		case 0x5: util::stream_format(stream, "and   %s,%s", r[Rx], r[Ry]); break; // and byte
		case 0x6: util::stream_format(stream, "orb   %s,%s", r[Rx], r[Ry]); break; // or byte
		case 0x7: util::stream_format(stream, "xor   %s,%s", r[Rx], r[Ry]); break; // xor byte
		case 0x8: util::stream_format(stream, "add   %s,%s", r[Rx], r[Ry]); break; // add
		case 0x9: util::stream_format(stream, "sub   %s,%s", r[Rx], r[Ry]); break; // subtract
		case 0xa: util::stream_format(stream, "adds1 %s,%s", r[Rx], r[Ry]); break; // add special #1
		case 0xb: util::stream_format(stream, "adds2 %s,%s", r[Rx], r[Ry]); break; // add special #2
		case 0xc: util::stream_format(stream, "htl   %s,%s", r[Rx], r[Ry]); break; // high to low
		case 0xd: util::stream_format(stream, "lth   %s,%s", r[Rx], r[Ry]); break; // low to high
		case 0xe: util::stream_format(stream, "getr  $%x,%s", DA, r[Ry]); break; // get to register
		case 0xf: util::stream_format(stream, "geta  $%x,%s", DA, r[Ry]); break; // get to register and add
		}
		break;
	case 0x1: util::stream_format(stream, "ctl   $%x,#$%x", DA, IMM); break; // control
	case 0x2: util::stream_format(stream, "ldhd  %s,$%x", r[Rx], IMM * 2); break; // load halfword direct
	case 0x3: util::stream_format(stream, "sthd  %s,$%x", r[Rx], IMM * 2); break; // store halfword direct
	case 0x4:
		// put byte
		if (MOD < 8)
			util::stream_format(stream, "putb  $%x,%s,%s", DA, r[Ry], im[MOD]);
		else
			util::stream_format(stream, "putb  $%x,%s", DA, r[Ry]);
		break;
	case 0x5:
		// store halfword indirect
		if (MOD < 8)
			util::stream_format(stream, "sthi  %s,%s,%s", r[Rx], r[Ry], im[MOD]);
		else
			util::stream_format(stream, "sthi  %s,%s", r[Rx], r[Ry]);
		break;
	case 0x6:
		// load byte indirect
		if (MOD < 8)
			util::stream_format(stream, "ldbi  %s,%s,%s", r[Rx], r[Ry], im[MOD]);
		else
			util::stream_format(stream, "ldbi  %s,%s", r[Rx], r[Ry]);
		break;
	case 0x7:
		// store byte indirect
		if (MOD < 8)
			util::stream_format(stream, "stbi  %s,%s,%s", r[Rx], r[Ry], im[MOD]);
		else
			util::stream_format(stream, "stbi  %s,%s", r[Rx], r[Ry]);
		break;
	case 0x8: util::stream_format(stream, "emit  %s,#$%x", r[Rx], IMM); break; // emit byte
	case 0x9: util::stream_format(stream, "clri  %s,#$%x", r[Rx], IMM); break; // clear immediate
	case 0xa:
		if (Rx)
			// add immediate
			util::stream_format(stream, "addi  %s,#$%x", r[Rx], IMM + 1);
		else
		{
			// synthetic jump relative (forward)
			util::stream_format(stream, "jump  $%x", pc + IMM + 1);
			flags |= STEP_COND;
		}
		break;
	case 0xb: util::stream_format(stream, "seti  %s,#$%x", r[Rx], IMM); break; // set immediate
	case 0xc:
		switch (MOD)
		{
		case 0x3: case 0x4: case 0xb: case 0xc:
			// one-operand jumps
			util::stream_format(stream, "j%-4s %s", jm[MOD], r[Rx]);
			break;
		case 0x0: case 0x1: case 0x2: case 0x5:
		case 0x6: case 0x7: case 0x8: case 0x9:
		case 0xa: case 0xd: case 0xe: case 0xf:
			// two-operand jumps
			util::stream_format(stream, "j%-4s %s,%s", jm[MOD], r[Rx], r[Ry]);
			break;
		}
		flags |= STEP_COND;
		break;
	case 0xd:
		// load halfword indirect
		if (MOD < 8)
			util::stream_format(stream, "ldhi  %s,%s,%s", r[Rx], r[Ry], im[MOD]);
		else
			util::stream_format(stream, "ldhi  %s,%s", r[Rx], r[Ry]);
		break;
	case 0xe:
		if (DA == 0 && MOD >= 0xc)
		{
			switch (MOD)
			{
			case 0xc: util::stream_format(stream, "shftr %s", r[Ry]); break; // shift right 1
			case 0xd: util::stream_format(stream, "rotr  %s", r[Ry]); break; // shift right and rotate 1
			case 0xe: util::stream_format(stream, "srr3  %s", r[Ry]); break; // shift right and rotate 3
			case 0xf: util::stream_format(stream, "srr4  %s", r[Ry]); break; // shift right and rotate 4
			}
		}
		else
		{
			if (MOD < 0x8)
				// get byte
				util::stream_format(stream, "getb  $%x,%s,%s", DA, r[Ry], im[MOD]);
			else if (MOD < 0xc)
				// get byte
				util::stream_format(stream, "getb  $%x,%s", DA, r[Ry]);
			else
				// get register byte
				util::stream_format(stream, "getrb $%x,%s", DA, r[Ry]);
		}
		break;
	case 0xf:
		if (Rx)
			// subtract immediate
			util::stream_format(stream, "subi  %s,#$%x", r[Rx], IMM + 1);
		else
		{
			// synthetic jump relative (backward)
			util::stream_format(stream, "jump  $%x", pc - IMM - 1);
			flags |= STEP_COND;
		}
		break;
	}

	return 2 | flags | SUPPORTED;
}