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; |