trunk/src/emu/cpu/ie15/ie15.c
r0 | r22732 | |
| 1 | #include "emu.h" |
| 2 | #include "debugger.h" |
| 3 | #include "ie15.h" |
| 4 | |
| 5 | //************************************************************************** |
| 6 | // MACROS |
| 7 | //************************************************************************** |
| 8 | |
| 9 | #define SKIP_OP(x) do { \ |
| 10 | x = rop() & 0xf0; \ |
| 11 | if (x == 0x10 || x == 0x20 || x == 0x30) \ |
| 12 | m_PC.w.l = m_PC.w.l + 1; \ |
| 13 | } while(0) |
| 14 | |
| 15 | //************************************************************************** |
| 16 | // GLOBAL VARIABLES |
| 17 | //************************************************************************** |
| 18 | |
| 19 | // device type definition |
| 20 | const device_type IE15 = &device_creator<ie15_device>; |
| 21 | |
| 22 | //************************************************************************** |
| 23 | // DEVICE INTERFACE |
| 24 | //************************************************************************** |
| 25 | |
| 26 | //------------------------------------------------- |
| 27 | // ie15_device - constructor |
| 28 | //------------------------------------------------- |
| 29 | ie15_device::ie15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 30 | : cpu_device(mconfig, IE15, "ie15", tag, owner, clock), |
| 31 | m_program_config("program", ENDIANNESS_LITTLE, 8, 14), |
| 32 | m_io_config("io", ENDIANNESS_LITTLE, 8, 8), |
| 33 | m_program(0), |
| 34 | m_direct(0) |
| 35 | { |
| 36 | // set our instruction counter |
| 37 | m_icountptr = &m_icount; |
| 38 | }; |
| 39 | |
| 40 | //------------------------------------------------- |
| 41 | // device_start - start up the device |
| 42 | //------------------------------------------------- |
| 43 | |
| 44 | void ie15_device::device_start() |
| 45 | { |
| 46 | // find address spaces |
| 47 | m_program = &space(AS_PROGRAM); |
| 48 | m_direct = &m_program->direct(); |
| 49 | m_io = &space(AS_IO); |
| 50 | |
| 51 | // save state |
| 52 | save_item(NAME(m_PC)); |
| 53 | save_item(NAME(m_A)); |
| 54 | save_item(NAME(m_CF)); |
| 55 | save_item(NAME(m_ZF)); |
| 56 | save_item(NAME(m_RF)); |
| 57 | // XXX save registers |
| 58 | |
| 59 | // register our state for the debugger |
| 60 | state_add(IE15_PC, "PC", m_PC.w.l).mask(0x0fff); |
| 61 | state_add(STATE_GENPC, "GENPC", m_PC.w.l).mask(0x0fff).noshow(); |
| 62 | state_add(STATE_GENFLAGS,"GENFLAGS", m_flags).mask(0x0f).callimport().callexport().noshow().formatstr("%4s"); |
| 63 | state_add(IE15_A, "A", m_A); |
| 64 | |
| 65 | astring tempstring; |
| 66 | for (int ireg = 0; ireg < 32; ireg++) |
| 67 | state_add(IE15_R0 + ireg, tempstring.format("R%d", ireg), m_REGS[ireg]); |
| 68 | } |
| 69 | |
| 70 | //------------------------------------------------- |
| 71 | // device_reset - reset the device |
| 72 | //------------------------------------------------- |
| 73 | |
| 74 | void ie15_device::device_reset() |
| 75 | { |
| 76 | m_CF = m_ZF = m_RF = 0; |
| 77 | m_A = 0; |
| 78 | m_PC.d = 0; |
| 79 | memset(m_REGS,0,sizeof(m_REGS)); |
| 80 | } |
| 81 | |
| 82 | //------------------------------------------------- |
| 83 | // memory_space_config - return the configuration |
| 84 | // of the specified address space, or NULL if |
| 85 | // the space doesn't exist |
| 86 | //------------------------------------------------- |
| 87 | |
| 88 | const address_space_config *ie15_device::memory_space_config(address_spacenum spacenum) const |
| 89 | { |
| 90 | return (spacenum == AS_PROGRAM) ? &m_program_config : |
| 91 | (spacenum == AS_IO) ? &m_io_config : |
| 92 | NULL; |
| 93 | } |
| 94 | |
| 95 | //------------------------------------------------- |
| 96 | // state_import - import state into the device, |
| 97 | // after it has been set |
| 98 | //------------------------------------------------- |
| 99 | |
| 100 | void ie15_device::state_import(const device_state_entry &entry) |
| 101 | { |
| 102 | switch (entry.index()) |
| 103 | { |
| 104 | case STATE_GENFLAGS: |
| 105 | m_CF = (m_flags >> 3) & 1; |
| 106 | m_ZF = (m_flags >> 2) & 1; |
| 107 | m_RF = (m_flags >> 1) & 1; |
| 108 | break; |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | //------------------------------------------------- |
| 113 | // state_export - export state from the device, |
| 114 | // to a known location where it can be read |
| 115 | //------------------------------------------------- |
| 116 | |
| 117 | void ie15_device::state_export(const device_state_entry &entry) |
| 118 | { |
| 119 | switch (entry.index()) |
| 120 | { |
| 121 | case STATE_GENFLAGS: |
| 122 | m_flags = (m_CF ? 0x08 : 0x00) | |
| 123 | (m_ZF ? 0x04 : 0x00) | |
| 124 | (m_RF ? 0x02 : 0x00); |
| 125 | break; |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | //------------------------------------------------- |
| 130 | // state_string_export - export state as a string |
| 131 | // for the debugger |
| 132 | //------------------------------------------------- |
| 133 | |
| 134 | void ie15_device::state_string_export(const device_state_entry &entry, astring &string) |
| 135 | { |
| 136 | switch (entry.index()) |
| 137 | { |
| 138 | case STATE_GENFLAGS: |
| 139 | string.printf("%c%c%c", |
| 140 | m_CF ? 'C':'.', |
| 141 | m_ZF ? 'Z':'.', |
| 142 | m_RF ? 'R':'.'); |
| 143 | break; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | //------------------------------------------------- |
| 148 | // disasm_min_opcode_bytes - return the length |
| 149 | // of the shortest instruction, in bytes |
| 150 | //------------------------------------------------- |
| 151 | |
| 152 | UINT32 ie15_device::disasm_min_opcode_bytes() const |
| 153 | { |
| 154 | return 1; |
| 155 | } |
| 156 | |
| 157 | //------------------------------------------------- |
| 158 | // disasm_max_opcode_bytes - return the length |
| 159 | // of the longest instruction, in bytes |
| 160 | //------------------------------------------------- |
| 161 | |
| 162 | UINT32 ie15_device::disasm_max_opcode_bytes() const |
| 163 | { |
| 164 | return 2; |
| 165 | } |
| 166 | |
| 167 | //------------------------------------------------- |
| 168 | // disasm_disassemble - call the disassembly |
| 169 | // helper function |
| 170 | //------------------------------------------------- |
| 171 | |
| 172 | offs_t ie15_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) |
| 173 | { |
| 174 | extern CPU_DISASSEMBLE( ie15 ); |
| 175 | return CPU_DISASSEMBLE_NAME(ie15)(NULL, buffer, pc, oprom, opram, 0); |
| 176 | } |
| 177 | |
| 178 | //************************************************************************** |
| 179 | // EXECUTION |
| 180 | //************************************************************************** |
| 181 | |
| 182 | //------------------------------------------------- |
| 183 | // execute_min_cycles - return minimum number of |
| 184 | // cycles it takes for one instruction to execute |
| 185 | //------------------------------------------------- |
| 186 | |
| 187 | UINT32 ie15_device::execute_min_cycles() const |
| 188 | { |
| 189 | return 1; |
| 190 | } |
| 191 | |
| 192 | //------------------------------------------------- |
| 193 | // execute_max_cycles - return maximum number of |
| 194 | // cycles it takes for one instruction to execute |
| 195 | //------------------------------------------------- |
| 196 | |
| 197 | UINT32 ie15_device::execute_max_cycles() const |
| 198 | { |
| 199 | return 1; |
| 200 | } |
| 201 | |
| 202 | //------------------------------------------------- |
| 203 | // execute_run - execute until our icount expires |
| 204 | //------------------------------------------------- |
| 205 | |
| 206 | void ie15_device::execute_run() |
| 207 | { |
| 208 | do |
| 209 | { |
| 210 | debugger_instruction_hook(this, m_PC.d); |
| 211 | execute_one(rop()); |
| 212 | } while (m_icount > 0); |
| 213 | } |
| 214 | |
| 215 | inline void ie15_device::illegal(UINT8 opcode) |
| 216 | { |
| 217 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 218 | { |
| 219 | logerror("IE15 illegal instruction %04X $%02X\n", m_PC.w.l, opcode); |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | // XXX verify that m_ZF and m_CF are set and handled right |
| 224 | // XXX 'ota' apparently writes the ALU buffer register, not accumulator |
| 225 | // XXX what if ldc was at 0x_ff? |
| 226 | inline void ie15_device::execute_one(int opcode) |
| 227 | { |
| 228 | UINT16 tmp; |
| 229 | |
| 230 | m_icount -= 1; |
| 231 | |
| 232 | switch (opcode & 0xf0) |
| 233 | { |
| 234 | case 0x00: // add |
| 235 | tmp = m_A + get_reg_lo(opcode & 15); |
| 236 | m_A = tmp & 255; |
| 237 | update_flags(m_A); |
| 238 | m_CF = BIT(tmp, 8); |
| 239 | break; |
| 240 | case 0x10: // jmp |
| 241 | m_PC.w.l = get_addr(opcode); |
| 242 | // m_CF = 0; |
| 243 | break; |
| 244 | case 0x20: // ldc |
| 245 | set_reg(opcode & 15, arg() | (m_PC.w.l & 0xf00)); |
| 246 | m_PC.w.l = m_PC.w.l + 1; |
| 247 | // m_CF = 0; |
| 248 | break; |
| 249 | case 0x40: // dsr |
| 250 | tmp = get_reg_lo(opcode & 15) - 1; |
| 251 | // m_CF = BIT(tmp, 8); |
| 252 | tmp &= 255; |
| 253 | set_reg(opcode & 15, tmp); |
| 254 | update_flags(tmp); |
| 255 | if (m_ZF) { |
| 256 | SKIP_OP(tmp); |
| 257 | } |
| 258 | break; |
| 259 | case 0x30: |
| 260 | switch (opcode) |
| 261 | { |
| 262 | case 0x30: // lca |
| 263 | m_A = arg(); |
| 264 | update_flags(m_A); |
| 265 | m_PC.w.l = m_PC.w.l + 1; |
| 266 | break; |
| 267 | case 0x33: // ral |
| 268 | tmp = m_A; |
| 269 | m_A = (m_A << 1) | BIT(tmp,7); |
| 270 | update_flags(m_A); |
| 271 | break; |
| 272 | case 0x35: // rar |
| 273 | tmp = m_A; |
| 274 | m_A = (m_A >> 1) | (BIT(tmp,0) ? 0x80 : 0x00); |
| 275 | update_flags(m_A); |
| 276 | break; |
| 277 | default: |
| 278 | illegal(opcode); |
| 279 | break; |
| 280 | }; |
| 281 | break; |
| 282 | case 0x50: |
| 283 | switch (opcode) |
| 284 | { |
| 285 | case 0x51: // inc |
| 286 | case 0x50: // isn |
| 287 | case 0x58: // ise |
| 288 | tmp = m_A + 1; |
| 289 | m_A = tmp & 255; |
| 290 | update_flags(m_A); |
| 291 | m_CF = BIT(tmp, 8); |
| 292 | if (opcode == 0x50 && m_ZF) |
| 293 | SKIP_OP(tmp); |
| 294 | if (opcode == 0x58 && !m_ZF) |
| 295 | SKIP_OP(tmp); |
| 296 | break; |
| 297 | case 0x5b: // dec |
| 298 | case 0x52: // dsn |
| 299 | case 0x5a: // dse |
| 300 | tmp = m_A - 1; |
| 301 | m_A = tmp & 255; |
| 302 | update_flags(m_A); |
| 303 | m_CF = BIT(tmp, 8); |
| 304 | if (opcode == 0x52 && m_ZF) |
| 305 | SKIP_OP(tmp); |
| 306 | if (opcode == 0x5a && !m_ZF) |
| 307 | SKIP_OP(tmp); |
| 308 | break; |
| 309 | case 0x5d: // com |
| 310 | m_A ^= 255; |
| 311 | update_flags(m_A); |
| 312 | break; |
| 313 | case 0x5f: // clr |
| 314 | m_A = 0; |
| 315 | update_flags(m_A); |
| 316 | break; |
| 317 | default: |
| 318 | illegal(opcode); |
| 319 | break; |
| 320 | }; |
| 321 | break; |
| 322 | case 0x70: // jmi |
| 323 | // m_CF = 0; |
| 324 | m_PC.w.l = get_reg(opcode & 15); |
| 325 | break; |
| 326 | case 0x60: // lla |
| 327 | // special case -- port 7 |
| 328 | if (opcode == 0x67) |
| 329 | m_A = 255; |
| 330 | else |
| 331 | m_A = m_io->read_byte(opcode & 15); |
| 332 | update_flags(m_A); |
| 333 | break; |
| 334 | case 0xf0: // ota |
| 335 | // special case -- ports 016, 017 |
| 336 | if (opcode == 0xfe) |
| 337 | m_RF = 1; |
| 338 | else if (opcode == 0xff) |
| 339 | m_RF = 0; |
| 340 | else |
| 341 | m_io->write_byte(opcode & 15, m_A); |
| 342 | // m_CF = 0; |
| 343 | break; |
| 344 | case 0xc0: // cfl, sfl |
| 345 | switch (opcode) |
| 346 | { |
| 347 | // special case -- accessing control flag 05 resets CF |
| 348 | case 0xc5: |
| 349 | case 0xcd: |
| 350 | m_CF = 0; |
| 351 | break; |
| 352 | default: |
| 353 | m_io->write_byte(020 | (opcode & 7), BIT(opcode, 3)); |
| 354 | break; |
| 355 | } |
| 356 | break; |
| 357 | case 0x80: // sfc, skp, sfs, nop |
| 358 | tmp = opcode & 7; |
| 359 | switch (tmp) |
| 360 | { |
| 361 | case 5: |
| 362 | tmp = BIT(m_A, 7); |
| 363 | break; |
| 364 | case 6: |
| 365 | tmp = m_CF; |
| 366 | break; |
| 367 | case 7: |
| 368 | tmp = 0; |
| 369 | break; |
| 370 | default: |
| 371 | tmp = m_io->read_byte(020 | tmp); |
| 372 | break; |
| 373 | |
| 374 | } |
| 375 | if (!BIT(opcode, 3) && !tmp) |
| 376 | SKIP_OP(tmp); |
| 377 | if (BIT(opcode, 3) && tmp) |
| 378 | SKIP_OP(tmp); |
| 379 | break; |
| 380 | case 0xb0: // cs |
| 381 | // m_CF = 0; |
| 382 | if (m_A == get_reg_lo(opcode & 15)) { |
| 383 | m_ZF = 1; |
| 384 | SKIP_OP(tmp); |
| 385 | } |
| 386 | break; |
| 387 | case 0x90: // and |
| 388 | m_A &= get_reg_lo(opcode & 15); |
| 389 | update_flags(m_A); |
| 390 | break; |
| 391 | case 0xa0: // xor |
| 392 | m_A ^= get_reg_lo(opcode & 15); |
| 393 | update_flags(m_A); |
| 394 | break; |
| 395 | case 0xd0: // lda |
| 396 | m_A = get_reg_lo(opcode & 15); |
| 397 | update_flags(m_A); |
| 398 | break; |
| 399 | case 0xe0: // sta |
| 400 | set_reg(opcode & 15, m_A | (m_PC.w.l & 0xf00)); |
| 401 | // m_CF = 0; |
| 402 | break; |
| 403 | default: |
| 404 | illegal(opcode); |
| 405 | break; |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | /*************************************************************************** |
| 410 | INLINE FUNCTIONS |
| 411 | ***************************************************************************/ |
| 412 | |
| 413 | inline UINT8 ie15_device::rop() |
| 414 | { |
| 415 | UINT8 retVal = m_direct->read_decrypted_byte(m_PC.w.l); |
| 416 | m_PC.w.l = (m_PC.w.l + 1) & 0x0fff; |
| 417 | return retVal; |
| 418 | } |
| 419 | |
| 420 | inline UINT8 ie15_device::arg() |
| 421 | { |
| 422 | UINT8 retVal = m_direct->read_raw_byte(m_PC.w.l); |
| 423 | return retVal; |
| 424 | } |
| 425 | |
| 426 | inline UINT8 ie15_device::get_reg_lo(UINT8 reg) |
| 427 | { |
| 428 | UINT16 tmp = m_RF ? m_REGS[16 + reg] : m_REGS[reg]; |
| 429 | return tmp & 255; |
| 430 | } |
| 431 | |
| 432 | inline UINT16 ie15_device::get_reg(UINT8 reg) |
| 433 | { |
| 434 | return m_RF ? m_REGS[16 + reg] : m_REGS[reg]; |
| 435 | } |
| 436 | |
| 437 | inline void ie15_device::set_reg(UINT8 reg, UINT16 val) |
| 438 | { |
| 439 | (m_RF ? m_REGS[16 + reg] : m_REGS[reg]) = val; |
| 440 | |
| 441 | } |
| 442 | |
| 443 | inline void ie15_device::update_flags(UINT8 val) |
| 444 | { |
| 445 | m_ZF = (val == 0xff) ? 1 : 0; |
| 446 | } |
| 447 | |
| 448 | inline UINT8 ie15_device::do_condition(UINT8 val) |
| 449 | { |
| 450 | UINT8 v = (val >> 5) & 1; |
| 451 | UINT8 cond = 0; |
| 452 | switch((val>> 3) & 0x03) { |
| 453 | case 0 : |
| 454 | if (m_CF==v) cond = 1; |
| 455 | break; |
| 456 | case 1 : |
| 457 | if (m_ZF==v) cond = 1; |
| 458 | break; |
| 459 | } |
| 460 | return cond; |
| 461 | } |
| 462 | |
| 463 | inline UINT16 ie15_device::get_addr(UINT8 val) |
| 464 | { |
| 465 | UINT8 lo = arg(); |
| 466 | return ((val & 0x0f) << 8) + lo + 1; |
| 467 | } |
trunk/src/mess/drivers/ie15.c
r0 | r22732 | |
| 1 | /*************************************************************************** |
| 2 | |
| 3 | 15IE-00-013 Terminal |
| 4 | |
| 5 | board images : http://asvcorp.ru/darch/hardware/pdp/fryazin-display/index.html |
| 6 | |
| 7 | 29/06/2012 Skeleton driver. |
| 8 | |
| 9 | A serial (RS232 or current loop) green-screen terminal, mostly VT52 compatible |
| 10 | (no Hold Screen mode and no graphics character set, but has Cyrillic characters). |
| 11 | The top line is a status line. |
| 12 | |
| 13 | ****************************************************************************/ |
| 14 | |
| 15 | #include "emu.h" |
| 16 | #include "cpu/ie15/ie15.h" |
| 17 | #include "imagedev/bitbngr.h" |
| 18 | #include "machine/keyboard.h" |
| 19 | #include "sound/beep.h" |
| 20 | |
| 21 | #define SCREEN_PAGE (80*48) |
| 22 | |
| 23 | #define IE_1 0x80 |
| 24 | #define IE_KB_ACK 1 |
| 25 | |
| 26 | #define IE15_TOTAL_HORZ 1000 |
| 27 | #define IE15_TOTAL_VERT 28*11 |
| 28 | |
| 29 | #define IE15_DISP_HORZ 800 |
| 30 | #define IE15_DISP_VERT 25*11 |
| 31 | |
| 32 | #define IE15_HORZ_START 100 |
| 33 | #define IE15_VERT_START 2*11 |
| 34 | |
| 35 | #define VERBOSE_DBG 1 /* general debug messages */ |
| 36 | |
| 37 | #define DBG_LOG(N,M,A) \ |
| 38 | do { \ |
| 39 | if(VERBOSE_DBG>=N) \ |
| 40 | { \ |
| 41 | if( M ) \ |
| 42 | logerror("%11.6f at %s: %-24s",machine().time().as_double(),machine().describe_context(),(char*)M ); \ |
| 43 | logerror A; \ |
| 44 | } \ |
| 45 | } while (0) |
| 46 | |
| 47 | #if VERBOSE_DBG > 0 |
| 48 | #define LOOPBACK (m_io_keyboard->read() & 0x20) |
| 49 | #else |
| 50 | #define LOOPBACK (0) |
| 51 | #endif |
| 52 | |
| 53 | #define BITBANGER_TAG "bitbanger" |
| 54 | |
| 55 | class ie15_state : public driver_device |
| 56 | { |
| 57 | public: |
| 58 | ie15_state(const machine_config &mconfig, device_type type, const char *tag) |
| 59 | : driver_device(mconfig, type, tag) |
| 60 | , m_maincpu(*this, "maincpu") |
| 61 | , m_beeper(*this, "beeper") |
| 62 | , m_bitbanger(*this, BITBANGER_TAG) |
| 63 | , m_io_keyboard(*this, KEYBOARD_TAG) |
| 64 | { } |
| 65 | |
| 66 | virtual void machine_reset(); |
| 67 | virtual void video_start(); |
| 68 | virtual void palette_init(); |
| 69 | UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); |
| 70 | UINT32 screen_update_hle(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); |
| 71 | TIMER_DEVICE_CALLBACK_MEMBER(scanline_callback); |
| 72 | DECLARE_WRITE8_MEMBER(kbd_put); |
| 73 | static const bitbanger_config ie15_bitbanger_config; |
| 74 | TIMER_CALLBACK_MEMBER(serial_tx_callback); |
| 75 | emu_timer *m_serial_tx_timer; |
| 76 | |
| 77 | DECLARE_WRITE8_MEMBER( mem_w ); |
| 78 | DECLARE_READ8_MEMBER( mem_r ); |
| 79 | DECLARE_WRITE8_MEMBER( mem_addr_lo_w ); |
| 80 | DECLARE_WRITE8_MEMBER( mem_addr_hi_w ); |
| 81 | DECLARE_WRITE8_MEMBER( mem_addr_inc_w ); |
| 82 | DECLARE_WRITE8_MEMBER( mem_addr_dec_w ); |
| 83 | DECLARE_READ8_MEMBER( flag_r ); |
| 84 | DECLARE_WRITE8_MEMBER( flag_w ); |
| 85 | DECLARE_WRITE8_MEMBER( beep_w ); |
| 86 | DECLARE_READ8_MEMBER( kb_r ); |
| 87 | DECLARE_READ8_MEMBER( kb_ready_r ); |
| 88 | DECLARE_READ8_MEMBER( kb_s_red_r ); |
| 89 | DECLARE_READ8_MEMBER( kb_s_sdv_r ); |
| 90 | DECLARE_READ8_MEMBER( kb_s_dk_r ); |
| 91 | DECLARE_READ8_MEMBER( kb_s_dupl_r ); |
| 92 | DECLARE_READ8_MEMBER( kb_s_lin_r ); |
| 93 | DECLARE_WRITE8_MEMBER( kb_ready_w ); |
| 94 | DECLARE_READ8_MEMBER( serial_tx_ready_r ); |
| 95 | DECLARE_WRITE8_MEMBER( serial_w ); |
| 96 | DECLARE_READ8_MEMBER( serial_rx_ready_r ); |
| 97 | DECLARE_READ8_MEMBER( serial_r ); |
| 98 | #if 0 |
| 99 | DECLARE_WRITE8_MEMBER( serial_speed_w ); |
| 100 | #endif |
| 101 | |
| 102 | private: |
| 103 | TIMER_CALLBACK_MEMBER(ie15_beepoff); |
| 104 | UINT32 draw_scanline(UINT16 *p, UINT16 offset, UINT8 scanline, UINT8 y); |
| 105 | bitmap_ind16 m_tmpbmp; |
| 106 | |
| 107 | const UINT8 *m_p_chargen; |
| 108 | UINT8 *m_p_videoram; |
| 109 | UINT8 m_beep; |
| 110 | UINT8 m_cursor; |
| 111 | UINT8 m_kb_data; |
| 112 | UINT8 m_kb_flag; |
| 113 | UINT8 m_kb_flag0; |
| 114 | UINT8 m_latch; |
| 115 | UINT8 m_ruslat; |
| 116 | UINT8 m_serial_rx_bits; |
| 117 | UINT8 m_serial_rx_buffer; |
| 118 | UINT8 m_serial_rx_data; |
| 119 | UINT8 m_serial_tx_bits; |
| 120 | UINT8 m_serial_tx_data; |
| 121 | UINT8 m_statusline; |
| 122 | UINT8 m_video; |
| 123 | UINT32 m_videoptr; |
| 124 | UINT32 m_videoptr_2; |
| 125 | |
| 126 | static void bitbanger_callback(running_machine &machine, UINT8 bit); |
| 127 | DECLARE_WRITE_LINE_MEMBER( serial_rx_callback ); |
| 128 | |
| 129 | protected: |
| 130 | required_device<cpu_device> m_maincpu; |
| 131 | required_device<beep_device> m_beeper; |
| 132 | required_device<bitbanger_device> m_bitbanger; |
| 133 | required_ioport m_io_keyboard; |
| 134 | }; |
| 135 | |
| 136 | READ8_MEMBER( ie15_state::mem_r ) { |
| 137 | UINT8 ret; |
| 138 | |
| 139 | ret = m_p_videoram[m_videoptr]; |
| 140 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0 && m_videoptr >= SCREEN_PAGE) |
| 141 | { |
| 142 | DBG_LOG(2,"memory",("R @ %03x == %02x\n", m_videoptr, ret)); |
| 143 | } |
| 144 | m_videoptr++; |
| 145 | m_videoptr &= 0xfff; |
| 146 | m_latch = 0; |
| 147 | return ret; |
| 148 | } |
| 149 | |
| 150 | WRITE8_MEMBER( ie15_state::mem_w ) { |
| 151 | if ((m_latch ^= 1) == 0) { |
| 152 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0 && m_videoptr >= SCREEN_PAGE) |
| 153 | { |
| 154 | DBG_LOG(2,"memory",("W @ %03x <- %02x\n", m_videoptr, data)); |
| 155 | } |
| 156 | m_p_videoram[m_videoptr++] = data; |
| 157 | m_videoptr &= 0xfff; |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | WRITE8_MEMBER( ie15_state::mem_addr_inc_w ) { |
| 162 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 163 | { |
| 164 | DBG_LOG(2,"memory",("++ %03x\n", m_videoptr)); |
| 165 | } |
| 166 | m_videoptr++; |
| 167 | m_videoptr &= 0xfff; |
| 168 | if (m_video) |
| 169 | m_videoptr_2 = m_videoptr; |
| 170 | } |
| 171 | |
| 172 | WRITE8_MEMBER( ie15_state::mem_addr_dec_w ) { |
| 173 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 174 | { |
| 175 | DBG_LOG(2,"memory",("-- %03x\n", m_videoptr)); |
| 176 | } |
| 177 | m_videoptr--; |
| 178 | m_videoptr &= 0xfff; |
| 179 | if (m_video) |
| 180 | m_videoptr_2 = m_videoptr; |
| 181 | } |
| 182 | |
| 183 | WRITE8_MEMBER( ie15_state::mem_addr_lo_w ) { |
| 184 | UINT16 tmp = m_videoptr; |
| 185 | |
| 186 | tmp &= 0xff0; |
| 187 | tmp |= ((data >> 4) & 0xf); |
| 188 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 189 | { |
| 190 | DBG_LOG(2,"memory",("lo %03x <- %02x = %03x\n", m_videoptr, data, tmp)); |
| 191 | } |
| 192 | m_videoptr = tmp; |
| 193 | if (m_video) |
| 194 | m_videoptr_2 = tmp; |
| 195 | } |
| 196 | |
| 197 | WRITE8_MEMBER( ie15_state::mem_addr_hi_w ) { |
| 198 | UINT16 tmp = m_videoptr; |
| 199 | |
| 200 | tmp &= 0xf; |
| 201 | tmp |= (data << 4); |
| 202 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 203 | { |
| 204 | DBG_LOG(2,"memory",("hi %03x <- %02x = %03x\n", m_videoptr, data, tmp)); |
| 205 | } |
| 206 | m_videoptr = tmp; |
| 207 | if (m_video) |
| 208 | m_videoptr_2 = tmp; |
| 209 | } |
| 210 | |
| 211 | TIMER_CALLBACK_MEMBER(ie15_state::ie15_beepoff) |
| 212 | { |
| 213 | machine().device<beep_device>("beeper")->set_state(0); |
| 214 | } |
| 215 | |
| 216 | WRITE8_MEMBER( ie15_state::beep_w ) { |
| 217 | UINT16 length = (m_beep&128)?150:400; |
| 218 | |
| 219 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 220 | { |
| 221 | DBG_LOG(1,"beep",("(%s)\n", m_beep?"short":"long")); |
| 222 | } |
| 223 | machine().scheduler().timer_set(attotime::from_msec(length), timer_expired_delegate(FUNC(ie15_state::ie15_beepoff),this)); |
| 224 | machine().device<beep_device>("beeper")->set_state(1); |
| 225 | } |
| 226 | |
| 227 | // active high |
| 228 | READ8_MEMBER( ie15_state::kb_r ) { |
| 229 | DBG_LOG(2,"keyboard",("R %02X '%c'\n", m_kb_data, m_kb_data < 0x20?' ':m_kb_data)); |
| 230 | return m_kb_data; |
| 231 | } |
| 232 | |
| 233 | // active low |
| 234 | READ8_MEMBER( ie15_state::kb_ready_r ) { |
| 235 | m_kb_flag &= IE_1; |
| 236 | if (m_kb_flag != m_kb_flag0) { |
| 237 | DBG_LOG(2,"keyboard",("? %c\n", m_kb_flag?'n':'y')); |
| 238 | m_kb_flag0 = m_kb_flag; |
| 239 | } |
| 240 | return m_kb_flag; |
| 241 | } |
| 242 | |
| 243 | // active low |
| 244 | WRITE8_MEMBER( ie15_state::kb_ready_w ) { |
| 245 | DBG_LOG(2,"keyboard",("clear ready\n")); |
| 246 | m_kb_flag = IE_1 | IE_KB_ACK; |
| 247 | } |
| 248 | |
| 249 | |
| 250 | // active high; active = interpret controls, inactive = display controls |
| 251 | READ8_MEMBER( ie15_state::kb_s_red_r ) { |
| 252 | return m_io_keyboard->read() & 0x01 ? IE_1 : 0; |
| 253 | } |
| 254 | |
| 255 | // active high; active = setup mode |
| 256 | READ8_MEMBER( ie15_state::kb_s_sdv_r ) { |
| 257 | return m_io_keyboard->read() & 0x02 ? IE_1 : 0; |
| 258 | } |
| 259 | |
| 260 | // active high, XXX stub |
| 261 | READ8_MEMBER( ie15_state::kb_s_dk_r ) { |
| 262 | return 0; |
| 263 | } |
| 264 | |
| 265 | // active low; active = full duplex, inactive = half duplex |
| 266 | READ8_MEMBER( ie15_state::kb_s_dupl_r ) { |
| 267 | return m_io_keyboard->read() & 0x08 ? IE_1 : 0; |
| 268 | } |
| 269 | |
| 270 | // active high; active = on-line, inactive = local editing |
| 271 | READ8_MEMBER( ie15_state::kb_s_lin_r ) { |
| 272 | return m_io_keyboard->read() & 0x10 ? IE_1 : 0; |
| 273 | } |
| 274 | |
| 275 | // active low |
| 276 | READ8_MEMBER( ie15_state::serial_rx_ready_r ) { |
| 277 | if (LOOPBACK) |
| 278 | return m_serial_tx_data ? 0 : IE_1; |
| 279 | else |
| 280 | return m_serial_rx_data ? 0 : IE_1; |
| 281 | } |
| 282 | |
| 283 | // not called unless data is ready |
| 284 | READ8_MEMBER( ie15_state::serial_r ) { |
| 285 | UINT8 tmp; |
| 286 | |
| 287 | if (LOOPBACK) { |
| 288 | tmp = m_serial_tx_data; |
| 289 | m_serial_tx_data = 0; |
| 290 | } else { |
| 291 | tmp = m_serial_rx_data; |
| 292 | m_serial_rx_data = 0; |
| 293 | } |
| 294 | DBG_LOG(2,"serial",("R %02X '%c'\n", tmp, tmp < 0x20?' ':tmp)); |
| 295 | return tmp; |
| 296 | } |
| 297 | |
| 298 | /* |
| 299 | m_serial_rx_buffer incoming bits. |
| 300 | m_serial_rx_bits number of bits in _buffer. |
| 301 | m_serial_rx_data complete byte, ready to be read by host, or 0 if no data. |
| 302 | */ |
| 303 | |
| 304 | WRITE_LINE_MEMBER( ie15_state::serial_rx_callback ) |
| 305 | { |
| 306 | UINT8 tmp = m_serial_rx_bits; |
| 307 | |
| 308 | switch (m_serial_rx_bits) { |
| 309 | // wait for start bit (0) |
| 310 | case 10: |
| 311 | m_serial_rx_bits = 0; |
| 312 | case 0: |
| 313 | if (!state) { |
| 314 | m_serial_rx_bits++; |
| 315 | m_serial_rx_buffer = 0; |
| 316 | } |
| 317 | break; |
| 318 | // stuff incoming bits into byte buffer |
| 319 | case 1: case 2: case 3: case 4: |
| 320 | case 5: case 6: case 7: case 8: |
| 321 | m_serial_rx_buffer |= state << (m_serial_rx_bits-1); |
| 322 | m_serial_rx_bits++; |
| 323 | break; |
| 324 | // expecting stop bit (1) |
| 325 | case 9: |
| 326 | if (state && !m_serial_rx_data) { |
| 327 | m_serial_rx_data = m_serial_rx_buffer; |
| 328 | m_serial_rx_bits++; |
| 329 | } else |
| 330 | m_serial_rx_bits = 0; |
| 331 | break; |
| 332 | default: |
| 333 | // overflow |
| 334 | break; |
| 335 | } |
| 336 | DBG_LOG(2,"serial",("r %d bits %02d->%02d buffer %02X data %02X\n", |
| 337 | state, tmp, m_serial_rx_bits, m_serial_rx_buffer, m_serial_rx_data)); |
| 338 | } |
| 339 | |
| 340 | const bitbanger_config ie15_state::ie15_bitbanger_config = |
| 341 | { |
| 342 | DEVCB_DRIVER_LINE_MEMBER(ie15_state, serial_rx_callback), /* callback */ |
| 343 | BITBANGER_PRINTER, /* default mode */ |
| 344 | BITBANGER_9600, /* default output baud */ |
| 345 | BITBANGER_0PERCENT /* default fine tune adjustment */ |
| 346 | }; |
| 347 | |
| 348 | // active high |
| 349 | READ8_MEMBER( ie15_state::serial_tx_ready_r ) { |
| 350 | return m_serial_tx_data ? 0 : IE_1; |
| 351 | } |
| 352 | |
| 353 | WRITE8_MEMBER( ie15_state::serial_w ) { |
| 354 | DBG_LOG(2,"serial",("W %02X '%c'\n", data, data < 0x20?' ':data)); |
| 355 | if (LOOPBACK) { |
| 356 | if (!m_serial_tx_data) |
| 357 | m_serial_tx_data = data; |
| 358 | } else { |
| 359 | /* 1 start bit */ |
| 360 | m_bitbanger->output(0); |
| 361 | /* 8 data bits, 1 stop bit, no parity */ |
| 362 | m_serial_tx_bits = 8; |
| 363 | m_serial_tx_data = data; |
| 364 | m_serial_tx_timer->adjust(attotime::from_hz(9600)); |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | TIMER_CALLBACK_MEMBER(ie15_state::serial_tx_callback) { |
| 369 | if (!m_serial_tx_bits) { |
| 370 | m_bitbanger->output(1); |
| 371 | m_serial_tx_data = 0; |
| 372 | } else { |
| 373 | m_bitbanger->output(BIT(m_serial_tx_data, 8-(m_serial_tx_bits--))); |
| 374 | m_serial_tx_timer->adjust(attotime::from_hz(9600)); |
| 375 | } |
| 376 | } |
| 377 | |
| 378 | READ8_MEMBER( ie15_state::flag_r ) { |
| 379 | UINT8 ret = 0; |
| 380 | |
| 381 | switch (offset) |
| 382 | { |
| 383 | case 0: // hsync pulse (not hblank) |
| 384 | ret = machine().primary_screen->hpos() < IE15_HORZ_START; |
| 385 | break; |
| 386 | case 1: // marker scanline |
| 387 | ret = (machine().primary_screen->vpos() % 11) > 7; |
| 388 | break; |
| 389 | case 2: // vblank |
| 390 | ret = !machine().primary_screen->vblank(); |
| 391 | break; |
| 392 | case 4: |
| 393 | ret = m_ruslat; |
| 394 | break; |
| 395 | default: |
| 396 | break; |
| 397 | } |
| 398 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0 && ret) |
| 399 | { |
| 400 | DBG_LOG(2,"flag",("read %d: %d\n", offset, ret)); |
| 401 | } |
| 402 | return ret; |
| 403 | } |
| 404 | |
| 405 | WRITE8_MEMBER( ie15_state::flag_w ) { |
| 406 | switch (offset) |
| 407 | { |
| 408 | case 0: |
| 409 | m_video = data; |
| 410 | break; |
| 411 | case 1: |
| 412 | m_cursor = data; |
| 413 | break; |
| 414 | case 2: |
| 415 | m_beep = data; |
| 416 | break; |
| 417 | case 3: |
| 418 | m_statusline = data; |
| 419 | break; |
| 420 | case 4: |
| 421 | m_ruslat = data; |
| 422 | break; |
| 423 | default: |
| 424 | break; |
| 425 | } |
| 426 | if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) |
| 427 | { |
| 428 | DBG_LOG(2,"flag",("%sset %d\n", data?"":"re", offset)); |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | static ADDRESS_MAP_START(ie15_mem, AS_PROGRAM, 8, ie15_state) |
| 433 | ADDRESS_MAP_UNMAP_HIGH |
| 434 | AM_RANGE( 0x0000, 0x0fff ) AM_ROM |
| 435 | ADDRESS_MAP_END |
| 436 | |
| 437 | static ADDRESS_MAP_START(ie15_io, AS_IO, 8, ie15_state) |
| 438 | ADDRESS_MAP_UNMAP_HIGH |
| 439 | AM_RANGE(000, 000) AM_READ(mem_r) AM_WRITE(mem_w) // 00h W: memory request, R: memory data [6.1.2.2] |
| 440 | AM_RANGE(001, 001) AM_READ(serial_rx_ready_r) AM_WRITENOP // 01h W: memory latch [6.1.2.2] |
| 441 | AM_RANGE(002, 002) AM_WRITE(mem_addr_hi_w) // 02h W: memory address high [6.1.2.2] |
| 442 | AM_RANGE(003, 003) AM_WRITE(mem_addr_lo_w) // 03h W: memory address low [6.1.2.2] |
| 443 | AM_RANGE(004, 004) AM_WRITE(mem_addr_inc_w) // 04h W: memory address counter + [6.1.2.2] |
| 444 | AM_RANGE(005, 005) AM_WRITE(mem_addr_dec_w) // 05h W: memory address counter - [6.1.2.2] |
| 445 | AM_RANGE(006, 006) AM_READ(serial_r) AM_WRITE(serial_w) // 06h W: serial port data [6.1.5.4] |
| 446 | // port 7 is handled in cpu core |
| 447 | AM_RANGE(010, 010) AM_READ(serial_tx_ready_r) AM_WRITE(beep_w) // 08h W: speaker control [6.1.5.4] |
| 448 | AM_RANGE(011, 011) AM_READ(kb_r) // 09h R: keyboard data [6.1.5.2] |
| 449 | AM_RANGE(012, 012) AM_READ(kb_s_red_r) // 0Ah I: keyboard mode "RED" [6.1.5.2] |
| 450 | AM_RANGE(013, 013) AM_READ(kb_ready_r) // 0Bh R: keyboard data ready [6.1.5.2] |
| 451 | AM_RANGE(014, 014) AM_READ(kb_s_sdv_r) AM_WRITENOP // 0Ch W: serial port speed [6.1.3.1], R: keyboard mode "SDV" [6.1.5.2] |
| 452 | AM_RANGE(015, 015) AM_READ(kb_s_dk_r) AM_WRITE(kb_ready_w) // 0Dh I: keyboard mode "DK" [6.1.5.2] |
| 453 | AM_RANGE(016, 016) AM_READ(kb_s_dupl_r) // 0Eh I: keyboard mode "DUPL" [6.1.5.2] |
| 454 | AM_RANGE(017, 017) AM_READ(kb_s_lin_r) // 0Fh I: keyboard mode "LIN" [6.1.5.2] |
| 455 | // simulation of flag registers |
| 456 | AM_RANGE(020, 027) AM_READ(flag_r) AM_WRITE(flag_w) |
| 457 | ADDRESS_MAP_END |
| 458 | |
| 459 | /* Input ports */ |
| 460 | static INPUT_PORTS_START( ie15 ) |
| 461 | PORT_START("keyboard") |
| 462 | PORT_DIPNAME(0x01, 0x00, "RED mode") |
| 463 | PORT_DIPSETTING(0x00, "Off" ) |
| 464 | PORT_DIPSETTING(0x01, "On" ) |
| 465 | PORT_DIPNAME(0x02, 0x00, "SDV mode (Setup)") |
| 466 | PORT_DIPSETTING(0x00, "Off" ) |
| 467 | PORT_DIPSETTING(0x02, "On" ) |
| 468 | PORT_DIPNAME(0x08, 0x00, "DUPL mode") |
| 469 | PORT_DIPSETTING(0x00, "Off" ) |
| 470 | PORT_DIPSETTING(0x08, "On" ) |
| 471 | PORT_DIPNAME(0x10, 0x00, "LIN mode") |
| 472 | PORT_DIPSETTING(0x00, "Off" ) |
| 473 | PORT_DIPSETTING(0x10, "On" ) |
| 474 | PORT_DIPNAME(0x20, 0x00, "digital loopback") |
| 475 | PORT_DIPSETTING(0x00, "Off" ) |
| 476 | PORT_DIPSETTING(0x20, "On" ) |
| 477 | INPUT_PORTS_END |
| 478 | |
| 479 | WRITE8_MEMBER( ie15_state::kbd_put ) |
| 480 | { |
| 481 | DBG_LOG(2,"keyboard",("W %02X<-%02X '%c' %c\n", m_kb_data, data, data < 0x20?' ':data, m_kb_flag?'n':'y')); |
| 482 | if (m_kb_flag == IE_1) { |
| 483 | m_kb_data = data; |
| 484 | m_kb_flag = 0; |
| 485 | } |
| 486 | } |
| 487 | |
| 488 | static ASCII_KEYBOARD_INTERFACE( keyboard_intf ) |
| 489 | { |
| 490 | DEVCB_DRIVER_MEMBER(ie15_state, kbd_put) |
| 491 | }; |
| 492 | |
| 493 | |
| 494 | void ie15_state::machine_reset() |
| 495 | { |
| 496 | m_ruslat = m_beep = m_statusline = m_cursor = m_video = m_kb_data = m_kb_flag0 = 0; |
| 497 | m_serial_tx_data = m_serial_tx_bits = m_serial_rx_buffer = m_serial_rx_data = m_serial_rx_bits = 0; |
| 498 | m_kb_flag = IE_1; |
| 499 | |
| 500 | machine().device<beep_device>("beeper")->set_frequency(2400); |
| 501 | machine().device<beep_device>("beeper")->set_state(0); |
| 502 | |
| 503 | m_serial_tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ie15_state::serial_tx_callback),this)); |
| 504 | } |
| 505 | |
| 506 | void ie15_state::video_start() |
| 507 | { |
| 508 | m_p_chargen = machine().root_device().memregion("chargen")->base(); |
| 509 | m_p_videoram = memregion("video")->base(); |
| 510 | m_videoptr = m_videoptr_2 = m_latch = 0; |
| 511 | |
| 512 | m_tmpbmp.allocate(IE15_DISP_HORZ, IE15_DISP_VERT); |
| 513 | } |
| 514 | |
| 515 | UINT32 ie15_state::draw_scanline(UINT16 *p, UINT16 offset, UINT8 scanline, UINT8 y) |
| 516 | { |
| 517 | UINT8 gfx,fg,bg,ra,blink,red; |
| 518 | UINT16 x,chr; |
| 519 | |
| 520 | bg = 0; fg = 1; ra = scanline % 8; |
| 521 | blink = (machine().primary_screen->frame_number() % 10) >= 5; |
| 522 | red = m_io_keyboard->read() & 0x01; |
| 523 | |
| 524 | DBG_LOG(2,"draw_scanline", |
| 525 | ("addr %03x row %d-%d video %d\n", offset, y, scanline, m_video)); |
| 526 | |
| 527 | for (x = offset; x < offset + 80; x++) |
| 528 | { |
| 529 | if (m_video) { |
| 530 | chr = m_p_videoram[x] << 3; |
| 531 | gfx = m_p_chargen[chr | ra]; |
| 532 | |
| 533 | /* |
| 534 | Cursor is a character with only 3 scan lines, and is |
| 535 | not shown if flag 1 is not active on this scan line. |
| 536 | It always blinks if shown. |
| 537 | |
| 538 | Control characters blink if RED mode is on and they |
| 539 | are not on status line; else they are blanked out. |
| 540 | */ |
| 541 | |
| 542 | if (scanline > 7 && (!m_cursor || blink)) |
| 543 | gfx = 0; |
| 544 | if (chr < (0x20<<3)) { |
| 545 | if (!y || !red || blink) |
| 546 | gfx = 0; |
| 547 | else |
| 548 | gfx = m_p_chargen[chr | 0x200 | ra]; |
| 549 | } |
| 550 | /* Display a scanline of a character */ |
| 551 | *p++ = BIT(gfx, 7) ? fg : bg; |
| 552 | *p++ = BIT(gfx, 6) ? fg : bg; |
| 553 | *p++ = BIT(gfx, 5) ? fg : bg; |
| 554 | *p++ = BIT(gfx, 4) ? fg : bg; |
| 555 | *p++ = BIT(gfx, 3) ? fg : bg; |
| 556 | *p++ = BIT(gfx, 2) ? fg : bg; |
| 557 | *p++ = BIT(gfx, 1) ? fg : bg; |
| 558 | *p++ = bg; |
| 559 | *p++ = bg; |
| 560 | *p++ = bg; |
| 561 | } else { |
| 562 | *p++ = bg; |
| 563 | *p++ = bg; |
| 564 | *p++ = bg; |
| 565 | *p++ = bg; |
| 566 | *p++ = bg; |
| 567 | *p++ = bg; |
| 568 | *p++ = bg; |
| 569 | *p++ = bg; |
| 570 | *p++ = bg; |
| 571 | *p++ = bg; |
| 572 | } |
| 573 | } |
| 574 | return 0; |
| 575 | } |
| 576 | |
| 577 | TIMER_DEVICE_CALLBACK_MEMBER(ie15_state::scanline_callback) |
| 578 | { |
| 579 | UINT16 y = machine().primary_screen->vpos(); |
| 580 | // DBG_LOG(2,"scanline", |
| 581 | // ("addr %03x frame %lld x %04d y %03d\n", m_videoptr_2, machine().primary_screen->frame_number(), machine().primary_screen->hpos(), y)); |
| 582 | if (y>=IE15_VERT_START) { |
| 583 | y -= IE15_VERT_START; |
| 584 | if (y < IE15_DISP_VERT) { |
| 585 | draw_scanline(&m_tmpbmp.pix16(y), m_videoptr_2, y%11, y/11); |
| 586 | } |
| 587 | } |
| 588 | } |
| 589 | |
| 590 | UINT32 ie15_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) |
| 591 | { |
| 592 | copybitmap( bitmap, m_tmpbmp, 0, 0, IE15_HORZ_START, IE15_VERT_START, cliprect ); |
| 593 | return 0; |
| 594 | } |
| 595 | |
| 596 | |
| 597 | /* F4 Character Displayer */ |
| 598 | static const gfx_layout ie15_charlayout = |
| 599 | { |
| 600 | 7, 8, /* 7x8 pixels in 10x11 cell */ |
| 601 | 256, /* 256 characters */ |
| 602 | 1, /* 1 bits per pixel */ |
| 603 | { 0 }, /* no bitplanes */ |
| 604 | /* x offsets */ |
| 605 | { 0, 1, 2, 3, 4, 5, 6 }, |
| 606 | /* y offsets */ |
| 607 | { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, |
| 608 | 8*8 /* every char takes 8 bytes */ |
| 609 | }; |
| 610 | |
| 611 | static GFXDECODE_START( ie15 ) |
| 612 | GFXDECODE_ENTRY( "chargen", 0x0000, ie15_charlayout, 0, 1 ) |
| 613 | GFXDECODE_END |
| 614 | |
| 615 | void ie15_state::palette_init() |
| 616 | { |
| 617 | palette_set_color(machine(), 0, RGB_BLACK); // black |
| 618 | palette_set_color_rgb(machine(), 1, 0x00, 0xc0, 0x00); // green |
| 619 | } |
| 620 | |
| 621 | static MACHINE_CONFIG_START( ie15, ie15_state ) |
| 622 | /* Basic machine hardware */ |
| 623 | MCFG_CPU_ADD("maincpu", IE15, XTAL_30_8MHz / 10) |
| 624 | MCFG_CPU_PROGRAM_MAP(ie15_mem) |
| 625 | MCFG_CPU_IO_MAP(ie15_io) |
| 626 | MCFG_TIMER_DRIVER_ADD_PERIODIC("scantimer", ie15_state, scanline_callback, attotime::from_hz(50*28*11)) |
| 627 | MCFG_TIMER_START_DELAY(attotime::from_hz(XTAL_30_8MHz/(2*IE15_HORZ_START))) |
| 628 | |
| 629 | /* Video hardware */ |
| 630 | MCFG_SCREEN_ADD("screen", RASTER) |
| 631 | MCFG_SCREEN_UPDATE_DRIVER(ie15_state, screen_update) |
| 632 | MCFG_SCREEN_RAW_PARAMS(XTAL_30_8MHz/2,IE15_TOTAL_HORZ,IE15_HORZ_START, |
| 633 | IE15_HORZ_START+IE15_DISP_HORZ,IE15_TOTAL_VERT,IE15_VERT_START, |
| 634 | IE15_VERT_START+IE15_DISP_VERT); |
| 635 | MCFG_GFXDECODE(ie15) |
| 636 | MCFG_PALETTE_LENGTH(2) |
| 637 | |
| 638 | /* Devices */ |
| 639 | MCFG_ASCII_KEYBOARD_ADD(KEYBOARD_TAG, keyboard_intf) |
| 640 | MCFG_BITBANGER_ADD(BITBANGER_TAG, ie15_state::ie15_bitbanger_config) |
| 641 | |
| 642 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 643 | MCFG_SOUND_ADD("beeper", BEEP, 0) |
| 644 | MCFG_SOUND_ROUTE(ALL_OUTPUTS,"mono",0.15) |
| 645 | MACHINE_CONFIG_END |
| 646 | |
| 647 | |
| 648 | /* ROM definition */ |
| 649 | ROM_START( ie15 ) |
| 650 | ROM_REGION( 0x1000, "maincpu", ROMREGION_ERASE00 ) |
| 651 | ROM_DEFAULT_BIOS("5chip") |
| 652 | ROM_SYSTEM_BIOS(0, "5chip", "5-chip firmware (newer)") |
| 653 | ROMX_LOAD( "dump1.bin", 0x0000, 0x1000, CRC(14b82284) SHA1(5ac4159fbb1c3b81445605e26cd97a713ae12b5f),ROM_BIOS(1) ) |
| 654 | ROM_SYSTEM_BIOS(1, "6chip", "6-chip firmware (older)") |
| 655 | ROMX_LOAD( "dump5.bin", 0x0000, 0x1000, CRC(01f2e065) SHA1(2b72dc0594e38a528400cd25aed0c47e0c432895),ROM_BIOS(2) ) |
| 656 | |
| 657 | ROM_REGION( 0x1000, "video", ROMREGION_ERASE00 ) |
| 658 | |
| 659 | ROM_REGION( 0x0800, "chargen", ROMREGION_ERASE00 ) |
| 660 | ROM_LOAD( "chargen-15ie.bin", 0x0000, 0x0800, CRC(ed16bf6b) SHA1(6af9fb75f5375943d5c0ce9ed408e0fb4621b17e) ) |
| 661 | ROM_END |
| 662 | |
| 663 | /* Driver */ |
| 664 | |
| 665 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ |
| 666 | COMP( 1980, ie15, 0, 0, ie15, ie15, driver_device, 0, "USSR", "15IE-00-013", 0) |