1 |
2 |
dgisselq |
////////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
//
|
3 |
|
|
// Filename: zopcodes.cpp
|
4 |
|
|
//
|
5 |
|
|
// Project: Zip CPU -- a small, lightweight, RISC CPU core
|
6 |
|
|
//
|
7 |
|
|
// Purpose:
|
8 |
|
|
//
|
9 |
|
|
// Creator: Dan Gisselquist, Ph.D.
|
10 |
|
|
// Gisselquist Tecnology, LLC
|
11 |
|
|
//
|
12 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
13 |
|
|
//
|
14 |
|
|
// Copyright (C) 2015, Gisselquist Technology, LLC
|
15 |
|
|
//
|
16 |
|
|
// This program is free software (firmware): you can redistribute it and/or
|
17 |
|
|
// modify it under the terms of the GNU General Public License as published
|
18 |
|
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
19 |
|
|
// your option) any later version.
|
20 |
|
|
//
|
21 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
22 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
23 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
24 |
|
|
// for more details.
|
25 |
|
|
//
|
26 |
|
|
// You should have received a copy of the GNU General Public License along
|
27 |
|
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
28 |
|
|
// target there if the PDF file isn't present.) If not, see
|
29 |
|
|
// <http://www.gnu.org/licenses/> for a copy.
|
30 |
|
|
//
|
31 |
|
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
32 |
|
|
// http://www.gnu.org/licenses/gpl.html
|
33 |
|
|
//
|
34 |
|
|
//
|
35 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
36 |
|
|
|
37 |
|
|
#include <stdio.h>
|
38 |
|
|
#include <strings.h>
|
39 |
|
|
#include <string.h>
|
40 |
|
|
#include <assert.h>
|
41 |
|
|
|
42 |
|
|
#include "twoc.h"
|
43 |
|
|
#include "zopcodes.h"
|
44 |
|
|
|
45 |
|
|
const char *zop_regstr[] = {
|
46 |
|
|
"R0", "R1", "R2", "R3",
|
47 |
|
|
"R4", "R5", "R6", "R7",
|
48 |
|
|
"R8", "R9", "R10","R11",
|
49 |
|
|
"R12","SP", "CC", "PC",
|
50 |
|
|
"uR0", "uR1", "uR2", "uR3",
|
51 |
|
|
"uR4", "uR5", "uR6", "uR7",
|
52 |
|
|
"uR8", "uR9", "uR10", "uR11",
|
53 |
|
|
"uR12", "uSP", "uCC", "uPC",
|
54 |
|
|
"sR0", "sR1", "sR2", "sR3",
|
55 |
|
|
"sR4", "sR5", "sR6", "sR7",
|
56 |
|
|
"sR8", "sR9", "sR10","sR11",
|
57 |
|
|
"sR12","sSP", "sCC", "sPC"
|
58 |
|
|
};
|
59 |
|
|
|
60 |
|
|
const char *zop_ccstr[] = {
|
61 |
|
|
"", ".Z", ".NE", ".GE", ".GT", ".LT", ".C", ".V"
|
62 |
|
|
};
|
63 |
|
|
|
64 |
|
|
const ZOPCODE zoplist[] = {
|
65 |
|
|
// Special case instructions. These are general instructions, but with
|
66 |
|
|
// special opcodes
|
67 |
|
|
// Conditional branches
|
68 |
|
|
"BRA", 0xffff8000, 0x2f0f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
|
69 |
|
|
"BRZ", 0xffff8000, 0x2f2f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
|
70 |
|
|
"BNZ", 0xffff8000, 0x2f4f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
|
71 |
|
|
"BGE", 0xffff8000, 0x2f6f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
|
72 |
|
|
"BGT", 0xffff8000, 0x2f8f0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
|
73 |
|
|
"BLT", 0xffff8000, 0x2faf0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
|
74 |
|
|
"BRC", 0xffff8000, 0x2fcf0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
|
75 |
|
|
"BRV", 0xffff8000, 0x2fef0000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(15,0), OPUNUSED,
|
76 |
|
|
// CLR
|
77 |
|
|
"CLRF", 0xff1f0000, 0xc0100000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
78 |
|
|
"CLRF", 0xff1f0000, 0xc1110000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
79 |
|
|
"CLRF", 0xff1f0000, 0xc2120000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
80 |
|
|
"CLRF", 0xff1f0000, 0xc3130000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
81 |
|
|
"CLRF", 0xff1f0000, 0xc4140000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
82 |
|
|
"CLRF", 0xff1f0000, 0xc5150000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
83 |
|
|
"CLRF", 0xff1f0000, 0xc6160000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
84 |
|
|
"CLRF", 0xff1f0000, 0xc7170000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
85 |
|
|
"CLRF", 0xff1f0000, 0xc8180000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
86 |
|
|
"CLRF", 0xff1f0000, 0xc9190000, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
87 |
|
|
"CLRF", 0xff1f0000, 0xca1a0000, REGFIELD(24),OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
88 |
|
|
"CLRF", 0xff1f0000, 0xcb1b0000, REGFIELD(24),OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
89 |
|
|
"CLRF", 0xff1f0000, 0xcc1c0000, REGFIELD(24),OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
90 |
|
|
"CLRF", 0xff1f0000, 0xcd1d0000, REGFIELD(24),OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
91 |
|
|
"CLRF", 0xff1f0000, 0xce1e0000, REGFIELD(24),OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
92 |
|
|
"CLRF", 0xff1f0000, 0xcf1f0000, REGFIELD(24),OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
93 |
|
|
//
|
94 |
|
|
"CLR", 0xf0ffffff, 0x30000000, REGFIELD(24),OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED,
|
95 |
|
|
//
|
96 |
|
|
"HALT", 0xff10007f, 0xbe000010, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
97 |
|
|
// The "wait" instruction is identical, with the only difference being
|
98 |
|
|
// the interrrupt context of the processor. Hence we allow both
|
99 |
|
|
// instructions here.
|
100 |
|
|
"WAIT", 0xff10007f, 0xbe000010, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
101 |
|
|
//
|
102 |
|
|
"INT", 0xff10007f, 0x9e00005f, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
103 |
|
|
// Return to user space
|
104 |
|
|
"RTU", 0xff10007f, 0xbe000020, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
105 |
|
|
// JMP (possibly a conditional jump, if not covered by branches above)
|
106 |
|
|
"JMP", 0xff108000, 0x2f000000, OPUNUSED,OPUNUSED, REGFIELD(16), IMMFIELD(15,0), BITFIELD(3,21),
|
107 |
|
|
"JMP", 0xff108000, 0x2f008000, OPUNUSED,OPUNUSED, URGFIELD(16), IMMFIELD(15,0), BITFIELD(3,21),
|
108 |
|
|
"LJMP", 0xff100000, 0xaf000000, OPUNUSED,OPUNUSED, OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
109 |
|
|
// NOT
|
110 |
|
|
"NOT", 0xf01fffff, 0xc00fffff, REGFIELD(24), OPUNUSED, OPUNUSED, OPUNUSED, BITFIELD(3,21),
|
111 |
|
|
// General instructions
|
112 |
|
|
"CMP", 0xf0100000, 0x00000000, OPUNUSED, REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
113 |
|
|
"CMP", 0xf0100000, 0x00100000, OPUNUSED, REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
114 |
|
|
"TST", 0xf0100000, 0x10000000, OPUNUSED, REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
115 |
|
|
"TST", 0xf0100000, 0x10100000, OPUNUSED, REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
116 |
|
|
// map bit = 1 (interrupts enabled) specifies user reg
|
117 |
|
|
"MOV", 0xf0108000, 0x20000000, REGFIELD(24),OPUNUSED, REGFIELD(16), IMMFIELD(15,0), BITFIELD(3,21),
|
118 |
|
|
"MOV", 0xf0108000, 0x20100000, URGFIELD(24),OPUNUSED, REGFIELD(16), IMMFIELD(15,0), BITFIELD(3,21),
|
119 |
|
|
"MOV", 0xf0108000, 0x20008000, REGFIELD(24),OPUNUSED, URGFIELD(16), IMMFIELD(15,0), BITFIELD(3,21),
|
120 |
|
|
"MOV", 0xf0108000, 0x20108000, URGFIELD(24),OPUNUSED, URGFIELD(16), IMMFIELD(15,0), BITFIELD(3,21),
|
121 |
|
|
//
|
122 |
|
|
"LDI", 0xf0000000, 0x30000000, REGFIELD(24),OPUNUSED, OPUNUSED, IMMFIELD(24,0), OPUNUSED,
|
123 |
|
|
//
|
124 |
|
|
"NOOP", 0xffffffff, 0x4e000000, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED,
|
125 |
|
|
"BRK", 0xffffffff, 0x4e000001, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED, OPUNUSED,
|
126 |
|
|
//
|
127 |
|
|
"LDILO",0xff100000, 0x4f000000, REGFIELD(16),OPUNUSED, OPUNUSED, IMMFIELD(16,0), BITFIELD(3,21),
|
128 |
|
|
"LDIHI",0xff100000, 0x4f100000, REGFIELD(16),OPUNUSED, OPUNUSED, IMMFIELD(16,0), BITFIELD(3,21),
|
129 |
|
|
//
|
130 |
|
|
"LOD", 0xf0100000, 0x60000000, REGFIELD(24), OPUNUSED, OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
131 |
|
|
"LOD", 0xf0100000, 0x60100000, REGFIELD(24), OPUNUSED, REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
132 |
|
|
//
|
133 |
|
|
"STO", 0xf0100000, 0x70000000, OPUNUSED, REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
134 |
|
|
"STO", 0xf0100000, 0x70100000, OPUNUSED, REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
135 |
|
|
//
|
136 |
|
|
"SUB", 0xf0100000, 0x80000000, REGFIELD(24), REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
137 |
|
|
"SUB", 0xf0100000, 0x80100000, REGFIELD(24), REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
138 |
|
|
//
|
139 |
|
|
"AND", 0xf0100000, 0x90000000, REGFIELD(24), REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
140 |
|
|
"AND", 0xf0100000, 0x90100000, REGFIELD(24), REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
141 |
|
|
//
|
142 |
|
|
"ADD", 0xf0100000, 0xa0000000, REGFIELD(24), REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
143 |
|
|
"ADD", 0xf0100000, 0xa0100000, REGFIELD(24), REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
144 |
|
|
//
|
145 |
|
|
"OR", 0xf0100000, 0xb0000000, REGFIELD(24), REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
146 |
|
|
"OR", 0xf0100000, 0xb0100000, REGFIELD(24), REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
147 |
|
|
//
|
148 |
|
|
"XOR", 0xf0100000, 0xc0000000, REGFIELD(24), REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
149 |
|
|
"XOR", 0xf0100000, 0xc0100000, REGFIELD(24), REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
150 |
|
|
//
|
151 |
|
|
"LSL", 0xf0100000, 0xd0000000, REGFIELD(24), REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
152 |
|
|
"LSL", 0xf0100000, 0xd0100000, REGFIELD(24), REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
153 |
|
|
//
|
154 |
|
|
"ASR", 0xf0100000, 0xe0000000, REGFIELD(24), REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
155 |
|
|
"ASR", 0xf0100000, 0xe0100000, REGFIELD(24), REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
156 |
|
|
//
|
157 |
|
|
"LSR", 0xf0100000, 0xf0000000, REGFIELD(24), REGFIELD(24), OPUNUSED, IMMFIELD(19,0), BITFIELD(3,21),
|
158 |
|
|
"LSR", 0xf0100000, 0xf0100000, REGFIELD(24), REGFIELD(24), REGFIELD(16), IMMFIELD(16,0), BITFIELD(3,21),
|
159 |
|
|
// Illegal instruction !!
|
160 |
|
|
"ILL", 0x00000000, 0x00000000, OPUNUSED, OPUNUSED, OPUNUSED, IMMFIELD(32,0), OPUNUSED
|
161 |
|
|
};
|
162 |
|
|
|
163 |
|
|
const int nzoplist = (sizeof(zoplist)/sizeof(ZOPCODE));
|
164 |
|
|
|
165 |
|
|
static int getbits(const ZIPI ins, const int which) {
|
166 |
|
|
if (which & 0x40000000) {
|
167 |
|
|
// printf("SBITS: %08x, %08x = %08lx\n", ins, which,
|
168 |
|
|
// sbits(ins>>(which & 0x03f), (which>>8)&0x03f));
|
169 |
|
|
return sbits(ins>>(which & 0x03f), (which>>8)&0x03f);
|
170 |
|
|
} else if (which &0x03f) {
|
171 |
|
|
return ubits(ins>>(which & 0x03f), (which>>8)&0x03f)
|
172 |
|
|
+ ((which>>16)&0x0ff);
|
173 |
|
|
} else
|
174 |
|
|
return which;
|
175 |
|
|
}
|
176 |
|
|
|
177 |
|
|
void zipi_to_string(const ZIPI ins, char *line) {
|
178 |
|
|
for(int i=0; i<nzoplist; i++)
|
179 |
|
|
assert(((~zoplist[i].s_mask)&zoplist[i].s_val)==0);
|
180 |
|
|
for(int i=0; i<nzoplist; i++) {
|
181 |
|
|
// printf("%2d: %6s %08x & %08x == %08x\n",
|
182 |
|
|
// i, zoplist[i].s_opstr, ins,
|
183 |
|
|
// zoplist[i].s_mask, zoplist[i].s_val);
|
184 |
|
|
if ((ins & zoplist[i].s_mask) == zoplist[i].s_val) {
|
185 |
|
|
sprintf(line, "\t%s", zoplist[i].s_opstr);
|
186 |
|
|
if (zoplist[i].s_cf != OPUNUSED) {
|
187 |
|
|
int bv = getbits(ins, zoplist[i].s_cf);
|
188 |
|
|
strcat(line, zop_ccstr[bv]);
|
189 |
|
|
} strcat(line, "\t");
|
190 |
|
|
|
191 |
|
|
// Treat stores special
|
192 |
|
|
if (strncasecmp("STO",zoplist[i].s_opstr, 3)==0) {
|
193 |
|
|
int ra = getbits(ins, zoplist[i].s_ra);
|
194 |
|
|
strcat(line, zop_regstr[ra]);
|
195 |
|
|
strcat(line, ",");
|
196 |
|
|
|
197 |
|
|
if (zoplist[i].s_i != OPUNUSED) {
|
198 |
|
|
int imv = 0;
|
199 |
|
|
imv = getbits(ins, zoplist[i].s_i);
|
200 |
|
|
if ((imv != 0)&&(zoplist[i].s_rb != OPUNUSED))
|
201 |
|
|
sprintf(&line[strlen(line)],
|
202 |
|
|
"$%d", imv);
|
203 |
|
|
else if (imv != 0)
|
204 |
|
|
sprintf(&line[strlen(line)],
|
205 |
|
|
"($%d)", imv);
|
206 |
|
|
} if (zoplist[i].s_rb != OPUNUSED) {
|
207 |
|
|
int rb = getbits(ins, zoplist[i].s_rb);
|
208 |
|
|
sprintf(&line[strlen(line)],
|
209 |
|
|
"(%s)", zop_regstr[rb]);
|
210 |
|
|
}
|
211 |
|
|
|
212 |
|
|
} else {
|
213 |
|
|
bool memop = (strncasecmp("LOD",
|
214 |
|
|
zoplist[i].s_opstr, 3)==0);
|
215 |
|
|
if (zoplist[i].s_i != OPUNUSED) {
|
216 |
|
|
int imv = 0;
|
217 |
|
|
imv = getbits(ins, zoplist[i].s_i);
|
218 |
|
|
if ((imv != 0)||(zoplist[i].s_rb == OPUNUSED))
|
219 |
|
|
sprintf(&line[strlen(line)],
|
220 |
|
|
"$%d%s", imv,
|
221 |
|
|
((!memop)&&(zoplist[i].s_rb!=OPUNUSED))?"+":"");
|
222 |
|
|
} if (zoplist[i].s_rb != OPUNUSED) {
|
223 |
|
|
int rb = getbits(ins, zoplist[i].s_rb);
|
224 |
|
|
if (memop)
|
225 |
|
|
sprintf(&line[strlen(line)],
|
226 |
|
|
"(%s)", zop_regstr[rb]);
|
227 |
|
|
else
|
228 |
|
|
strcat(line, zop_regstr[rb]);
|
229 |
|
|
} if(((zoplist[i].s_i != OPUNUSED)||(zoplist[i].s_rb != OPUNUSED))
|
230 |
|
|
&&((zoplist[i].s_ra != OPUNUSED)||(zoplist[i].s_result != OPUNUSED)))
|
231 |
|
|
strcat(line, ",");
|
232 |
|
|
|
233 |
|
|
if (zoplist[i].s_ra != OPUNUSED) {
|
234 |
|
|
int ra = getbits(ins, zoplist[i].s_ra);
|
235 |
|
|
strcat(line, zop_regstr[ra]);
|
236 |
|
|
} else if (zoplist[i].s_result != OPUNUSED) {
|
237 |
|
|
int ra = getbits(ins, zoplist[i].s_result);
|
238 |
|
|
strcat(line, zop_regstr[ra]);
|
239 |
|
|
}
|
240 |
|
|
|
241 |
|
|
}
|
242 |
|
|
break;
|
243 |
|
|
}
|
244 |
|
|
}
|
245 |
|
|
}
|
246 |
|
|
|