public void ctrl_w(uint8_t data) { m_control = data; // The upper 3 control bits are the clock divider. if ((m_control & 0xe0) == 0) { m_nmi_timer.adjust(attotime.never); set_nmi(CLEAR_LINE); m_chipsel[0].op_s32(0, CLEAR_LINE); m_chipsel[1].op_s32(0, CLEAR_LINE); m_chipsel[2].op_s32(0, CLEAR_LINE); m_chipsel[3].op_s32(0, CLEAR_LINE); // Setting this to true makes the next RW change not stretch. m_next_timer_state = true; } else { m_rw_stretch = !m_next_timer_state; m_rw_change = true; m_next_timer_state = true; m_nmi_stretch = BIT(m_control, 4) != 0; // NMI is cleared immediately if its to be stretched. if (m_nmi_stretch) { set_nmi(CLEAR_LINE); } uint8_t num_shifts = (uint8_t)((m_control & 0xe0) >> 5); uint8_t divisor = (uint8_t)(1U << num_shifts); // The next change should happen on the next clock falling edge. // Xevious' race causes this to bootloopsif it isn't 0. m_nmi_timer.adjust(attotime.zero, 0, attotime.from_hz(clock() / divisor) / 2); } }
// watchdog control //------------------------------------------------- // watchdog_reset - reset the watchdog timer //------------------------------------------------- public void watchdog_reset() { // if we're not enabled, skip it if (!m_enabled) { m_timer.adjust(attotime.never); } // VBLANK-based watchdog? else if (m_vblank_count != 0) { m_counter = m_vblank_count; } // timer-based watchdog? else if (m_time != attotime.zero) { m_timer.adjust(m_time); } // default to an obscene amount of time (3 seconds) else { m_timer.adjust(attotime.from_seconds(3)); } }
protected virtual void set_rmcr(uint8_t data) { if (m_rmcr == data) { return; } m_rmcr = data; switch ((m_rmcr & M6801_RMCR_CC_MASK) >> 2) { case 0: LOGSER("SCI: Using external serial clock: false\n"); m_sci_timer.enable(false); m_use_ext_serclock = false; break; case 3: // external clock LOGSER("SCI: Using external serial clock: true\n"); m_use_ext_serclock = true; m_sci_timer.enable(false); break; case 1: case 2: { int divisor = M6801_RMCR_SS[m_rmcr & M6801_RMCR_SS_MASK]; attotime period = cycles_to_attotime((uint64_t)divisor); LOGSER("SCI: Setting serial rate, Divisor: {0} Hz: {1}\n", divisor, period.as_hz()); m_sci_timer.adjust(period, 0, period); m_use_ext_serclock = false; } break; } }
//------------------------------------------------- // interface_post_reset - work to be done after a // device is reset //------------------------------------------------- public override void interface_post_reset() { // reset the interrupt vectors and queues for (int line = 0; line < m_input.Length; line++) { m_input[line].reset(); } // reconfingure VBLANK interrupts if (!string.IsNullOrEmpty(m_vblank_interrupt_screen)) { // get the screen that will trigger the VBLANK screen_device screen = device().siblingdevice <screen_device>(m_vblank_interrupt_screen); //assert(screen != NULL); screen.register_vblank_callback(on_vblank); } // reconfigure periodic interrupts if (m_timed_interrupt_period != attotime.zero) { attotime timedint_period = m_timed_interrupt_period; //assert(m_timedint_timer != NULL); m_timedint_timer.adjust(timedint_period, 0, timedint_period); } }
//------------------------------------------------- // interface_post_reset - work to be done after a // device is reset //------------------------------------------------- public override void interface_post_reset() { // reset the interrupt vectors and queues foreach (var elem in m_input) { elem.reset(); } // reconfingure VBLANK interrupts if (!string.IsNullOrEmpty(m_vblank_interrupt_screen)) { // get the screen that will trigger the VBLANK screen_device screen = device().siblingdevice <screen_device>(m_vblank_interrupt_screen); //throw new emu_unimplemented(); #if false assert(screen != nullptr); #endif screen.register_vblank_callback(on_vblank); } // reconfigure periodic interrupts if (m_timed_interrupt_period != attotime.zero) { attotime timedint_period = m_timed_interrupt_period; //throw new emu_unimplemented(); #if false assert(m_timedint_timer != nullptr); #endif m_timedint_timer.adjust(timedint_period, 0, timedint_period); } }
void set_rmcr(uint8_t data) { if (m_rmcr == data) { return; } m_rmcr = data; switch ((m_rmcr & M6801_RMCR_CC_MASK) >> 2) { case 0: m_sci_timer.enable(false); m_use_ext_serclock = false; break; case 3: // external clock m_use_ext_serclock = true; m_sci_timer.enable(false); break; case 1: case 2: { int divisor = M6801_RMCR_SS[m_rmcr & M6801_RMCR_SS_MASK]; attotime period = cycles_to_attotime((u64)divisor); m_sci_timer.adjust(period, 0, period); m_use_ext_serclock = false; } break; } }
protected override void device_clock_changed() { int prescaler = get_prescaler(); if (prescaler != 0) { logerror("/{0} prescaler selected\n", prescaler); attotime half_period = clocks_to_attotime((u64)(prescaler / 2)); m_vck_timer.adjust(half_period, 0, half_period); } else { logerror("VCK slave mode selected\n"); m_vck_timer.adjust(attotime.never); } }
public void device_scheduler_after_ctor(running_machine machine) { // ED: there's a circular dependency with device_scheduler. it creates a emu_timer, which calls machine.time(). so we null check here to fix that. // append a single never-expiring timer so there is always one in the list m_timer_list = m_timer_allocator.alloc().init(machine, null, null, true); m_timer_list.adjust(attotime.never); }
public void go_w(u8 data = 0) { vggo(); if (m_sync_halt != 0 && (m_nvect > 10)) { /* * This is a good time to start a new frame. Major Havoc * sometimes sets VGGO after a very short vector list. That's * why we ignore frames with less than 10 vectors. */ m_vector.op0.clear_list(); } vg_flush(); vg_set_halt(0); m_vg_run_timer.adjust(attotime.zero); }
//WRITE8_MEMBER( namco_06xx_device::ctrl_w ) public void ctrl_w(address_space space, offs_t offset, u8 data, u8 mem_mask = 0xff) { LOG("{0}: 06XX '{1}' control {2}\n", machine().describe_context(), tag(), data); m_control = data; if ((m_control & 0x0f) == 0) { LOG("disabling nmi generate timer\n"); m_nmi_timer.adjust(attotime.never); } else { LOG("setting nmi generate timer to 200us\n"); // this timing is critical. Due to a bug, Bosconian will stop responding to // inputs if a transfer terminates at the wrong time. // On the other hand, the time cannot be too short otherwise the 54XX will // not have enough time to process the incoming controls. m_nmi_timer.adjust(attotime.from_usec(200), 0, attotime.from_usec(200)); if ((m_control & 0x10) != 0) { if (BIT(m_control, 0) != 0) { m_readreq[0].op(space, 0); } if (BIT(m_control, 1) != 0) { m_readreq[1].op(space, 0); } if (BIT(m_control, 2) != 0) { m_readreq[2].op(space, 0); } if (BIT(m_control, 3) != 0) { m_readreq[3].op(space, 0); } } } }
void irq_set() { m_cpu.target.set_input_line(0, ASSERT_LINE); // The execution time of one instruction is ~4us, so we must make sure to // give the cpu time to poll the /IRQ input before we clear it. // The input clock to the 06XX interface chip is 64H, that is // 18432000/6/64 = 48kHz, so it makes sense for the irq line to be // asserted for one clock cycle ~= 21us. m_irq_cleared_timer.adjust(attotime.from_usec(21), 0); }
//------------------------------------------------- // device_reset - reset the device //------------------------------------------------- protected override void device_reset() { // type based configuration switch (m_type) { case timer_type.TIMER_TYPE_GENERIC: case timer_type.TIMER_TYPE_PERIODIC: { // convert the period into attotime attotime period; if (m_period > attotime.zero) { period = m_period; // convert the start_delay into attotime attotime start_delay = attotime.zero; if (m_start_delay > attotime.zero) { start_delay = m_start_delay; } // allocate and start the backing timer m_timer.adjust(start_delay, m_param, period); } break; } case timer_type.TIMER_TYPE_SCANLINE: if (m_screen == null) { fatalerror("timer '{0}': unable to find screen '{1}'\n", tag(), m_screen.finder_tag()); } // set the timer to fire immediately m_first_time = true; m_timer.adjust(attotime.zero, m_param); break; } }
attotime m_last_update; // last update time // construction/destruction //------------------------------------------------- // sound_manager - constructor //------------------------------------------------- public sound_manager(running_machine machine) { m_machine = machine; m_update_timer = null; m_finalmix_leftover = 0; m_finalmix = new std.vector <s16>(machine.sample_rate()); m_leftmix = new std.vector <s32>(machine.sample_rate()); m_rightmix = new std.vector <s32>(machine.sample_rate()); m_nosound_mode = machine.osd().no_sound() ? 1 : 0; m_wavfile = null; m_update_attoseconds = STREAMS_UPDATE_ATTOTIME.attoseconds(); m_last_update = attotime.zero; // get filename for WAV file or AVI file if specified string wavfile = machine.options().wav_write(); string avifile = machine.options().avi_write(); // handle -nosound and lower sample rate if not recording WAV or AVI if (m_nosound_mode != 0 && string.IsNullOrEmpty(wavfile) && string.IsNullOrEmpty(avifile)) { machine.sample_rate_set(11025); } // count the mixers if (sound_global.VERBOSE) { mixer_interface_iterator iter = new mixer_interface_iterator(machine.root_device()); sound_global.VPRINTF("total mixers = {0}\n", iter.count()); } // register callbacks machine.configuration().config_register("mixer", config_load, config_save); machine.add_notifier(machine_notification.MACHINE_NOTIFY_PAUSE, pause); machine.add_notifier(machine_notification.MACHINE_NOTIFY_RESUME, resume); machine.add_notifier(machine_notification.MACHINE_NOTIFY_RESET, reset); machine.add_notifier(machine_notification.MACHINE_NOTIFY_EXIT, stop_recording); // register global states machine.save().save_item(m_last_update, "m_last_update"); // set the starting attenuation set_attenuation(machine.options().volume()); // start the periodic update flushing timer m_update_timer = machine.scheduler().timer_alloc(update, this); m_update_timer.adjust(STREAMS_UPDATE_ATTOTIME, 0, STREAMS_UPDATE_ATTOTIME); }
//TIMER_CALLBACK_MEMBER(run_state_machine); void run_state_machine(object ptr, int param) { int cycles = 0; while (cycles < VGSLICE) { // Get next state m_state_latch = (u8)((m_state_latch & 0x10) | (m_prom.op[state_addr()] & 0xf)); if (ST3() != 0) { // Read vector RAM/ROM update_databus(); // Decode state and call the corresponding handler switch (m_state_latch & 7) { case 0: cycles += handler_0(); break; case 1: cycles += handler_1(); break; case 2: cycles += handler_2(); break; case 3: cycles += handler_3(); break; case 4: cycles += handler_4(); break; case 5: cycles += handler_5(); break; case 6: cycles += handler_6(); break; case 7: cycles += handler_7(); break; } } // If halt flag was set, let CPU catch up before we make halt visible if (m_halt != 0 && (m_state_latch & 0x10) == 0) { m_vg_halt_timer.adjust(attotime.from_hz(MASTER_CLOCK) * (u32)cycles, 1); } m_state_latch = (u8)((m_halt << 4) | (m_state_latch & 0xf)); cycles += 8; } m_vg_run_timer.adjust(attotime.from_hz(MASTER_CLOCK) * (u32)cycles); }
//------------------------------------------------- // device_timer: Handle device-specific timer // calbacks //------------------------------------------------- protected override void device_timer(emu_timer timer, device_timer_id id, int param, object ptr) { switch (id) { case TID_FORCE_UPDATE: if (param > 0) { m_divideo.screen().update_partial(param - 1); } param += 64; if (param >= m_divideo.screen().visible_area().bottom()) { param = 0; } timer.adjust(m_divideo.screen().time_until_pos(param), param); break; } }
protected override void device_timer(emu_timer timer, device_timer_id id, int param, object ptr) { switch (id) { case TIMER_VCK: m_vck = !m_vck; m_vck_cb.op(m_vck ? 1 : 0); if (!m_vck) { m_capture_timer.adjust(attotime.from_nsec(15600)); } break; case TIMER_ADPCM_CAPTURE: update_adpcm(); break; } }
protected override void device_timer(emu_timer timer, device_timer_id id, int param, object ptr) { switch (id) { case TIMER_VCK: m_vck = !m_vck; m_vck_cb.op_s32(m_vck ? 1 : 0); if (!m_vck) { m_capture_timer.adjust(attotime.from_hz(clock() / 6)); // 15.6 usec at 384KHz } break; case TIMER_ADPCM_CAPTURE: update_adpcm(); break; } }
//void address_data_start_w(u8 data); // start and ale connected, address to the data bus // device-level overrides protected override void device_start() { // resolve callbacks m_eoc_cb.resolve_safe(); m_eoc_ff_cb.resolve_safe(); m_in_cb.resolve_all_safe_u8(0xff); // allocate timers m_cycle_timer = timer_alloc(); m_cycle_timer.adjust(attotime.zero, 0, attotime.from_hz(clock())); // register for save states save_item(NAME(new { m_state })); save_item(NAME(new { m_start })); save_item(NAME(new { m_address })); save_item(NAME(new { m_sar })); save_item(NAME(new { m_eoc })); }
//WRITE_LINE_MEMBER( adc0808_device::start_w ) void start_w(int state_) { if (m_start == state_) { return; } if (state_ != 0 && m_start == 0) { m_state = state.STATE_CONVERSION_START; m_cycle_timer.adjust(attotime.from_hz(clock())); } else if (state_ == 0 && m_start != 0) { m_cycle_timer.adjust(attotime.from_hz(clock())); } m_start = state_; }
//void internal_post(char32_t ch); //------------------------------------------------- // timer - timer callback to keep things flowing // when posting a string of characters //------------------------------------------------- void timer(object ptr, int param) { if (m_queue_chars != null) { // the driver has a queue_chars handler while (!empty() && m_queue_chars(m_buffer, m_bufbegin, 1) != 0) { m_bufbegin = (m_bufbegin + 1) % (UInt32)m_buffer.size(); if (m_current_rate != attotime.zero) { break; } } } else { // the driver does not have a queue_chars handler // loop through this character's component codes keycode_map_entry code = find_code(m_buffer[(int)m_bufbegin]); bool advance; if (code != null) { do { assert(m_fieldnum < code.field.Length); ioport_field field = code.field[m_fieldnum]; if (field != null) { // special handling for toggle fields if (!field.live().toggle) { field.set_value(!m_status_keydown ? (UInt32)1 : 0); } else if (!m_status_keydown) { field.set_value(!field.digital_value() ? (UInt32)1 : 0); } } }while (code.field[m_fieldnum] != null && (++m_fieldnum < code.field.Length) && m_status_keydown); advance = (m_fieldnum >= code.field.Length) || code.field[m_fieldnum] == null; } else { advance = true; } if (advance) { m_fieldnum = 0; m_status_keydown = !m_status_keydown; // proceed to next character when keydown expires if (!m_status_keydown) { m_bufbegin = (m_bufbegin + 1) % (UInt32)m_buffer.size(); } } } // need to make sure timerproc is called again if buffer not empty if (!empty()) { m_timer.adjust(choose_delay(m_buffer[(int)m_bufbegin])); } }
void reset(running_machine machine) { // setup autoboot if needed m_autoboot_timer.adjust(new attotime(options().autoboot_delay(), 0), 0); }
//void apply_stain(bitmap_ind16 &bitmap, uint16_t *pf, uint16_t *mo, int x, int y); // memory access //uint16_t &slipram(int offset) { return m_slipram[offset]; } // device-level overrides //------------------------------------------------- // device_start: Start up the device //------------------------------------------------- protected override void device_start() { // call parent base.device_start(); // verify configuration gfx_element gfx = m_gfxdecode.op0.gfx(m_atari_motion_objects_config.m_gfxindex); if (gfx == null) { throw new emu_fatalerror("No gfxelement #{0}!", m_atari_motion_objects_config.m_gfxindex); } // determine the masks m_linkmask.set(m_atari_motion_objects_config.m_link_entry); m_codemask.set(m_atari_motion_objects_config.m_code_entry); m_colormask.set(m_atari_motion_objects_config.m_color_entry); m_xposmask.set(m_atari_motion_objects_config.m_xpos_entry); m_yposmask.set(m_atari_motion_objects_config.m_ypos_entry); m_widthmask.set(m_atari_motion_objects_config.m_width_entry); m_heightmask.set(m_atari_motion_objects_config.m_height_entry); m_hflipmask.set(m_atari_motion_objects_config.m_hflip_entry); m_vflipmask.set(m_atari_motion_objects_config.m_vflip_entry); m_prioritymask.set(m_atari_motion_objects_config.m_priority_entry); m_neighbormask.set(m_atari_motion_objects_config.m_neighbor_entry); m_absolutemask.set(m_atari_motion_objects_config.m_absolute_entry); // derive tile information m_tilewidth = gfx.width(); m_tileheight = gfx.height(); m_tilexshift = compute_log(m_tilewidth); m_tileyshift = compute_log(m_tileheight); // derive bitmap information m_bitmapwidth = round_to_powerof2(m_xposmask.mask()); m_bitmapheight = round_to_powerof2(m_yposmask.mask()); m_bitmapxmask = m_bitmapwidth - 1; m_bitmapymask = m_bitmapheight - 1; // derive sprite information m_entrycount = round_to_powerof2(m_linkmask.mask()); m_entrybits = compute_log(m_entrycount); m_spriteramsize = m_atari_motion_objects_config.m_bankcount * m_entrycount; m_spriterammask = m_spriteramsize - 1; m_slipshift = (m_atari_motion_objects_config.m_slipheight != 0) ? compute_log(m_atari_motion_objects_config.m_slipheight) : 0; m_slipramsize = m_bitmapheight >> m_slipshift; m_sliprammask = m_slipramsize - 1; if (m_atari_motion_objects_config.m_maxperline == 0) { m_atari_motion_objects_config.m_maxperline = MAX_PER_BANK; } // Get the slipram from the share if not already explicitly set if (m_slipram == null) { m_slipram = new Pointer <u16>(m_slipramshare.op); } // allocate and initialize the code lookup int codesize = round_to_powerof2((int)m_codemask.mask()); m_codelookup.resize((size_t)codesize); for (int i = 0; i < codesize; i++) { m_codelookup[i] = (uint32_t)i; } // allocate and initialize the color lookup int colorsize = round_to_powerof2((int)m_colormask.mask()); m_colorlookup.resize((size_t)colorsize); for (int i = 0; i < colorsize; i++) { m_colorlookup[i] = (uint8_t)i; } // allocate and the gfx lookup int gfxsize = codesize / 256; m_gfxlookup.resize((size_t)gfxsize); for (int i = 0; i < gfxsize; i++) { m_gfxlookup[i] = m_atari_motion_objects_config.m_gfxindex; } // allocate a timer to periodically force update m_force_update_timer = timer_alloc(TID_FORCE_UPDATE); m_force_update_timer.adjust(m_divideo.screen().time_until_pos(0)); // register for save states save_item(NAME(new { m_bank })); save_item(NAME(new { m_xscroll })); save_item(NAME(new { m_yscroll })); }
// internal helpers //------------------------------------------------- // recompute_sample_rate_data - recompute sample // rate data, and all streams that are affected // by this stream //------------------------------------------------- void recompute_sample_rate_data() { if (m_synchronous) { m_sample_rate = 0; // When synchronous, pick the sample rate for the inputs, if any for (int inputnum = 0; inputnum < m_input.size(); inputnum++) { stream_input input = m_input[inputnum]; if (input.m_source != null) { if (m_sample_rate == 0) { m_sample_rate = input.m_source.m_stream.m_sample_rate; } else if (m_sample_rate != input.m_source.m_stream.m_sample_rate) { throw new emu_fatalerror("Incompatible sample rates as input of a synchronous stream: {0} and {1}\n", m_sample_rate, input.m_source.m_stream.m_sample_rate); } } } } // recompute the timing parameters attoseconds_t update_attoseconds = m_device.machine().sound().update_attoseconds(); if (m_sample_rate != 0) { m_attoseconds_per_sample = attotime.ATTOSECONDS_PER_SECOND / m_sample_rate; m_max_samples_per_update = (int)((update_attoseconds + m_attoseconds_per_sample - 1) / m_attoseconds_per_sample); } else { m_attoseconds_per_sample = 0; m_max_samples_per_update = 0; } // update resample and output buffer sizes allocate_resample_buffers(); allocate_output_buffers(); // iterate over each input for (int inputnum = 0; inputnum < m_input.size(); inputnum++) // for (auto & input : m_input) { var input = m_input[inputnum]; // if we have a source, see if its sample rate changed if (input.m_source != null && input.m_source.m_stream.m_sample_rate != 0) { // okay, we have a new sample rate; recompute the latency to be the maximum // sample period between us and our input attoseconds_t new_attosecs_per_sample = attotime.ATTOSECONDS_PER_SECOND / input.m_source.m_stream.m_sample_rate; attoseconds_t latency = Math.Max(new_attosecs_per_sample, m_attoseconds_per_sample); // if the input stream's sample rate is lower, we will use linear interpolation // this requires an extra sample from the source if (input.m_source.m_stream.m_sample_rate < m_sample_rate) { latency += new_attosecs_per_sample; } // if our sample rates match exactly, we don't need any latency else if (input.m_source.m_stream.m_sample_rate == m_sample_rate) { latency = 0; } // we generally don't want to tweak the latency, so we just keep the greatest // one we've computed thus far input.m_latency_attoseconds = Math.Max(input.m_latency_attoseconds, latency); //throw new emu_unimplemented(); #if false assert(input.m_latency_attoseconds < update_attoseconds); #endif } else { input.m_latency_attoseconds = 0; } } // If synchronous, prime the timer if (m_synchronous) { attotime time = m_device.machine().time(); if (m_attoseconds_per_sample != 0) { attoseconds_t next_edge = m_attoseconds_per_sample - (time.attoseconds() % m_attoseconds_per_sample); m_sync_timer.adjust(new attotime(0, next_edge)); } else { m_sync_timer.adjust(attotime.never); } } }
// construction/destruction //------------------------------------------------- // video_manager - constructor //------------------------------------------------- public video_manager(running_machine machine) { m_machine = machine; m_screenless_frame_timer = null; m_output_changed = false; m_throttle_realtime = attotime.zero; m_throttle_emutime = attotime.zero; m_throttle_history = 0; m_speed_last_realtime = 0; m_speed_last_emutime = attotime.zero; m_speed_percent = 1.0; m_overall_real_seconds = 0; m_overall_real_ticks = 0; m_overall_emutime = attotime.zero; m_overall_valid_counter = 0; m_frame_update_counter = 0; m_throttled = true; m_throttle_rate = 1.0f; m_fastforward = false; m_seconds_to_run = (u32)machine.options().seconds_to_run(); m_auto_frameskip = machine.options().auto_frameskip(); m_speed = (u32)original_speed_setting(); m_low_latency = machine.options().low_latency(); m_empty_skip_count = 0; m_frameskip_max = m_auto_frameskip ? (u8)machine.options().frameskip() : (u8)0; m_frameskip_level = m_auto_frameskip ? (u8)0 : (u8)machine.options().frameskip(); m_frameskip_counter = 0; m_frameskip_adjust = 0; m_skipping_this_frame = false; m_average_oversleep = 0; m_snap_target = null; m_snap_native = true; m_snap_width = 0; m_snap_height = 0; // request a callback upon exiting machine.add_notifier(machine_notification.MACHINE_NOTIFY_EXIT, exit); machine.save().register_postload(postload); // extract initial execution state from global configuration settings update_refresh_speed(); unsigned screen_count = (unsigned)(new screen_device_enumerator(machine.root_device()).count()); bool no_screens = screen_count == 0; // create a render target for snapshots string viewname = machine.options().snap_view(); m_snap_native = !no_screens && std.strcmp(viewname, "native") == 0; // the native target is hard-coded to our internal layout and has all options disabled if (m_snap_native) { throw new emu_unimplemented(); } else { // other targets select the specified view and turn off effects m_snap_target = machine.render().target_alloc(null, RENDER_CREATE_HIDDEN); m_snap_target.set_view(m_snap_target.configured_view(viewname, 0, 1)); m_snap_target.set_screen_overlay_enabled(false); } // extract snap resolution if present //if (sscanf(machine.options().snap_size(), "%dx%d", &m_snap_width, &m_snap_height) != 2) var parts = machine.options().snap_size().Split('x'); if (parts.Length == 2) { m_snap_width = Convert.ToInt32(parts[0]); m_snap_height = Convert.ToInt32(parts[1]); } else { m_snap_width = m_snap_height = 0; } // if no screens, create a periodic timer to drive updates if (no_screens) { m_screenless_frame_timer = machine.scheduler().timer_alloc(screenless_update_callback, this); m_screenless_frame_timer.adjust(screen_device.DEFAULT_FRAME_PERIOD, 0, screen_device.DEFAULT_FRAME_PERIOD); machine.output().set_global_notifier(video_notifier_callback, this); } }
// device_execute_interface overrides //virtual UINT32 execute_min_cycles() const { return 1; } //virtual UINT32 execute_max_cycles() const { return 3; } //virtual UINT32 execute_input_lines() const { return 1; } public void device_execute_interface_execute_run() { while (m_icountRef.i > 0) { byte opcode; byte arg; byte oc; /* fetch the opcode */ debugger_instruction_hook(GETPC()); opcode = READOP(GETPC()); /* increment the PC */ INCPC(); /* start with instruction doing 1 cycle */ oc = 1; switch (opcode) { case 0x00: /* nop ZCS:...*/ m_st = 1; break; case 0x01: /* outO ZCS:...*/ m_write_o.op((byte)pla(m_A, TEST_CF())); m_st = 1; break; case 0x02: /* outP ZCS:... */ m_write_p.op(m_A); m_st = 1; break; case 0x03: /* outR ZCS:... */ arg = m_Y; m_write_r[arg & 3].op(m_A); m_st = 1; break; case 0x04: /* tay ZCS:... */ m_Y = m_A; m_st = 1; break; case 0x05: /* tath ZCS:... */ m_TH = m_A; m_st = 1; break; case 0x06: /* tatl ZCS:... */ m_TL = m_A; m_st = 1; break; case 0x07: /* tas ZCS:... */ m_SB = m_A; m_st = 1; break; case 0x08: /* icy ZCS:x.x */ m_Y++; UPDATE_ST_C(m_Y); m_Y &= 0x0f; UPDATE_ZF(m_Y); break; case 0x09: /* icm ZCS:x.x */ arg = RDMEM(GETEA()); arg++; UPDATE_ST_C(arg); arg &= 0x0f; UPDATE_ZF(arg); WRMEM(GETEA(), arg); break; case 0x0a: /* stic ZCS:x.x */ WRMEM(GETEA(), m_A); m_Y++; UPDATE_ST_C(m_Y); m_Y &= 0x0f; UPDATE_ZF(m_Y); break; case 0x0b: /* x ZCS:x.. */ arg = RDMEM(GETEA()); WRMEM(GETEA(), m_A); m_A = arg; UPDATE_ZF(m_A); m_st = 1; break; case 0x0c: /* rol ZCS:xxx */ m_A <<= 1; m_A |= (byte)TEST_CF(); UPDATE_ST_C(m_A); m_cf = (byte)(m_st ^ 1); m_A &= 0x0f; UPDATE_ZF(m_A); break; case 0x0d: /* l ZCS:x.. */ m_A = RDMEM(GETEA()); UPDATE_ZF(m_A); m_st = 1; break; case 0x0e: /* adc ZCS:xxx */ arg = RDMEM(GETEA()); arg += m_A; arg += (byte)TEST_CF(); UPDATE_ST_C(arg); m_cf = (byte)(m_st ^ 1); m_A = (byte)(arg & 0x0f); UPDATE_ZF(m_A); break; case 0x0f: /* and ZCS:x.x */ m_A &= RDMEM(GETEA()); UPDATE_ZF(m_A); m_st = (byte)(m_zf ^ 1); break; case 0x10: /* daa ZCS:.xx */ if (TEST_CF() != 0 || m_A > 9) { m_A += 6; } UPDATE_ST_C(m_A); m_cf = (byte)(m_st ^ 1); m_A &= 0x0f; break; case 0x11: /* das ZCS:.xx */ if (TEST_CF() != 0 || m_A > 9) { m_A += 10; } UPDATE_ST_C(m_A); m_cf = (byte)(m_st ^ 1); m_A &= 0x0f; break; case 0x12: /* inK ZCS:x.. */ m_A = (byte)(m_read_k.op() & 0x0f); UPDATE_ZF(m_A); m_st = 1; break; case 0x13: /* inR ZCS:x.. */ arg = m_Y; m_A = (byte)(m_read_r[arg & 3].op() & 0x0f); UPDATE_ZF(m_A); m_st = 1; break; case 0x14: /* tya ZCS:x.. */ m_A = m_Y; UPDATE_ZF(m_A); m_st = 1; break; case 0x15: /* ttha ZCS:x.. */ m_A = m_TH; UPDATE_ZF(m_A); m_st = 1; break; case 0x16: /* ttla ZCS:x.. */ m_A = m_TL; UPDATE_ZF(m_A); m_st = 1; break; case 0x17: /* tsa ZCS:x.. */ m_A = m_SB; UPDATE_ZF(m_A); m_st = 1; break; case 0x18: /* dcy ZCS:..x */ m_Y--; UPDATE_ST_C(m_Y); m_Y &= 0x0f; break; case 0x19: /* dcm ZCS:x.x */ arg = RDMEM(GETEA()); arg--; UPDATE_ST_C(arg); arg &= 0x0f; UPDATE_ZF(arg); WRMEM(GETEA(), arg); break; case 0x1a: /* stdc ZCS:x.x */ WRMEM(GETEA(), m_A); m_Y--; UPDATE_ST_C(m_Y); m_Y &= 0x0f; UPDATE_ZF(m_Y); break; case 0x1b: /* xx ZCS:x.. */ arg = m_X; m_X = m_A; m_A = arg; UPDATE_ZF(m_A); m_st = 1; break; case 0x1c: /* ror ZCS:xxx */ m_A |= (byte)(TEST_CF() << 4); UPDATE_ST_C((byte)(m_A << 4)); m_cf = (byte)(m_st ^ 1); m_A >>= 1; m_A &= 0x0f; UPDATE_ZF(m_A); break; case 0x1d: /* st ZCS:x.. */ WRMEM(GETEA(), m_A); m_st = 1; break; case 0x1e: /* sbc ZCS:xxx */ arg = RDMEM(GETEA()); arg -= m_A; arg -= (byte)TEST_CF(); UPDATE_ST_C(arg); m_cf = (byte)(m_st ^ 1); m_A = (byte)(arg & 0x0f); UPDATE_ZF(m_A); break; case 0x1f: /* or ZCS:x.x */ m_A |= RDMEM(GETEA()); UPDATE_ZF(m_A); m_st = (byte)(m_zf ^ 1); break; case 0x20: /* setR ZCS:... */ arg = m_read_r[m_Y / 4].op(); m_write_r[m_Y / 4].op((byte)(arg | (1 << (m_Y % 4)))); m_st = 1; break; case 0x21: /* setc ZCS:.xx */ m_cf = 1; m_st = 1; break; case 0x22: /* rstR ZCS:... */ arg = m_read_r[m_Y / 4].op(); m_write_r[m_Y / 4].op((byte)(arg & ~(1 << (m_Y % 4)))); m_st = 1; break; case 0x23: /* rstc ZCS:.xx */ m_cf = 0; m_st = 1; break; case 0x24: /* tstr ZCS:..x */ arg = m_read_r[m_Y / 4].op(); m_st = (arg & (1 << (m_Y % 4))) != 0 ? (byte)0 : (byte)1; break; case 0x25: /* tsti ZCS:..x */ m_st = (byte)(m_nf ^ 1); break; case 0x26: /* tstv ZCS:..x */ m_st = (byte)(m_vf ^ 1); m_vf = 0; break; case 0x27: /* tsts ZCS:..x */ m_st = (byte)(m_sf ^ 1); if (m_sf != 0) { /* re-enable the timer if we disabled it previously */ if (m_SBcount >= mb88_cpu_device.SERIAL_DISABLE_THRESH) { m_serial.adjust(attotime.from_hz(clock() / mb88_cpu_device.SERIAL_PRESCALE), 0, attotime.from_hz(clock() / mb88_cpu_device.SERIAL_PRESCALE)); } m_SBcount = 0; } m_sf = 0; break; case 0x28: /* tstc ZCS:..x */ m_st = (byte)(m_cf ^ 1); break; case 0x29: /* tstz ZCS:..x */ m_st = (byte)(m_zf ^ 1); break; case 0x2a: /* sts ZCS:x.. */ WRMEM(GETEA(), m_SB); UPDATE_ZF(m_SB); m_st = 1; break; case 0x2b: /* ls ZCS:x.. */ m_SB = RDMEM(GETEA()); UPDATE_ZF(m_SB); m_st = 1; break; case 0x2c: /* rts ZCS:... */ m_SI = (byte)((m_SI - 1) & 3); m_PC = (byte)(m_SP[m_SI] & 0x3f); m_PA = (byte)((m_SP[m_SI] >> 6) & 0x1f); m_st = 1; break; case 0x2d: /* neg ZCS: ..x */ m_A = (byte)((~m_A) + 1); m_A &= 0x0f; UPDATE_ST_Z(m_A); break; case 0x2e: /* c ZCS:xxx */ arg = RDMEM(GETEA()); arg -= m_A; UPDATE_CF(arg); arg &= 0x0f; UPDATE_ST_Z(arg); m_zf = (byte)(m_st ^ 1); break; case 0x2f: /* eor ZCS:x.x */ m_A ^= RDMEM(GETEA()); UPDATE_ST_Z(m_A); m_zf = (byte)(m_st ^ 1); break; case 0x30: case 0x31: case 0x32: case 0x33: /* sbit ZCS:... */ arg = RDMEM(GETEA()); WRMEM(GETEA(), (byte)(arg | (1 << (opcode & 3)))); m_st = 1; break; case 0x34: case 0x35: case 0x36: case 0x37: /* rbit ZCS:... */ arg = RDMEM(GETEA()); WRMEM(GETEA(), (byte)(arg & ~(1 << (opcode & 3)))); m_st = 1; break; case 0x38: case 0x39: case 0x3a: case 0x3b: /* tbit ZCS:... */ arg = RDMEM(GETEA()); m_st = (arg & (1 << (opcode & 3))) != 0 ? (byte)0 : (byte)1; break; case 0x3c: /* rti ZCS:... */ /* restore address and saved state flags on the top bits of the stack */ m_SI = (byte)((m_SI - 1) & 3); m_PC = (byte)(m_SP[m_SI] & 0x3f); m_PA = (byte)((m_SP[m_SI] >> 6) & 0x1f); m_st = (byte)((m_SP[m_SI] >> 13) & 1); m_zf = (byte)((m_SP[m_SI] >> 14) & 1); m_cf = (byte)((m_SP[m_SI] >> 15) & 1); break; case 0x3d: /* jpa imm ZCS:..x */ m_PA = (byte)(READOP(GETPC()) & 0x1f); m_PC = (byte)(m_A * 4); oc = 2; m_st = 1; break; case 0x3e: /* en imm ZCS:... */ update_pio_enable((byte)(m_pio | READOP(GETPC()))); INCPC(); oc = 2; m_st = 1; break; case 0x3f: /* dis imm ZCS:... */ update_pio_enable((byte)(m_pio & ~(READOP(GETPC())))); INCPC(); oc = 2; m_st = 1; break; case 0x40: case 0x41: case 0x42: case 0x43: /* setD ZCS:... */ arg = m_read_r[0].op(); arg |= (byte)(1 << (opcode & 3)); m_write_r[0].op(arg); m_st = 1; break; case 0x44: case 0x45: case 0x46: case 0x47: /* rstD ZCS:... */ arg = m_read_r[0].op(); arg &= (byte)(~(1 << (opcode & 3))); m_write_r[0].op(arg); m_st = 1; break; case 0x48: case 0x49: case 0x4a: case 0x4b: /* tstD ZCS:..x */ arg = m_read_r[2].op(); m_st = (arg & (1 << (opcode & 3))) != 0 ? (byte)0 : (byte)1; break; case 0x4c: case 0x4d: case 0x4e: case 0x4f: /* tba ZCS:..x */ m_st = (m_A & (1 << (opcode & 3))) != 0 ? (byte)0 : (byte)1; break; case 0x50: case 0x51: case 0x52: case 0x53: /* xd ZCS:x.. */ arg = RDMEM((UInt32)(opcode & 3)); WRMEM((UInt32)(opcode & 3), m_A); m_A = arg; UPDATE_ZF(m_A); m_st = 1; break; case 0x54: case 0x55: case 0x56: case 0x57: /* xyd ZCS:x.. */ arg = RDMEM((UInt32)((opcode & 3) + 4)); WRMEM((UInt32)((opcode & 3) + 4), m_Y); m_Y = arg; UPDATE_ZF(m_Y); m_st = 1; break; case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: /* lxi ZCS:x.. */ m_X = (byte)(opcode & 7); UPDATE_ZF(m_X); m_st = 1; break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: /* call imm ZCS:..x */ arg = READOP(GETPC()); INCPC(); oc = 2; if (TEST_ST() != 0) { m_SP[m_SI] = GETPC(); m_SI = (byte)((m_SI + 1) & 3); m_PC = (byte)(arg & 0x3f); m_PA = (byte)(((opcode & 7) << 2) | (arg >> 6)); } m_st = 1; break; case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: /* jpl imm ZCS:..x */ arg = READOP(GETPC()); INCPC(); oc = 2; if (TEST_ST() != 0) { m_PC = (byte)(arg & 0x3f); m_PA = (byte)(((opcode & 7) << 2) | (arg >> 6)); } m_st = 1; break; case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: /* ai ZCS:xxx */ arg = (byte)(opcode & 0x0f); arg += m_A; UPDATE_ST_C(arg); m_cf = (byte)(m_st ^ 1); m_A = (byte)(arg & 0x0f); UPDATE_ZF(m_A); break; case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: /* lxi ZCS:x.. */ m_Y = (byte)(opcode & 0x0f); UPDATE_ZF(m_Y); m_st = 1; break; case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: /* li ZCS:x.. */ m_A = (byte)(opcode & 0x0f); UPDATE_ZF(m_A); m_st = 1; break; case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: /* cyi ZCS:xxx */ arg = (byte)((opcode & 0x0f) - m_Y); UPDATE_CF(arg); arg &= 0x0f; UPDATE_ST_Z(arg); m_zf = (byte)(m_st ^ 1); break; case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: /* ci ZCS:xxx */ arg = (byte)((opcode & 0x0f) - m_A); UPDATE_CF(arg); arg &= 0x0f; UPDATE_ST_Z(arg); m_zf = (byte)(m_st ^ 1); break; default: /* jmp ZCS:..x */ if (TEST_ST() != 0) { m_PC = (byte)(opcode & 0x3f); } m_st = 1; break; } /* update cycle counts */ CYCLES(oc); /* update interrupts, serial and timer flags */ update_pio(oc); } }