trunk/src/emu/cpu/dsp16/dsp16.h
| r20095 | r20096 | |
| 13 | 13 | |
| 14 | 14 | |
| 15 | 15 | //************************************************************************** |
| 16 | | // INTERFACE CONFIGURATION MACROS |
| 17 | | //************************************************************************** |
| 18 | | |
| 19 | | //#define MCFG_DSP16_CONFIG(_config) |
| 20 | | // dsp16_device::static_set_config(*device, _config); |
| 21 | | |
| 22 | | |
| 23 | | |
| 24 | | //************************************************************************** |
| 25 | 16 | // TYPE DEFINITIONS |
| 26 | 17 | //************************************************************************** |
| 27 | 18 | |
| r20095 | r20096 | |
| 95 | 86 | // internal stuff |
| 96 | 87 | UINT16 m_ppc; |
| 97 | 88 | |
| 89 | // This core handles the cache as more of a loop than 15 seperate memory elements. |
| 90 | // It's a bit of a hack, but it's easier this way. |
| 91 | UINT16 m_cacheStart; |
| 92 | UINT16 m_cacheEnd; |
| 93 | UINT16 m_cacheRedoNextPC; |
| 94 | UINT16 m_cacheIterations; |
| 95 | static const UINT16 CACHE_INVALID = 0xffff; |
| 96 | |
| 98 | 97 | // memory access |
| 99 | 98 | inline UINT32 program_read(UINT32 addr); |
| 100 | 99 | inline void program_write(UINT32 addr, UINT32 data); |
| r20095 | r20096 | |
| 108 | 107 | int m_icount; |
| 109 | 108 | |
| 110 | 109 | // operations |
| 111 | | void execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance); |
| 110 | void execute_one(const UINT16& op, UINT8& cycles, INT16& pcAdvance); |
| 112 | 111 | |
| 112 | // table decoders |
| 113 | void* registerFromRImmediateField(const UINT8& R); |
| 113 | 114 | void* registerFromRTable(const UINT8& R); |
| 114 | 115 | |
| 115 | 116 | // helpers |
| 116 | 117 | void* addressYL(); |
| 117 | | //void writeYxRegister(const UINT16& value); |
| 118 | 118 | void writeRegister(void* reg, const UINT16& value); |
| 119 | 119 | }; |
| 120 | 120 | |
trunk/src/emu/cpu/dsp16/dsp16.c
| r20095 | r20096 | |
| 10 | 10 | #include "debugger.h" |
| 11 | 11 | #include "dsp16.h" |
| 12 | 12 | |
| 13 | // |
| 14 | // TODO: |
| 15 | // * Store the cache in 15 unique memory locations as it is on-chip. |
| 16 | // * Modify cycle counts when running from within the cache |
| 17 | // |
| 13 | 18 | |
| 14 | 19 | //************************************************************************** |
| 15 | 20 | // DEVICE INTERFACE |
| r20095 | r20096 | |
| 52 | 57 | m_sioc(0), |
| 53 | 58 | m_pioc(0), |
| 54 | 59 | m_ppc(0), |
| 60 | m_cacheStart(CACHE_INVALID), |
| 61 | m_cacheEnd(CACHE_INVALID), |
| 62 | m_cacheRedoNextPC(CACHE_INVALID), |
| 63 | m_cacheIterations(0), |
| 55 | 64 | m_program(NULL), |
| 56 | 65 | m_direct(NULL), |
| 57 | 66 | m_icount(0) |
| r20095 | r20096 | |
| 69 | 78 | { |
| 70 | 79 | // register state with the debugger |
| 71 | 80 | state_add(STATE_GENPC, "GENPC", m_pc).noshow(); |
| 81 | //state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); |
| 72 | 82 | state_add(STATE_GENFLAGS, "GENFLAGS", m_psw).callimport().callexport().formatstr("%10s").noshow(); |
| 73 | 83 | state_add(DSP16_PC, "PC", m_pc); |
| 74 | 84 | state_add(DSP16_I, "I", m_i); |
| r20095 | r20096 | |
| 96 | 106 | state_add(DSP16_SIOC, "SIOC", m_sioc).formatstr("%16s"); |
| 97 | 107 | state_add(DSP16_PIOC, "PIOC", m_pioc); //.formatstr("%16s"); |
| 98 | 108 | |
| 109 | // register our state for saving |
| 99 | 110 | save_item(NAME(m_i)); |
| 100 | 111 | save_item(NAME(m_pc)); |
| 101 | 112 | save_item(NAME(m_pt)); |
| r20095 | r20096 | |
| 121 | 132 | save_item(NAME(m_c2)); |
| 122 | 133 | save_item(NAME(m_sioc)); |
| 123 | 134 | save_item(NAME(m_pioc)); |
| 135 | save_item(NAME(m_ppc)); |
| 136 | save_item(NAME(m_cacheStart)); |
| 137 | save_item(NAME(m_cacheEnd)); |
| 138 | save_item(NAME(m_cacheRedoNextPC)); |
| 139 | save_item(NAME(m_cacheIterations)); |
| 124 | 140 | |
| 125 | 141 | // get our address spaces |
| 126 | 142 | m_program = &space(AS_PROGRAM); |
| r20095 | r20096 | |
| 145 | 161 | m_re = 0x0000; |
| 146 | 162 | // AUC is not affected by reset |
| 147 | 163 | m_ppc = m_pc; |
| 164 | |
| 165 | // Hacky cache emulation. |
| 166 | m_cacheStart = CACHE_INVALID; |
| 167 | m_cacheEnd = CACHE_INVALID; |
| 168 | m_cacheRedoNextPC = CACHE_INVALID; |
| 169 | m_cacheIterations = 0; |
| 148 | 170 | } |
| 149 | 171 | |
| 150 | 172 | |
| r20095 | r20096 | |
| 170 | 192 | switch (entry.index()) |
| 171 | 193 | { |
| 172 | 194 | case STATE_GENFLAGS: |
| 173 | | string.printf("(multiple below)"); |
| 195 | string.printf("(below)"); |
| 174 | 196 | break; |
| 175 | 197 | |
| 176 | 198 | // Placeholder for a better view later (TODO) |
| r20095 | r20096 | |
| 290 | 312 | |
| 291 | 313 | // instruction fetch & execute |
| 292 | 314 | UINT8 cycles; |
| 293 | | UINT8 pcAdvance; |
| 315 | INT16 pcAdvance; |
| 294 | 316 | const UINT16 op = opcode_read(); |
| 317 | printf("%d ", m_cacheIterations); |
| 295 | 318 | execute_one(op, cycles, pcAdvance); |
| 319 | printf("%d\n", m_cacheIterations); |
| 296 | 320 | |
| 297 | | // step forward |
| 321 | // step |
| 298 | 322 | m_pc += pcAdvance; |
| 299 | 323 | m_icount -= cycles; |
| 300 | 324 | |
trunk/src/emu/cpu/dsp16/dsp16ops.c
| r20095 | r20096 | |
| 10 | 10 | |
| 11 | 11 | void dsp16_device::writeRegister(void* reg, const UINT16 &value) |
| 12 | 12 | { |
| 13 | // Make sure you're not attempting to write somewhere this function doesn't support. |
| 14 | if (reg == &m_p || reg == &m_a0 || reg == &m_a1) |
| 15 | { |
| 16 | logerror("dsp16::writeRegister called on invalid register at PC 0x%04x.\n", m_pc); |
| 17 | return; |
| 18 | } |
| 19 | |
| 13 | 20 | if (reg == &m_auc || reg == &m_c0 || reg == &m_c1 || reg == &m_c2) |
| 14 | 21 | { |
| 15 | | *(UINT8*)reg = value & 0x00ff; // 8 bit registers |
| 22 | // 8 bit registers |
| 23 | *(UINT8*)reg = value & 0x00ff; |
| 16 | 24 | } |
| 17 | 25 | else if (reg == &m_i) |
| 18 | 26 | { |
| 19 | | m_i = value & 0x0fff; // 12 bit register |
| 27 | // 12 bit register |
| 28 | m_i = value & 0x0fff; |
| 20 | 29 | } |
| 21 | 30 | else if (reg == &m_y) |
| 22 | 31 | { |
| 23 | | //writeYxRegister(value); // TODO - check a flag to see if clearing yl is necessary |
| 24 | | m_y = (value << 16) | (m_y & 0x0000ffff); // Temporary |
| 32 | // Y register [[TODO - check a flag to see if clearing yl is necessary]] |
| 33 | m_y = (value << 16) | (m_y & 0x0000ffff); |
| 25 | 34 | } |
| 26 | 35 | else if (reg == addressYL()) |
| 27 | 36 | { |
| 28 | | m_y = value | (m_y & 0xffff0000); // Temporary |
| 37 | // Yl register |
| 38 | m_y = value | (m_y & 0xffff0000); |
| 29 | 39 | } |
| 30 | 40 | else |
| 31 | 41 | { |
| 32 | | *(UINT16*)reg = value; // The rest |
| 42 | // Everything else |
| 43 | *(UINT16*)reg = value; |
| 33 | 44 | } |
| 34 | 45 | } |
| 35 | 46 | |
| 36 | 47 | |
| 48 | void* dsp16_device::registerFromRImmediateField(const UINT8& R) |
| 49 | { |
| 50 | switch (R) |
| 51 | { |
| 52 | case 0x00: return (void*)&m_j; |
| 53 | case 0x01: return (void*)&m_k; |
| 54 | case 0x02: return (void*)&m_rb; |
| 55 | case 0x03: return (void*)&m_re; |
| 56 | case 0x04: return (void*)&m_r0; |
| 57 | case 0x05: return (void*)&m_r1; |
| 58 | case 0x06: return (void*)&m_r2; |
| 59 | case 0x07: return (void*)&m_r3; |
| 60 | |
| 61 | default: return NULL; |
| 62 | } |
| 63 | return NULL; |
| 64 | } |
| 65 | |
| 66 | |
| 37 | 67 | void* dsp16_device::registerFromRTable(const UINT8 &R) |
| 38 | 68 | { |
| 39 | 69 | switch (R) |
| r20095 | r20096 | |
| 73 | 103 | } |
| 74 | 104 | |
| 75 | 105 | |
| 76 | | void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance) |
| 106 | void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, INT16& pcAdvance) |
| 77 | 107 | { |
| 78 | 108 | cycles = 1; |
| 79 | 109 | pcAdvance = 1; |
| r20095 | r20096 | |
| 286 | 316 | const UINT16 iVal = opcode_read(1); |
| 287 | 317 | void* reg = registerFromRTable(R); |
| 288 | 318 | writeRegister(reg, iVal); |
| 289 | | |
| 290 | 319 | cycles = 2; |
| 291 | 320 | pcAdvance = 2; |
| 292 | 321 | break; |
| r20095 | r20096 | |
| 296 | 325 | case 0x02: case 0x03: |
| 297 | 326 | { |
| 298 | 327 | // R = M |
| 299 | | //const UINT8 M = (op & 0x00ff); |
| 300 | | //const UINT8 R = (op & 0x0e00) >> 9; |
| 328 | const INT8 M = (op & 0x00ff); |
| 329 | const UINT8 R = (op & 0x0e00) >> 9; |
| 330 | void* reg = registerFromRImmediateField(R); |
| 331 | writeRegister(reg, (INT16)M); // Sign extend 8 bit int |
| 332 | cycles = 1; |
| 301 | 333 | break; |
| 302 | 334 | } |
| 303 | 335 | |
| r20095 | r20096 | |
| 305 | 337 | case 0x0e: |
| 306 | 338 | { |
| 307 | 339 | // do|redo K |
| 308 | | //const UINT8 K = (op & 0x007f); |
| 309 | | //const UINT8 NI = (op & 0x0780) >> 7; |
| 340 | const UINT8 K = (op & 0x007f); |
| 341 | const UINT8 NI = (op & 0x0780) >> 7; |
| 342 | if (NI != 0) |
| 343 | { |
| 344 | // Do |
| 345 | m_cacheStart = m_pc + 1; |
| 346 | m_cacheEnd = m_pc + NI + 1; |
| 347 | m_cacheIterations = K+1; |
| 348 | cycles = 1; |
| 349 | } |
| 350 | else |
| 351 | { |
| 352 | // Redo |
| 353 | m_cacheIterations = K+1; |
| 354 | m_cacheRedoNextPC = m_pc + 1; |
| 355 | pcAdvance = m_cacheStart - m_pc; |
| 356 | cycles = 2; |
| 357 | } |
| 310 | 358 | break; |
| 311 | 359 | } |
| 312 | 360 | |
| r20095 | r20096 | |
| 322 | 370 | break; |
| 323 | 371 | } |
| 324 | 372 | } |
| 373 | |
| 374 | // Handle end-of-cache conditions for do|redos |
| 375 | if (m_cacheIterations == 0 && m_cacheRedoNextPC != CACHE_INVALID) |
| 376 | { |
| 377 | // You've reached the end of a cache loop after a redo opcode. |
| 378 | pcAdvance = m_cacheRedoNextPC - m_pc; |
| 379 | m_cacheRedoNextPC = CACHE_INVALID; |
| 380 | } |
| 381 | if (m_cacheIterations > 0 && (m_pc+pcAdvance == m_cacheEnd)) |
| 382 | { |
| 383 | // A regular iteration on a cached loop. |
| 384 | m_cacheIterations--; |
| 385 | pcAdvance = m_cacheStart - m_pc; |
| 386 | } |
| 325 | 387 | } |