trunk/src/emu/cpu/i4004/i4004.c
r23755 | r23756 | |
11 | 11 | #include "debugger.h" |
12 | 12 | #include "i4004.h" |
13 | 13 | |
14 | | #define VERBOSE 0 |
15 | 14 | |
16 | | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) |
17 | | |
18 | 15 | static const UINT8 kbp_table[] = { 0x00,0x01,0x02,0x0f,0x03,0x0f,0x0f,0x0f,0x04,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f }; |
19 | 16 | |
20 | | /*************************************************************************** |
21 | | TYPE DEFINITIONS |
22 | | ***************************************************************************/ |
23 | 17 | |
24 | | struct i4004_state |
25 | | { |
26 | | UINT8 A; // Accumulator |
27 | | UINT8 R[8]; |
28 | | PAIR ADDR[4]; // Address registers |
29 | | PAIR RAM; |
30 | | UINT8 C; // Carry flag |
31 | | UINT8 TEST; // Test PIN status |
32 | | PAIR PC; // It is in fact one of ADDR regs |
33 | | UINT8 flags; // used for I/O only |
34 | | |
35 | | legacy_cpu_device *device; |
36 | | address_space *program; |
37 | | direct_read_data *direct; |
38 | | address_space *data; |
39 | | address_space *io; |
40 | | int icount; |
41 | | int pc_pos; // PC possition in ADDR |
42 | | int addr_mask; |
43 | | }; |
44 | | |
45 | 18 | /*************************************************************************** |
46 | 19 | MACROS |
47 | 20 | ***************************************************************************/ |
48 | | #define GET_PC (cpustate->ADDR[cpustate->pc_pos]) |
| 21 | #define GET_PC (m_ADDR[m_pc_pos]) |
49 | 22 | |
50 | | /*************************************************************************** |
51 | | INLINE FUNCTIONS |
52 | | ***************************************************************************/ |
53 | 23 | |
54 | | INLINE i4004_state *get_safe_token(device_t *device) |
| 24 | const device_type I4004 = &device_creator<i4004_cpu_device>; |
| 25 | |
| 26 | |
| 27 | i4004_cpu_device::i4004_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 28 | : cpu_device(mconfig, I4004, "Intel I4004", tag, owner, clock) |
| 29 | , m_program_config("program", ENDIANNESS_LITTLE, 8, 12, 0) |
| 30 | , m_io_config("io", ENDIANNESS_LITTLE, 8, 6, 0) |
| 31 | , m_data_config("data", ENDIANNESS_LITTLE, 8, 12, 0) |
55 | 32 | { |
56 | | assert(device != NULL); |
57 | | assert(device->type() == I4004); |
58 | | return (i4004_state *)downcast<legacy_cpu_device *>(device)->token(); |
| 33 | m_is_octal = true; |
59 | 34 | } |
60 | 35 | |
61 | | INLINE UINT8 ROP(i4004_state *cpustate) |
| 36 | |
| 37 | UINT8 i4004_cpu_device::ROP() |
62 | 38 | { |
63 | | UINT8 retVal = cpustate->direct->read_decrypted_byte(GET_PC.w.l); |
| 39 | UINT8 retVal = m_direct->read_decrypted_byte(GET_PC.w.l); |
64 | 40 | GET_PC.w.l = (GET_PC.w.l + 1) & 0x0fff; |
65 | | cpustate->PC = GET_PC; |
| 41 | m_PC = GET_PC; |
66 | 42 | return retVal; |
67 | 43 | } |
68 | 44 | |
69 | | INLINE UINT8 READ_ROM(i4004_state *cpustate) |
| 45 | UINT8 i4004_cpu_device::READ_ROM() |
70 | 46 | { |
71 | | return cpustate->direct->read_decrypted_byte((GET_PC.w.l & 0x0f00) | cpustate->R[0]); |
| 47 | return m_direct->read_decrypted_byte((GET_PC.w.l & 0x0f00) | m_R[0]); |
72 | 48 | } |
73 | 49 | |
74 | | INLINE void WPM(i4004_state *cpustate) |
| 50 | void i4004_cpu_device::WPM() |
75 | 51 | { |
76 | | UINT8 t = (cpustate->program->read_byte(cpustate->RAM.d) << 4) | cpustate->A; |
77 | | cpustate->program->write_byte((GET_PC.w.l & 0x0f00) | cpustate->RAM.d, t); |
| 52 | UINT8 t = (m_program->read_byte(m_RAM.d) << 4) | m_A; |
| 53 | m_program->write_byte((GET_PC.w.l & 0x0f00) | m_RAM.d, t); |
78 | 54 | } |
79 | 55 | |
80 | 56 | |
81 | | INLINE UINT8 ARG(i4004_state *cpustate) |
| 57 | UINT8 i4004_cpu_device::ARG() |
82 | 58 | { |
83 | | UINT8 retVal = cpustate->direct->read_raw_byte(GET_PC.w.l); |
| 59 | UINT8 retVal = m_direct->read_raw_byte(GET_PC.w.l); |
84 | 60 | GET_PC.w.l = (GET_PC.w.l + 1) & 0x0fff; |
85 | | cpustate->PC = GET_PC; |
| 61 | m_PC = GET_PC; |
86 | 62 | return retVal; |
87 | 63 | } |
88 | 64 | |
89 | | INLINE UINT8 RM(i4004_state *cpustate) |
| 65 | UINT8 i4004_cpu_device::RM() |
90 | 66 | { |
91 | | return cpustate->data->read_byte(cpustate->RAM.d) & 0x0f; |
| 67 | return m_data->read_byte(m_RAM.d) & 0x0f; |
92 | 68 | } |
93 | 69 | |
94 | | INLINE UINT8 RMS(i4004_state *cpustate, UINT32 a) |
| 70 | UINT8 i4004_cpu_device::RMS(UINT32 a) |
95 | 71 | { |
96 | | return cpustate->data->read_byte((cpustate->RAM.d & 0xff0) + a) >> 4; |
| 72 | return m_data->read_byte((m_RAM.d & 0xff0) + a) >> 4; |
97 | 73 | } |
98 | 74 | |
99 | | INLINE void WM(i4004_state *cpustate, UINT8 v) |
| 75 | void i4004_cpu_device::WM(UINT8 v) |
100 | 76 | { |
101 | | UINT8 t = cpustate->data->read_byte(cpustate->RAM.d); |
102 | | cpustate->data->write_byte(cpustate->RAM.d, (t & 0xf0) | v); |
| 77 | UINT8 t = m_data->read_byte(m_RAM.d); |
| 78 | m_data->write_byte(m_RAM.d, (t & 0xf0) | v); |
103 | 79 | } |
104 | 80 | |
105 | 81 | |
106 | | INLINE void WMP(i4004_state *cpustate, UINT8 v) |
| 82 | void i4004_cpu_device::WMP(UINT8 v) |
107 | 83 | { |
108 | | cpustate->io->write_byte((cpustate->RAM.d >> 6) | 0x10, v & 0x0f); |
| 84 | m_io->write_byte((m_RAM.d >> 6) | 0x10, v & 0x0f); |
109 | 85 | } |
110 | 86 | |
111 | | INLINE void WMS(i4004_state *cpustate, UINT32 a, UINT8 v) |
| 87 | void i4004_cpu_device::WMS(UINT32 a, UINT8 v) |
112 | 88 | { |
113 | | UINT8 t = cpustate->data->read_byte((cpustate->RAM.d & 0xff0) + a); |
114 | | cpustate->data->write_byte((cpustate->RAM.d & 0xff0) + a, (t & 0x0f) | (v<<4)); |
| 89 | UINT8 t = m_data->read_byte((m_RAM.d & 0xff0) + a); |
| 90 | m_data->write_byte((m_RAM.d & 0xff0) + a, (t & 0x0f) | (v<<4)); |
115 | 91 | } |
116 | 92 | |
117 | | INLINE UINT8 RIO(i4004_state *cpustate) |
| 93 | UINT8 i4004_cpu_device::RIO() |
118 | 94 | { |
119 | | return cpustate->io->read_byte(cpustate->RAM.b.l >> 4) & 0x0f; |
| 95 | return m_io->read_byte(m_RAM.b.l >> 4) & 0x0f; |
120 | 96 | } |
121 | 97 | |
122 | | INLINE void WIO(i4004_state *cpustate, UINT8 v) |
| 98 | void i4004_cpu_device::WIO(UINT8 v) |
123 | 99 | { |
124 | | cpustate->io->write_byte(cpustate->RAM.b.l >> 4, v & 0x0f); |
| 100 | m_io->write_byte(m_RAM.b.l >> 4, v & 0x0f); |
125 | 101 | } |
126 | 102 | |
127 | | INLINE UINT8 GET_REG(i4004_state *cpustate, UINT8 num) |
| 103 | UINT8 i4004_cpu_device::GET_REG(UINT8 num) |
128 | 104 | { |
129 | | UINT8 r = cpustate->R[num>>1]; |
| 105 | UINT8 r = m_R[num>>1]; |
130 | 106 | if (num & 1) { |
131 | 107 | return r & 0x0f; |
132 | 108 | } else { |
r23755 | r23756 | |
134 | 110 | } |
135 | 111 | } |
136 | 112 | |
137 | | INLINE void SET_REG(i4004_state *cpustate, UINT8 num, UINT8 val) |
| 113 | void i4004_cpu_device::SET_REG(UINT8 num, UINT8 val) |
138 | 114 | { |
139 | 115 | if (num & 1) { |
140 | | cpustate->R[num>>1] = (cpustate->R[num>>1] & 0xf0) + (val & 0x0f); |
| 116 | m_R[num>>1] = (m_R[num>>1] & 0xf0) + (val & 0x0f); |
141 | 117 | } else { |
142 | | cpustate->R[num>>1] = (cpustate->R[num>>1] & 0x0f) + ((val & 0x0f) << 4); |
| 118 | m_R[num>>1] = (m_R[num>>1] & 0x0f) + ((val & 0x0f) << 4); |
143 | 119 | } |
144 | 120 | } |
145 | 121 | |
146 | | INLINE void PUSH_STACK(i4004_state *cpustate) |
| 122 | void i4004_cpu_device::PUSH_STACK() |
147 | 123 | { |
148 | | cpustate->pc_pos = (cpustate->pc_pos + 1) & cpustate->addr_mask; |
| 124 | m_pc_pos = (m_pc_pos + 1) & m_addr_mask; |
149 | 125 | } |
150 | 126 | |
151 | | INLINE void POP_STACK(i4004_state *cpustate) |
| 127 | void i4004_cpu_device::POP_STACK() |
152 | 128 | { |
153 | | cpustate->ADDR[cpustate->pc_pos].d = 0; |
154 | | cpustate->pc_pos = (cpustate->pc_pos - 1) & cpustate->addr_mask; |
| 129 | m_ADDR[m_pc_pos].d = 0; |
| 130 | m_pc_pos = (m_pc_pos - 1) & m_addr_mask; |
155 | 131 | } |
156 | 132 | |
157 | | void i4004_set_test(device_t *device, UINT8 val) |
| 133 | void i4004_cpu_device::set_test(UINT8 val) |
158 | 134 | { |
159 | | i4004_state *cpustate = get_safe_token(device); |
160 | | cpustate->TEST = val; |
| 135 | m_TEST = val; |
161 | 136 | } |
162 | 137 | |
163 | | static void execute_one(i4004_state *cpustate, int opcode) |
| 138 | void i4004_cpu_device::execute_one(int opcode) |
164 | 139 | { |
165 | | cpustate->icount -= 8; |
| 140 | m_icount -= 8; |
166 | 141 | switch (opcode) |
167 | 142 | { |
168 | 143 | case 0x00: /* NOP */ |
r23755 | r23756 | |
173 | 148 | case 0x18: case 0x19: case 0x1a: case 0x1b: |
174 | 149 | case 0x1c: case 0x1d: case 0x1e: case 0x1f: /* JCN */ |
175 | 150 | { |
176 | | UINT8 arg = ARG(cpustate); |
| 151 | UINT8 arg = ARG(); |
177 | 152 | |
178 | 153 | UINT8 C1 = BIT(opcode,3); |
179 | 154 | UINT8 C2 = BIT(opcode,2); |
180 | 155 | UINT8 C3 = BIT(opcode,1); |
181 | 156 | UINT8 C4 = BIT(opcode,0); |
182 | | UINT8 JUMP = (((cpustate->A == 0) ? 1 : 0) & C2) | ((cpustate->C) & C3) | ((cpustate->TEST ^ 1) & C4); |
183 | | cpustate->icount -= 8; |
| 157 | UINT8 JUMP = (((m_A == 0) ? 1 : 0) & C2) | ((m_C) & C3) | ((m_TEST ^ 1) & C4); |
| 158 | m_icount -= 8; |
184 | 159 | |
185 | 160 | if(((C1 ^ 1) & JUMP) | (C1 & (JUMP ^ 1))) { |
186 | 161 | GET_PC.w.l = (GET_PC.w.l & 0x0f00) | arg; |
187 | | cpustate->PC = GET_PC; |
| 162 | m_PC = GET_PC; |
188 | 163 | } |
189 | 164 | } |
190 | 165 | break; |
191 | 166 | case 0x20: case 0x22: case 0x24: case 0x26: |
192 | 167 | case 0x28: case 0x2a: case 0x2c: case 0x2e: /* FIM */ |
193 | | cpustate->icount -= 8; |
194 | | cpustate->R[(opcode & 0x0f)>>1] = ROP(cpustate); |
| 168 | m_icount -= 8; |
| 169 | m_R[(opcode & 0x0f)>>1] = ROP(); |
195 | 170 | break; |
196 | 171 | case 0x21: case 0x23: case 0x25: case 0x27: |
197 | 172 | case 0x29: case 0x2b: case 0x2d: case 0x2f: /* SRC */ |
198 | | cpustate->RAM.b.l = cpustate->R[(opcode & 0x0f)>>1]; |
| 173 | m_RAM.b.l = m_R[(opcode & 0x0f)>>1]; |
199 | 174 | break; |
200 | 175 | case 0x30: case 0x32: case 0x34: case 0x36: |
201 | 176 | case 0x38: case 0x3a: case 0x3c: case 0x3e: /* FIN */ |
202 | | cpustate->icount -= 8; |
203 | | cpustate->R[(opcode & 0x0f)>>1] = READ_ROM(cpustate); |
| 177 | m_icount -= 8; |
| 178 | m_R[(opcode & 0x0f)>>1] = READ_ROM(); |
204 | 179 | break; |
205 | 180 | case 0x31: case 0x33: case 0x35: case 0x37: |
206 | 181 | case 0x39: case 0x3b: case 0x3d: case 0x3f: /* JIN */ |
207 | | GET_PC.w.l = (GET_PC.w.l & 0x0f00) | cpustate->R[(opcode & 0x0f)>>1]; |
208 | | cpustate->PC = GET_PC; |
| 182 | GET_PC.w.l = (GET_PC.w.l & 0x0f00) | m_R[(opcode & 0x0f)>>1]; |
| 183 | m_PC = GET_PC; |
209 | 184 | break; |
210 | 185 | case 0x40: case 0x41: case 0x42: case 0x43: |
211 | 186 | case 0x44: case 0x45: case 0x46: case 0x47: |
212 | 187 | case 0x48: case 0x49: case 0x4a: case 0x4b: |
213 | 188 | case 0x4c: case 0x4d: case 0x4e: case 0x4f: /* JUN */ |
214 | | cpustate->icount -= 8; |
215 | | GET_PC.w.l = ((opcode & 0x0f) << 8) | ARG(cpustate); |
216 | | cpustate->PC = GET_PC; |
| 189 | m_icount -= 8; |
| 190 | GET_PC.w.l = ((opcode & 0x0f) << 8) | ARG(); |
| 191 | m_PC = GET_PC; |
217 | 192 | break; |
218 | 193 | case 0x50: case 0x51: case 0x52: case 0x53: |
219 | 194 | case 0x54: case 0x55: case 0x56: case 0x57: |
220 | 195 | case 0x58: case 0x59: case 0x5a: case 0x5b: |
221 | 196 | case 0x5c: case 0x5d: case 0x5e: case 0x5f: /* JMS */ |
222 | 197 | { |
223 | | UINT16 newPC = ((opcode & 0x0f) << 8) | ARG(cpustate); |
224 | | cpustate->icount -= 8; |
225 | | PUSH_STACK(cpustate); |
| 198 | UINT16 newPC = ((opcode & 0x0f) << 8) | ARG(); |
| 199 | m_icount -= 8; |
| 200 | PUSH_STACK(); |
226 | 201 | GET_PC.w.l = newPC; |
227 | | cpustate->PC = GET_PC; |
| 202 | m_PC = GET_PC; |
228 | 203 | } |
229 | 204 | break; |
230 | 205 | case 0x60: case 0x61: case 0x62: case 0x63: |
231 | 206 | case 0x64: case 0x65: case 0x66: case 0x67: |
232 | 207 | case 0x68: case 0x69: case 0x6a: case 0x6b: |
233 | 208 | case 0x6c: case 0x6d: case 0x6e: case 0x6f: /* INC */ |
234 | | SET_REG(cpustate, opcode & 0x0f, GET_REG(cpustate, opcode & 0x0f) + 1); |
| 209 | SET_REG(opcode & 0x0f, GET_REG(opcode & 0x0f) + 1); |
235 | 210 | break; |
236 | 211 | case 0x70: case 0x71: case 0x72: case 0x73: |
237 | 212 | case 0x74: case 0x75: case 0x76: case 0x77: |
238 | 213 | case 0x78: case 0x79: case 0x7a: case 0x7b: |
239 | 214 | case 0x7c: case 0x7d: case 0x7e: case 0x7f: /* ISZ */ |
240 | 215 | { |
241 | | UINT8 val = (GET_REG(cpustate, opcode & 0x0f) + 1) & 0xf; |
242 | | UINT16 addr = ARG(cpustate); |
243 | | cpustate->icount -= 8; |
244 | | SET_REG(cpustate, opcode & 0x0f, val); |
| 216 | UINT8 val = (GET_REG(opcode & 0x0f) + 1) & 0xf; |
| 217 | UINT16 addr = ARG(); |
| 218 | m_icount -= 8; |
| 219 | SET_REG(opcode & 0x0f, val); |
245 | 220 | if (val!=0) { |
246 | 221 | GET_PC.w.l = (GET_PC.w.l & 0x0f00) | addr; |
247 | 222 | } |
248 | | cpustate->PC = GET_PC; |
| 223 | m_PC = GET_PC; |
249 | 224 | } |
250 | 225 | break; |
251 | 226 | case 0x80: case 0x81: case 0x82: case 0x83: |
r23755 | r23756 | |
253 | 228 | case 0x88: case 0x89: case 0x8a: case 0x8b: |
254 | 229 | case 0x8c: case 0x8d: case 0x8e: case 0x8f: /* ADD */ |
255 | 230 | { |
256 | | UINT8 acc = cpustate->A + GET_REG(cpustate, opcode & 0x0f) + cpustate->C; |
257 | | cpustate->A = acc & 0x0f; |
258 | | cpustate->C = (acc >> 4) & 1; |
| 231 | UINT8 acc = m_A + GET_REG(opcode & 0x0f) + m_C; |
| 232 | m_A = acc & 0x0f; |
| 233 | m_C = (acc >> 4) & 1; |
259 | 234 | } |
260 | 235 | break; |
261 | 236 | case 0x90: case 0x91: case 0x92: case 0x93: |
r23755 | r23756 | |
263 | 238 | case 0x98: case 0x99: case 0x9a: case 0x9b: |
264 | 239 | case 0x9c: case 0x9d: case 0x9e: case 0x9f: /* SUB */ |
265 | 240 | { |
266 | | UINT8 acc = cpustate->A + (GET_REG(cpustate, opcode & 0x0f) ^ 0x0f) + (cpustate->C ^ 1); |
267 | | cpustate->A = acc & 0x0f; |
268 | | cpustate->C = (acc >> 4) & 1; |
| 241 | UINT8 acc = m_A + (GET_REG(opcode & 0x0f) ^ 0x0f) + (m_C ^ 1); |
| 242 | m_A = acc & 0x0f; |
| 243 | m_C = (acc >> 4) & 1; |
269 | 244 | } |
270 | 245 | break; |
271 | 246 | case 0xa0: case 0xa1: case 0xa2: case 0xa3: |
272 | 247 | case 0xa4: case 0xa5: case 0xa6: case 0xa7: |
273 | 248 | case 0xa8: case 0xa9: case 0xaa: case 0xab: |
274 | 249 | case 0xac: case 0xad: case 0xae: case 0xaf: /* LD */ |
275 | | cpustate->A = GET_REG(cpustate, opcode & 0x0f); |
| 250 | m_A = GET_REG(opcode & 0x0f); |
276 | 251 | break; |
277 | 252 | case 0xb0: case 0xb1: case 0xb2: case 0xb3: |
278 | 253 | case 0xb4: case 0xb5: case 0xb6: case 0xb7: |
279 | 254 | case 0xb8: case 0xb9: case 0xba: case 0xbb: |
280 | 255 | case 0xbc: case 0xbd: case 0xbe: case 0xbf: /* XCH */ |
281 | 256 | { |
282 | | UINT8 temp = cpustate->A; |
283 | | cpustate->A = GET_REG(cpustate, opcode & 0x0f); |
284 | | SET_REG(cpustate, opcode & 0x0f, temp); |
| 257 | UINT8 temp = m_A; |
| 258 | m_A = GET_REG(opcode & 0x0f); |
| 259 | SET_REG(opcode & 0x0f, temp); |
285 | 260 | } |
286 | 261 | break; |
287 | 262 | case 0xc0: case 0xc1: case 0xc2: case 0xc3: |
288 | 263 | case 0xc4: case 0xc5: case 0xc6: case 0xc7: |
289 | 264 | case 0xc8: case 0xc9: case 0xca: case 0xcb: |
290 | 265 | case 0xcc: case 0xcd: case 0xce: case 0xcf: /* BBL */ |
291 | | POP_STACK(cpustate); |
292 | | cpustate->A = opcode & 0x0f; |
293 | | cpustate->PC = GET_PC; |
| 266 | POP_STACK(); |
| 267 | m_A = opcode & 0x0f; |
| 268 | m_PC = GET_PC; |
294 | 269 | break; |
295 | 270 | case 0xd0: case 0xd1: case 0xd2: case 0xd3: |
296 | 271 | case 0xd4: case 0xd5: case 0xd6: case 0xd7: |
297 | 272 | case 0xd8: case 0xd9: case 0xda: case 0xdb: |
298 | 273 | case 0xdc: case 0xdd: case 0xde: case 0xdf: /* LDM */ |
299 | | cpustate->A = opcode & 0x0f; |
| 274 | m_A = opcode & 0x0f; |
300 | 275 | break; |
301 | 276 | case 0xe0: /* WRM */ |
302 | | WM(cpustate,cpustate->A); |
| 277 | WM(m_A); |
303 | 278 | break; |
304 | 279 | case 0xe1: /* WMP */ |
305 | | WMP(cpustate,cpustate->A); |
| 280 | WMP(m_A); |
306 | 281 | break; |
307 | 282 | case 0xe2: /* WRR */ |
308 | | WIO(cpustate,cpustate->A); |
| 283 | WIO(m_A); |
309 | 284 | break; |
310 | 285 | case 0xe3: /* WPM */ |
311 | | WPM(cpustate); |
| 286 | WPM(); |
312 | 287 | break; |
313 | 288 | case 0xe4: /* WR0 */ |
314 | | WMS(cpustate,0,cpustate->A); |
| 289 | WMS(0,m_A); |
315 | 290 | break; |
316 | 291 | case 0xe5: /* WR1 */ |
317 | | WMS(cpustate,1,cpustate->A); |
| 292 | WMS(1,m_A); |
318 | 293 | break; |
319 | 294 | case 0xe6: /* WR2 */ |
320 | | WMS(cpustate,2,cpustate->A); |
| 295 | WMS(2,m_A); |
321 | 296 | break; |
322 | 297 | case 0xe7: /* WR3 */ |
323 | | WMS(cpustate,3,cpustate->A); |
| 298 | WMS(3,m_A); |
324 | 299 | break; |
325 | 300 | case 0xe8: /* SBM */ |
326 | | cpustate->A = cpustate->A + (RM(cpustate) ^ 0x0f) + (cpustate->C ^ 1); |
327 | | cpustate->C = cpustate->A >> 4; |
328 | | cpustate->A &= 0x0f; |
| 301 | m_A = m_A + (RM() ^ 0x0f) + (m_C ^ 1); |
| 302 | m_C = m_A >> 4; |
| 303 | m_A &= 0x0f; |
329 | 304 | break; |
330 | 305 | case 0xe9: /* RDM */ |
331 | | cpustate->A = RM(cpustate); |
| 306 | m_A = RM(); |
332 | 307 | break; |
333 | 308 | case 0xea: /* RDR */ |
334 | | cpustate->A = RIO(cpustate); |
| 309 | m_A = RIO(); |
335 | 310 | break; |
336 | 311 | case 0xeb: /* ADM */ |
337 | | cpustate->A += RM(cpustate) + cpustate->C; |
338 | | cpustate->C = cpustate->A >> 4; |
339 | | cpustate->A &= 0x0f; |
| 312 | m_A += RM() + m_C; |
| 313 | m_C = m_A >> 4; |
| 314 | m_A &= 0x0f; |
340 | 315 | break; |
341 | 316 | case 0xec: /* RD0 */ |
342 | | cpustate->A = RMS(cpustate,0); |
| 317 | m_A = RMS(0); |
343 | 318 | break; |
344 | 319 | case 0xed: /* RD1 */ |
345 | | cpustate->A = RMS(cpustate,1); |
| 320 | m_A = RMS(1); |
346 | 321 | break; |
347 | 322 | case 0xee: /* RD2 */ |
348 | | cpustate->A = RMS(cpustate,2); |
| 323 | m_A = RMS(2); |
349 | 324 | break; |
350 | 325 | case 0xef: /* RD3 */ |
351 | | cpustate->A = RMS(cpustate,3); |
| 326 | m_A = RMS(3); |
352 | 327 | break; |
353 | 328 | |
354 | 329 | case 0xf0: /* CLB */ |
355 | | cpustate->A = 0; |
356 | | cpustate->C = 0; |
| 330 | m_A = 0; |
| 331 | m_C = 0; |
357 | 332 | break; |
358 | 333 | case 0xf1: /* CLC */ |
359 | | cpustate->C = 0; |
| 334 | m_C = 0; |
360 | 335 | break; |
361 | 336 | case 0xf2: /* IAC */ |
362 | | cpustate->A += 1; |
363 | | cpustate->C = cpustate->A >> 4; |
364 | | cpustate->A &= 0x0f; |
| 337 | m_A += 1; |
| 338 | m_C = m_A >> 4; |
| 339 | m_A &= 0x0f; |
365 | 340 | break; |
366 | 341 | case 0xf3: /* CMC */ |
367 | | cpustate->C ^= 1; |
| 342 | m_C ^= 1; |
368 | 343 | break; |
369 | 344 | case 0xf4: /* CMA */ |
370 | | cpustate->A ^= 0x0f; |
| 345 | m_A ^= 0x0f; |
371 | 346 | break; |
372 | 347 | case 0xf5: /* RAL */ |
373 | | cpustate->A = (cpustate->A << 1) | cpustate->C; |
374 | | cpustate->C = cpustate->A >> 4; |
375 | | cpustate->A &= 0x0f; |
| 348 | m_A = (m_A << 1) | m_C; |
| 349 | m_C = m_A >> 4; |
| 350 | m_A &= 0x0f; |
376 | 351 | break; |
377 | 352 | case 0xf6: /* RAR */ |
378 | 353 | { |
379 | | UINT8 c = cpustate->A & 1; |
380 | | cpustate->A = (cpustate->A >> 1) | (cpustate->C << 3); |
381 | | cpustate->C = c; |
| 354 | UINT8 c = m_A & 1; |
| 355 | m_A = (m_A >> 1) | (m_C << 3); |
| 356 | m_C = c; |
382 | 357 | } |
383 | 358 | break; |
384 | 359 | case 0xf7: /* TCC */ |
385 | | cpustate->A = cpustate->C; |
386 | | cpustate->C = 0; |
| 360 | m_A = m_C; |
| 361 | m_C = 0; |
387 | 362 | break; |
388 | 363 | case 0xf8: /* DAC */ |
389 | | cpustate->A = cpustate->A + 0x0f; |
390 | | cpustate->C = cpustate->A >> 4; |
391 | | cpustate->A &= 0x0f; |
| 364 | m_A = m_A + 0x0f; |
| 365 | m_C = m_A >> 4; |
| 366 | m_A &= 0x0f; |
392 | 367 | break; |
393 | 368 | case 0xf9: /* TCS */ |
394 | | cpustate->A = cpustate->C ? 10 : 9; |
395 | | cpustate->C = 0; |
| 369 | m_A = m_C ? 10 : 9; |
| 370 | m_C = 0; |
396 | 371 | break; |
397 | 372 | case 0xfa: /* STC */ |
398 | | cpustate->C = 1; |
| 373 | m_C = 1; |
399 | 374 | break; |
400 | 375 | case 0xfb: /* DAA */ |
401 | | if (cpustate->C || (cpustate->A > 9)) { |
402 | | cpustate->A += 6; |
| 376 | if (m_C || (m_A > 9)) { |
| 377 | m_A += 6; |
403 | 378 | } |
404 | | if (cpustate->A > 0x0f) { |
| 379 | if (m_A > 0x0f) { |
405 | 380 | // it is unaffected if it is in range |
406 | | cpustate->C = 1; |
| 381 | m_C = 1; |
407 | 382 | } |
408 | | cpustate->A &= 0x0f; |
| 383 | m_A &= 0x0f; |
409 | 384 | break; |
410 | 385 | case 0xfc: /* KBP */ |
411 | | cpustate->A = kbp_table[cpustate->A]; |
| 386 | m_A = kbp_table[m_A]; |
412 | 387 | break; |
413 | 388 | case 0xfd: /* DCL */ |
414 | | cpustate->RAM.b.h = cpustate->A; |
| 389 | m_RAM.b.h = m_A; |
415 | 390 | break; |
416 | 391 | } |
417 | 392 | } |
r23755 | r23756 | |
421 | 396 | COMMON EXECUTION |
422 | 397 | ***************************************************************************/ |
423 | 398 | |
424 | | static CPU_EXECUTE( i4004 ) |
| 399 | void i4004_cpu_device::execute_run() |
425 | 400 | { |
426 | | i4004_state *cpustate = get_safe_token(device); |
427 | | |
428 | 401 | do |
429 | 402 | { |
430 | | debugger_instruction_hook(device, GET_PC.d); |
431 | | execute_one(cpustate, ROP(cpustate)); |
| 403 | debugger_instruction_hook(this, GET_PC.d); |
| 404 | execute_one(ROP()); |
432 | 405 | |
433 | | } while (cpustate->icount > 0); |
| 406 | } while (m_icount > 0); |
434 | 407 | } |
435 | 408 | |
436 | 409 | /*************************************************************************** |
437 | 410 | CORE INITIALIZATION |
438 | 411 | ***************************************************************************/ |
439 | 412 | |
440 | | static CPU_INIT( i4004 ) |
| 413 | void i4004_cpu_device::device_start() |
441 | 414 | { |
442 | | i4004_state *cpustate = get_safe_token(device); |
443 | | |
444 | 415 | /* set up the state table */ |
445 | 416 | { |
446 | | device_state_interface *state; |
447 | | device->interface(state); |
448 | | state->state_add(I4004_PC, "PC", cpustate->PC.w.l).mask(0x0fff); |
449 | | state->state_add(STATE_GENPC, "GENPC", cpustate->PC.w.l).mask(0x0fff).noshow(); |
450 | | state->state_add(STATE_GENFLAGS, "GENFLAGS", cpustate->flags).mask(0x0f).callimport().callexport().noshow().formatstr("%4s"); |
451 | | state->state_add(I4004_A, "A", cpustate->A).mask(0x0f); |
| 417 | state_add(I4004_PC, "PC", m_PC.w.l).mask(0x0fff); |
| 418 | state_add(STATE_GENPC, "GENPC", m_PC.w.l).mask(0x0fff).noshow(); |
| 419 | state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).mask(0x0f).callimport().callexport().noshow().formatstr("%4s"); |
| 420 | state_add(I4004_A, "A", m_A).mask(0x0f); |
452 | 421 | |
453 | 422 | astring tempstr; |
454 | 423 | for (int regnum = 0; regnum < 8; regnum++) |
455 | | state->state_add(I4004_R01 + regnum, tempstr.format("R%X%X", regnum*2, regnum*2+1), cpustate->R[regnum]); |
| 424 | { |
| 425 | state_add(I4004_R01 + regnum, tempstr.format("R%X%X", regnum*2, regnum*2+1), m_R[regnum]); |
| 426 | } |
456 | 427 | |
457 | 428 | for (int addrnum = 0; addrnum < 4; addrnum++) |
458 | | state->state_add(I4004_ADDR1 + addrnum, tempstr.format("ADDR%d", addrnum + 1), cpustate->ADDR[addrnum].w.l).mask(0xfff); |
| 429 | { |
| 430 | state_add(I4004_ADDR1 + addrnum, tempstr.format("ADDR%d", addrnum + 1), m_ADDR[addrnum].w.l).mask(0xfff); |
| 431 | } |
459 | 432 | |
460 | | state->state_add(I4004_RAM, "RAM", cpustate->RAM.w.l).mask(0x0fff); |
| 433 | state_add(I4004_RAM, "RAM", m_RAM.w.l).mask(0x0fff); |
461 | 434 | } |
462 | 435 | |
463 | | cpustate->device = device; |
| 436 | m_program = &space(AS_PROGRAM); |
| 437 | m_direct = &m_program->direct(); |
| 438 | m_data = &space(AS_DATA); |
| 439 | m_io = &space(AS_IO); |
464 | 440 | |
465 | | cpustate->program = &device->space(AS_PROGRAM); |
466 | | cpustate->direct = &cpustate->program->direct(); |
467 | | cpustate->data = &device->space(AS_DATA); |
468 | | cpustate->io = &device->space(AS_IO); |
| 441 | save_item(NAME(m_PC)); |
| 442 | save_item(NAME(m_A)); |
| 443 | save_item(NAME(m_C)); |
| 444 | save_item(NAME(m_TEST)); |
| 445 | save_item(NAME(m_pc_pos)); |
| 446 | save_item(NAME(m_ADDR[0])); |
| 447 | save_item(NAME(m_ADDR[1])); |
| 448 | save_item(NAME(m_ADDR[2])); |
| 449 | save_item(NAME(m_ADDR[3])); |
| 450 | save_item(NAME(m_R[0])); |
| 451 | save_item(NAME(m_R[1])); |
| 452 | save_item(NAME(m_R[2])); |
| 453 | save_item(NAME(m_R[3])); |
| 454 | save_item(NAME(m_R[4])); |
| 455 | save_item(NAME(m_R[5])); |
| 456 | save_item(NAME(m_R[6])); |
| 457 | save_item(NAME(m_R[7])); |
| 458 | save_item(NAME(m_RAM)); |
469 | 459 | |
470 | | device->save_item(NAME(cpustate->PC)); |
471 | | device->save_item(NAME(cpustate->A)); |
472 | | device->save_item(NAME(cpustate->C)); |
473 | | device->save_item(NAME(cpustate->TEST)); |
474 | | device->save_item(NAME(cpustate->pc_pos)); |
475 | | device->save_item(NAME(cpustate->ADDR[0])); |
476 | | device->save_item(NAME(cpustate->ADDR[1])); |
477 | | device->save_item(NAME(cpustate->ADDR[2])); |
478 | | device->save_item(NAME(cpustate->ADDR[3])); |
479 | | device->save_item(NAME(cpustate->R[0])); |
480 | | device->save_item(NAME(cpustate->R[1])); |
481 | | device->save_item(NAME(cpustate->R[2])); |
482 | | device->save_item(NAME(cpustate->R[3])); |
483 | | device->save_item(NAME(cpustate->R[4])); |
484 | | device->save_item(NAME(cpustate->R[5])); |
485 | | device->save_item(NAME(cpustate->R[6])); |
486 | | device->save_item(NAME(cpustate->R[7])); |
487 | | device->save_item(NAME(cpustate->RAM)); |
| 460 | m_icountptr = &m_icount; |
488 | 461 | } |
489 | 462 | |
490 | 463 | |
491 | | |
492 | 464 | /*************************************************************************** |
493 | 465 | COMMON RESET |
494 | 466 | ***************************************************************************/ |
495 | 467 | |
496 | | static CPU_RESET( i4004 ) |
| 468 | void i4004_cpu_device::device_reset() |
497 | 469 | { |
498 | | i4004_state *cpustate = get_safe_token(device); |
| 470 | m_addr_mask = 3; |
| 471 | m_C = 0; |
| 472 | m_pc_pos = 0; |
| 473 | m_A = 0; |
| 474 | memset(m_R,0,8); |
| 475 | memset(m_ADDR,0,sizeof(m_ADDR)); |
| 476 | m_RAM.d = 0; |
| 477 | m_PC = GET_PC; |
499 | 478 | |
500 | | cpustate->addr_mask = 3; |
501 | | cpustate->C = 0; |
502 | | cpustate->pc_pos = 0; |
503 | | cpustate->A = 0; |
504 | | memset(cpustate->R,0,8); |
505 | | memset(cpustate->ADDR,0,sizeof(cpustate->ADDR)); |
506 | | cpustate->RAM.d = 0; |
507 | | cpustate->PC = GET_PC; |
508 | | |
509 | 479 | } |
510 | 480 | |
511 | 481 | |
r23755 | r23756 | |
514 | 484 | COMMON STATE IMPORT/EXPORT |
515 | 485 | ***************************************************************************/ |
516 | 486 | |
517 | | static CPU_IMPORT_STATE( i4004 ) |
| 487 | void i4004_cpu_device::state_import(const device_state_entry &entry) |
518 | 488 | { |
519 | | i4004_state *cpustate = get_safe_token(device); |
520 | | |
521 | 489 | switch (entry.index()) |
522 | 490 | { |
523 | 491 | case STATE_GENFLAGS: |
524 | | cpustate->C = (cpustate->flags >> 1) & 1; |
525 | | cpustate->TEST = (cpustate->flags >> 0) & 1; |
| 492 | m_C = (m_flags >> 1) & 1; |
| 493 | m_TEST = (m_flags >> 0) & 1; |
526 | 494 | break; |
527 | 495 | } |
528 | 496 | } |
529 | 497 | |
530 | | static CPU_EXPORT_STATE( i4004 ) |
| 498 | void i4004_cpu_device::state_export(const device_state_entry &entry) |
531 | 499 | { |
532 | | i4004_state *cpustate = get_safe_token(device); |
533 | | |
534 | 500 | switch (entry.index()) |
535 | 501 | { |
536 | 502 | case STATE_GENFLAGS: |
537 | | cpustate->flags = ((cpustate->A == 0) ? 0x04 : 0x00) | |
538 | | (cpustate->C ? 0x02 : 0x00) | |
539 | | (cpustate->TEST ? 0x01 : 0x00); |
| 503 | m_flags = ((m_A == 0) ? 0x04 : 0x00) | |
| 504 | (m_C ? 0x02 : 0x00) | |
| 505 | (m_TEST ? 0x01 : 0x00); |
540 | 506 | break; |
541 | 507 | } |
542 | 508 | } |
543 | 509 | |
544 | | static CPU_EXPORT_STRING( i4004 ) |
| 510 | void i4004_cpu_device::state_string_export(const device_state_entry &entry, astring &string) |
545 | 511 | { |
546 | | i4004_state *cpustate = get_safe_token(device); |
547 | | |
548 | 512 | switch (entry.index()) |
549 | 513 | { |
550 | 514 | case STATE_GENFLAGS: |
551 | 515 | string.printf(".%c%c%c", |
552 | | (cpustate->A==0) ? 'Z':'.', |
553 | | cpustate->C ? 'C':'.', |
554 | | cpustate->TEST ? 'T':'.'); |
| 516 | (m_A==0) ? 'Z':'.', |
| 517 | m_C ? 'C':'.', |
| 518 | m_TEST ? 'T':'.'); |
555 | 519 | break; |
556 | 520 | } |
557 | 521 | } |
558 | 522 | |
559 | | /*************************************************************************** |
560 | | COMMON SET INFO |
561 | | ***************************************************************************/ |
562 | | static CPU_SET_INFO( i4004 ) |
| 523 | offs_t i4004_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) |
563 | 524 | { |
| 525 | extern CPU_DISASSEMBLE( i4004 ); |
| 526 | return CPU_DISASSEMBLE_NAME(i4004)(this, buffer, pc, oprom, opram, options); |
564 | 527 | } |
565 | 528 | |
566 | | /*************************************************************************** |
567 | | 4004 GET INFO |
568 | | ***************************************************************************/ |
569 | | |
570 | | CPU_GET_INFO( i4004 ) |
571 | | { |
572 | | i4004_state *cpustate = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL; |
573 | | switch (state) |
574 | | { |
575 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
576 | | case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(i4004_state); break; |
577 | | case CPUINFO_INT_INPUT_LINES: info->i = 0; break; |
578 | | case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; |
579 | | case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break; |
580 | | case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; |
581 | | case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; |
582 | | case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break; |
583 | | case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break; |
584 | | case CPUINFO_INT_MIN_CYCLES: info->i = 8; break; |
585 | | case CPUINFO_INT_MAX_CYCLES: info->i = 16; break; |
586 | | |
587 | | case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break; |
588 | | case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 12; break; |
589 | | case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break; |
590 | | |
591 | | case CPUINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 8; break; |
592 | | case CPUINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 12; break; |
593 | | case CPUINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break; |
594 | | |
595 | | case CPUINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break; // Only lower 4 bits used |
596 | | case CPUINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 6; break; // 4 I/O for each ROM chip and 4 OUT for each RAM |
597 | | case CPUINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break; // There could be 4 chips in 16 banks for RAM |
598 | | |
599 | | /* --- the following bits of info are returned as pointers to functions --- */ |
600 | | case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(i4004); break; |
601 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(i4004); break; |
602 | | case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(i4004); break; |
603 | | case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(i4004); break; |
604 | | case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(i4004); break; |
605 | | case CPUINFO_FCT_IMPORT_STATE: info->import_state = CPU_IMPORT_STATE_NAME(i4004); break; |
606 | | case CPUINFO_FCT_EXPORT_STATE: info->export_state = CPU_EXPORT_STATE_NAME(i4004); break; |
607 | | case CPUINFO_FCT_EXPORT_STRING: info->export_string = CPU_EXPORT_STRING_NAME(i4004); break; |
608 | | |
609 | | /* --- the following bits of info are returned as pointers --- */ |
610 | | case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break; |
611 | | |
612 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
613 | | case CPUINFO_STR_NAME: strcpy(info->s, "4004"); break; |
614 | | case CPUINFO_STR_FAMILY: strcpy(info->s, "Intel 4004"); break; |
615 | | case CPUINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
616 | | case CPUINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
617 | | case CPUINFO_STR_CREDITS: strcpy(info->s, "Copyright Miodrag Milanovic"); break; |
618 | | |
619 | | case CPUINFO_IS_OCTAL: info->i = true; break; |
620 | | } |
621 | | } |
622 | | |
623 | | DEFINE_LEGACY_CPU_DEVICE(I4004, i4004); |
| 529 | // case CPUINFO_IS_OCTAL: info->i = true; break; |