trunk/src/emu/cpu/ssem/ssem.c
| r19736 | r19737 | |
| 14 | 14 | #define SSEM_DISASM_ON_UNIMPL 0 |
| 15 | 15 | #define SSEM_DUMP_MEM_ON_UNIMPL 0 |
| 16 | 16 | |
| 17 | | struct ssem_state |
| 18 | | { |
| 19 | | UINT32 pc; |
| 20 | | UINT32 a; |
| 21 | | UINT32 halt; |
| 22 | | |
| 23 | | legacy_cpu_device *device; |
| 24 | | address_space *program; |
| 25 | | int icount; |
| 26 | | }; |
| 27 | | |
| 28 | | INLINE ssem_state *get_safe_token(device_t *device) |
| 29 | | { |
| 30 | | assert(device != NULL); |
| 31 | | assert(device->type() == SSEM); |
| 32 | | return (ssem_state *)downcast<legacy_cpu_device *>(device)->token(); |
| 33 | | } |
| 34 | | |
| 35 | 17 | #define INSTR ((op >> 13) & 7) |
| 36 | 18 | #define ADDR (op & 0x1f) |
| 37 | 19 | |
| r19736 | r19737 | |
| 58 | 40 | return v; |
| 59 | 41 | } |
| 60 | 42 | |
| 61 | | INLINE UINT32 READ32(ssem_state *cpustate, UINT32 address) |
| 43 | inline UINT32 ssem_device::program_read32(UINT32 address) |
| 62 | 44 | { |
| 63 | 45 | UINT32 v = 0; |
| 64 | 46 | // The MAME core does not have a good way of specifying a minimum datum size that is more than |
| r19736 | r19737 | |
| 66 | 48 | // the address value to get the appropriate byte index. |
| 67 | 49 | address <<= 2; |
| 68 | 50 | |
| 69 | | v |= cpustate->program->read_byte(address + 0) << 24; |
| 70 | | v |= cpustate->program->read_byte(address + 1) << 16; |
| 71 | | v |= cpustate->program->read_byte(address + 2) << 8; |
| 72 | | v |= cpustate->program->read_byte(address + 3) << 0; |
| 51 | v |= m_program->read_byte(address + 0) << 24; |
| 52 | v |= m_program->read_byte(address + 1) << 16; |
| 53 | v |= m_program->read_byte(address + 2) << 8; |
| 54 | v |= m_program->read_byte(address + 3) << 0; |
| 73 | 55 | |
| 74 | 56 | return reverse(v); |
| 75 | 57 | } |
| 76 | 58 | |
| 77 | | INLINE void WRITE32(ssem_state *cpustate, UINT32 address, UINT32 data) |
| 59 | inline void ssem_device::program_write32(UINT32 address, UINT32 data) |
| 78 | 60 | { |
| 79 | 61 | UINT32 v = reverse(data); |
| 80 | 62 | |
| r19736 | r19737 | |
| 83 | 65 | // the address value to get the appropriate byte index. |
| 84 | 66 | address <<= 2; |
| 85 | 67 | |
| 86 | | cpustate->program->write_byte(address + 0, (v >> 24) & 0x000000ff); |
| 87 | | cpustate->program->write_byte(address + 1, (v >> 16) & 0x000000ff); |
| 88 | | cpustate->program->write_byte(address + 2, (v >> 8) & 0x000000ff); |
| 89 | | cpustate->program->write_byte(address + 3, (v >> 0) & 0x000000ff); |
| 68 | m_program->write_byte(address + 0, (v >> 24) & 0x000000ff); |
| 69 | m_program->write_byte(address + 1, (v >> 16) & 0x000000ff); |
| 70 | m_program->write_byte(address + 2, (v >> 8) & 0x000000ff); |
| 71 | m_program->write_byte(address + 3, (v >> 0) & 0x000000ff); |
| 90 | 72 | return; |
| 91 | 73 | } |
| 92 | 74 | |
| 93 | 75 | /*****************************************************************************/ |
| 94 | 76 | |
| 95 | | static void unimplemented_opcode(ssem_state *cpustate, UINT32 op) |
| 77 | ssem_device::ssem_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 78 | : cpu_device(mconfig, SSEM, "SSEM", tag, owner, clock), |
| 79 | m_program_config("program", ENDIANNESS_LITTLE, 8, 16), |
| 80 | m_pc(1), |
| 81 | m_shifted_pc(1<<2), |
| 82 | m_a(0), |
| 83 | m_halt(0), |
| 84 | m_icount(0) |
| 96 | 85 | { |
| 97 | | if((cpustate->device->machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 98 | | { |
| 99 | | char string[200]; |
| 100 | | ssem_dasm_one(string, cpustate->pc-1, op); |
| 101 | | mame_printf_debug("%08X: %s\n", cpustate->pc-1, string); |
| 102 | | } |
| 86 | // Allocate & setup |
| 87 | } |
| 103 | 88 | |
| 104 | | #if SSEM_DISASM_ON_UNIMPL |
| 105 | | { |
| 106 | | char string[200] = { 0 }; |
| 107 | | UINT32 i = 0; |
| 108 | | FILE *disasm = fopen("ssemdasm.txt", "wt"); |
| 109 | 89 | |
| 110 | | if(disasm) |
| 111 | | { |
| 112 | | for(i = 0; i < 0x20; i++) |
| 113 | | { |
| 114 | | UINT32 opcode = reverse(READ32(cpustate, i)); |
| 115 | | ssem_dasm_one(string, i, opcode); |
| 116 | | fprintf(disasm, "%02X: %08X %s\n", i, opcode, string); |
| 117 | | } |
| 90 | void ssem_device::device_start() |
| 91 | { |
| 92 | m_program = &space(AS_PROGRAM); |
| 118 | 93 | |
| 119 | | fclose(disasm); |
| 120 | | } |
| 121 | | } |
| 122 | | #endif |
| 123 | | #if SSEM_DUMP_MEM_ON_UNIMPL |
| 124 | | { |
| 125 | | UINT32 i = 0; |
| 126 | | FILE *store = fopen("ssemmem.bin", "wb"); |
| 94 | // register our state for the debugger |
| 95 | astring tempstr; |
| 96 | state_add(STATE_GENPC, "GENPC", m_pc).noshow(); |
| 97 | state_add(STATE_GENFLAGS, "GENFLAGS", m_halt).callimport().callexport().formatstr("%1s").noshow(); |
| 98 | state_add(SSEM_PC, "PC", m_shifted_pc).mask(0xffff); |
| 99 | state_add(SSEM_A, "A", m_a).mask(0xffffffff); |
| 100 | state_add(SSEM_HALT, "HALT", m_halt).mask(0xf); |
| 127 | 101 | |
| 128 | | if(store) |
| 129 | | { |
| 130 | | for( i = 0; i < 0x80; i++ ) |
| 131 | | { |
| 132 | | fputc(cpustate->program->read_byte(i), store); |
| 133 | | } |
| 134 | | fclose(store); |
| 135 | | } |
| 136 | | } |
| 137 | | #endif |
| 102 | /* setup regtable */ |
| 103 | save_item(NAME(m_pc)); |
| 104 | save_item(NAME(m_a)); |
| 105 | save_item(NAME(m_halt)); |
| 138 | 106 | |
| 139 | | fatalerror("SSEM: unknown opcode %d (%08X) at %d\n", reverse(op) & 7, reverse(op), cpustate->pc); |
| 107 | // set our instruction counter |
| 108 | m_icountptr = &m_icount; |
| 140 | 109 | } |
| 141 | 110 | |
| 142 | | /*****************************************************************************/ |
| 111 | void ssem_device::device_stop() |
| 112 | { |
| 113 | } |
| 143 | 114 | |
| 144 | | static CPU_INIT( ssem ) |
| 115 | void ssem_device::device_reset() |
| 145 | 116 | { |
| 146 | | ssem_state *cpustate = get_safe_token(device); |
| 147 | | cpustate->pc = 1; |
| 148 | | cpustate->a = 0; |
| 149 | | cpustate->halt = 0; |
| 117 | m_pc = 1; |
| 118 | m_shifted_pc = m_pc << 2; |
| 119 | m_a = 0; |
| 120 | m_halt = 0; |
| 121 | } |
| 150 | 122 | |
| 151 | | cpustate->device = device; |
| 152 | | cpustate->program = &device->space(AS_PROGRAM); |
| 123 | |
| 124 | //------------------------------------------------- |
| 125 | // memory_space_config - return the configuration |
| 126 | // of the specified address space, or NULL if |
| 127 | // the space doesn't exist |
| 128 | //------------------------------------------------- |
| 129 | |
| 130 | const address_space_config *ssem_device::memory_space_config(address_spacenum spacenum) const |
| 131 | { |
| 132 | if (spacenum == AS_PROGRAM) |
| 133 | { |
| 134 | return &m_program_config; |
| 135 | } |
| 136 | return NULL; |
| 153 | 137 | } |
| 154 | 138 | |
| 155 | | static CPU_EXIT( ssem ) |
| 139 | |
| 140 | //------------------------------------------------- |
| 141 | // state_string_export - export state as a string |
| 142 | // for the debugger |
| 143 | //------------------------------------------------- |
| 144 | |
| 145 | void ssem_device::state_string_export(const device_state_entry &entry, astring &string) |
| 156 | 146 | { |
| 147 | switch (entry.index()) |
| 148 | { |
| 149 | case STATE_GENFLAGS: |
| 150 | string.printf("%c", m_halt ? 'H' : '.'); |
| 151 | break; |
| 152 | } |
| 157 | 153 | } |
| 158 | 154 | |
| 159 | | static CPU_RESET( ssem ) |
| 155 | |
| 156 | //------------------------------------------------- |
| 157 | // disasm_min_opcode_bytes - return the length |
| 158 | // of the shortest instruction, in bytes |
| 159 | //------------------------------------------------- |
| 160 | |
| 161 | UINT32 ssem_device::disasm_min_opcode_bytes() const |
| 160 | 162 | { |
| 161 | | ssem_state *cpustate = get_safe_token(device); |
| 163 | return 4; |
| 164 | } |
| 162 | 165 | |
| 163 | | cpustate->pc = 1; |
| 164 | | cpustate->a = 0; |
| 165 | | cpustate->halt = 0; |
| 166 | |
| 167 | //------------------------------------------------- |
| 168 | // disasm_max_opcode_bytes - return the length |
| 169 | // of the longest instruction, in bytes |
| 170 | //------------------------------------------------- |
| 171 | |
| 172 | UINT32 ssem_device::disasm_max_opcode_bytes() const |
| 173 | { |
| 174 | return 4; |
| 166 | 175 | } |
| 167 | 176 | |
| 168 | | static CPU_EXECUTE( ssem ) |
| 177 | |
| 178 | //------------------------------------------------- |
| 179 | // disasm_disassemble - call the disassembly |
| 180 | // helper function |
| 181 | //------------------------------------------------- |
| 182 | |
| 183 | offs_t ssem_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) |
| 169 | 184 | { |
| 170 | | ssem_state *cpustate = get_safe_token(device); |
| 185 | extern CPU_DISASSEMBLE( ssem ); |
| 186 | return disassemble(buffer, pc, oprom, opram, 0); |
| 187 | } |
| 188 | |
| 189 | |
| 190 | //************************************************************************** |
| 191 | // CORE EXECUTION LOOP |
| 192 | //************************************************************************** |
| 193 | |
| 194 | //------------------------------------------------- |
| 195 | // execute_min_cycles - return minimum number of |
| 196 | // cycles it takes for one instruction to execute |
| 197 | //------------------------------------------------- |
| 198 | |
| 199 | UINT32 ssem_device::execute_min_cycles() const |
| 200 | { |
| 201 | return 1; |
| 202 | } |
| 203 | |
| 204 | |
| 205 | //------------------------------------------------- |
| 206 | // execute_max_cycles - return maximum number of |
| 207 | // cycles it takes for one instruction to execute |
| 208 | //------------------------------------------------- |
| 209 | |
| 210 | UINT32 ssem_device::execute_max_cycles() const |
| 211 | { |
| 212 | return 1; |
| 213 | } |
| 214 | |
| 215 | |
| 216 | //------------------------------------------------- |
| 217 | // execute_input_lines - return the number of |
| 218 | // input/interrupt lines |
| 219 | //------------------------------------------------- |
| 220 | |
| 221 | UINT32 ssem_device::execute_input_lines() const |
| 222 | { |
| 223 | return 0; |
| 224 | } |
| 225 | |
| 226 | |
| 227 | //------------------------------------------------- |
| 228 | // execute_set_input - set the state of an input |
| 229 | // line during execution |
| 230 | //------------------------------------------------- |
| 231 | |
| 232 | void ssem_device::execute_set_input(int inputnum, int state) |
| 233 | { |
| 234 | } |
| 235 | |
| 236 | |
| 237 | //------------------------------------------------- |
| 238 | // execute_run - execute a timeslice's worth of |
| 239 | // opcodes |
| 240 | //------------------------------------------------- |
| 241 | |
| 242 | void ssem_device::execute_run() |
| 243 | { |
| 171 | 244 | UINT32 op; |
| 172 | 245 | |
| 173 | | cpustate->pc &= 0x1f; |
| 246 | m_pc &= 0x1f; |
| 247 | m_shifted_pc = m_pc << 2; |
| 174 | 248 | |
| 175 | | while (cpustate->icount > 0) |
| 249 | while (m_icount > 0) |
| 176 | 250 | { |
| 177 | | debugger_instruction_hook(device, cpustate->pc); |
| 251 | debugger_instruction_hook(this, m_pc); |
| 178 | 252 | |
| 179 | | op = READ32(cpustate, cpustate->pc); |
| 253 | op = program_read32(m_pc); |
| 180 | 254 | |
| 181 | | if( !cpustate->halt ) |
| 255 | if( !m_halt ) |
| 182 | 256 | { |
| 183 | | cpustate->pc++; |
| 257 | m_pc++; |
| 258 | m_shifted_pc = m_pc << 2; |
| 184 | 259 | } |
| 185 | 260 | else |
| 186 | 261 | { |
| r19736 | r19737 | |
| 191 | 266 | { |
| 192 | 267 | case 0: |
| 193 | 268 | // JMP: Move the value at the specified address into the Program Counter. |
| 194 | | cpustate->pc = READ32(cpustate, ADDR) + 1; |
| 269 | m_pc = program_read32(ADDR) + 1; |
| 270 | m_shifted_pc = m_pc << 2; |
| 195 | 271 | break; |
| 196 | 272 | case 1: |
| 197 | 273 | // JRP: Add the value at the specified address to the Program Counter. |
| 198 | | cpustate->pc += (INT32)READ32(cpustate, ADDR); |
| 274 | m_pc += (INT32)program_read32(ADDR); |
| 275 | m_shifted_pc = m_pc << 2; |
| 199 | 276 | break; |
| 200 | 277 | case 2: |
| 201 | 278 | // LDN: Load the accumulator with the two's-complement negation of the value at the specified address. |
| 202 | | cpustate->a = (UINT32)(0 - (INT32)READ32(cpustate, ADDR)); |
| 279 | m_a = (UINT32)(0 - (INT32)program_read32(ADDR)); |
| 203 | 280 | break; |
| 204 | 281 | case 3: |
| 205 | 282 | // STO: Store the value in the accumulator at the specified address. |
| 206 | | WRITE32(cpustate, ADDR, cpustate->a); |
| 283 | program_write32(ADDR, m_a); |
| 207 | 284 | break; |
| 208 | 285 | case 4: |
| 209 | 286 | case 5: |
| 210 | 287 | // SUB: Subtract the value at the specified address from the accumulator. |
| 211 | | cpustate->a -= READ32(cpustate, ADDR); |
| 288 | m_a -= program_read32(ADDR); |
| 212 | 289 | break; |
| 213 | 290 | case 6: |
| 214 | 291 | // CMP: If the accumulator is less than zero, skip the next opcode. |
| 215 | | if((INT32)(cpustate->a) < 0) |
| 292 | if((INT32)(m_a) < 0) |
| 216 | 293 | { |
| 217 | | cpustate->pc++; |
| 294 | m_pc++; |
| 295 | m_shifted_pc = m_pc << 2; |
| 218 | 296 | } |
| 219 | 297 | break; |
| 220 | 298 | case 7: |
| 221 | 299 | // STP: Halt the computer. |
| 222 | | cpustate->halt = 1; |
| 300 | m_halt = 1; |
| 223 | 301 | break; |
| 224 | 302 | default: |
| 225 | | // This is impossible, but it's better to be safe than sorry. |
| 226 | | unimplemented_opcode(cpustate, op); |
| 303 | break; |
| 227 | 304 | } |
| 228 | 305 | |
| 229 | | --cpustate->icount; |
| 306 | --m_icount; |
| 230 | 307 | } |
| 231 | 308 | } |
| 232 | | |
| 233 | | |
| 234 | | /*****************************************************************************/ |
| 235 | | |
| 236 | | static CPU_SET_INFO( ssem ) |
| 237 | | { |
| 238 | | ssem_state *cpustate = get_safe_token(device); |
| 239 | | |
| 240 | | switch (state) |
| 241 | | { |
| 242 | | /* --- the following bits of info are set as 64-bit signed integers --- */ |
| 243 | | case CPUINFO_INT_PC: |
| 244 | | case CPUINFO_INT_REGISTER + SSEM_PC: cpustate->pc = info->i; break; |
| 245 | | case CPUINFO_INT_REGISTER + SSEM_A: cpustate->a = info->i; break; |
| 246 | | case CPUINFO_INT_REGISTER + SSEM_HALT: cpustate->halt = info->i; break; |
| 247 | | } |
| 248 | | } |
| 249 | | |
| 250 | | CPU_GET_INFO( ssem ) |
| 251 | | { |
| 252 | | ssem_state *cpustate = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL; |
| 253 | | |
| 254 | | switch(state) |
| 255 | | { |
| 256 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 257 | | case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ssem_state); break; |
| 258 | | case CPUINFO_INT_INPUT_LINES: info->i = 0; break; |
| 259 | | case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; |
| 260 | | case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break; |
| 261 | | case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; |
| 262 | | case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; |
| 263 | | case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; |
| 264 | | case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; |
| 265 | | case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; |
| 266 | | case CPUINFO_INT_MAX_CYCLES: info->i = 1; break; |
| 267 | | |
| 268 | | case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break; |
| 269 | | case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 16; break; |
| 270 | | case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break; |
| 271 | | case CPUINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break; |
| 272 | | case CPUINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break; |
| 273 | | case CPUINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break; |
| 274 | | case CPUINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 0; break; |
| 275 | | case CPUINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 0; break; |
| 276 | | case CPUINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break; |
| 277 | | |
| 278 | | case CPUINFO_INT_PC: /* intentional fallthrough */ |
| 279 | | case CPUINFO_INT_REGISTER + SSEM_PC: info->i = cpustate->pc << 2; break; |
| 280 | | case CPUINFO_INT_REGISTER + SSEM_A: info->i = cpustate->a; break; |
| 281 | | case CPUINFO_INT_REGISTER + SSEM_HALT: info->i = cpustate->halt; break; |
| 282 | | |
| 283 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 284 | | case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ssem); break; |
| 285 | | case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ssem); break; |
| 286 | | case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ssem); break; |
| 287 | | case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(ssem); break; |
| 288 | | case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ssem); break; |
| 289 | | case CPUINFO_FCT_BURN: info->burn = NULL; break; |
| 290 | | case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(ssem); break; |
| 291 | | case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break; |
| 292 | | |
| 293 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 294 | | case CPUINFO_STR_NAME: strcpy(info->s, "SSEM"); break; |
| 295 | | case CPUINFO_STR_FAMILY: strcpy(info->s, "SSEM"); break; |
| 296 | | case CPUINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 297 | | case CPUINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 298 | | case CPUINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; |
| 299 | | |
| 300 | | case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; |
| 301 | | |
| 302 | | case CPUINFO_STR_REGISTER + SSEM_PC: sprintf(info->s, "PC: %08X", cpustate->pc); break; |
| 303 | | case CPUINFO_STR_REGISTER + SSEM_A: sprintf(info->s, "A: %08X", cpustate->a); break; |
| 304 | | case CPUINFO_STR_REGISTER + SSEM_HALT: sprintf(info->s, "HALT: %d", cpustate->halt); break; |
| 305 | | } |
| 306 | | } |
| 307 | | |
| 308 | | DEFINE_LEGACY_CPU_DEVICE(SSEM, ssem); |