Example #1
0
        public void write(short addr, short data)
        {
            long cycles;

            if (addr > 0x0f)
            {
                return;
            }

            regs[addr] = data;
            cycles     = event_context.getTime(m_accessClk, event_context.phase);

            if (cycles != 0)
            {
                m_accessClk += cycles;
                // Sync up timers
                if ((cra & 0x21) == 0x01)
                {
                    ta -= (int)cycles;
                    if (ta == 0)
                    {
                        ta_event();
                    }
                }
                if ((crb & 0x61) == 0x01)
                {
                    tb -= (int)cycles;
                    if (tb == 0)
                    {
                        tb_event();
                    }
                }
            }

            switch (addr)
            {
            case PRA:
            case DDRA:
                portA();
                break;

            case PRB:
            case DDRB:
                portB();
                break;

            case TAL:
                ta_latch = SIDEndian.endian_16lo8(ta_latch, data);
                break;

            case TAH:
                ta_latch = SIDEndian.endian_16hi8(ta_latch, data);
                if ((cra & 0x01) == 0)     // Reload timer if stopped
                {
                    ta = ta_latch;
                }
                break;

            case TBL:
                tb_latch = SIDEndian.endian_16lo8(tb_latch, data);
                break;

            case TBH:
                tb_latch = SIDEndian.endian_16hi8(tb_latch, data);
                if ((crb & 0x01) == 0)     // Reload timer if stopped
                {
                    tb = tb_latch;
                }
                break;

            // TOD implementation taken from Vice
            case TOD_HR:     // Time Of Day clock hour
                // Flip AM/PM on hour 12
                // Flip AM/PM only when writing time, not when writing alarm
                data &= 0x9f;
                if ((data & 0x1f) == 0x12 && ((crb & 0x80) == 0))
                {
                    data ^= 0x80;
                }
                // deliberate run on
                if ((crb & 0x80) != 0)
                {
                    m_todalarm[addr - TOD_TEN] = data;
                }
                else
                {
                    if (addr == TOD_TEN)
                    {
                        m_todstopped = false;
                    }
                    if (addr == TOD_HR)
                    {
                        m_todstopped = true;
                    }
                    m_todclock[addr - TOD_TEN] = data;
                }
                // check alarm
                if (!m_todstopped && !memcmp(m_todalarm, m_todclock, m_todalarm.Length))
                {
                    trigger(INTERRUPT_ALARM);
                }
                break;

            case TOD_TEN:     // Time Of Day clock 1/10 s
            case TOD_SEC:     // Time Of Day clock sec
            case TOD_MIN:     // Time Of Day clock min
                if ((crb & 0x80) != 0)
                {
                    m_todalarm[addr - TOD_TEN] = data;
                }
                else
                {
                    if (addr == TOD_TEN)
                    {
                        m_todstopped = false;
                    }
                    if (addr == TOD_HR)
                    {
                        m_todstopped = true;
                    }
                    m_todclock[addr - TOD_TEN] = data;
                }
                // check alarm
                if (!m_todstopped && !memcmp(m_todalarm, m_todclock, m_todalarm.Length))
                {
                    trigger(INTERRUPT_ALARM);
                }
                break;

            case SDR:
                if ((cra & 0x40) != 0)
                {
                    sdr_buffered = true;
                }
                break;

            case ICR:
                if ((data & 0x80) != 0)
                {
                    icr |= (short)(data & 0x1f);
                }
                else
                {
                    icr &= (short)(~data & 0xff);
                }
                trigger(idr);
                break;

            case CRA:
                // Reset the underflow flipflop for the data port
                if (((data & 1) != 0) && ((cra & 1) == 0))
                {
                    ta           = ta_latch;
                    ta_underflow = true;
                }
                cra = data;

                // Check for forced load
                if ((data & 0x10) != 0)
                {
                    cra &= (~0x10 & 0xff);
                    ta   = ta_latch;
                }

                if ((data & 0x21) == 0x01)
                {
                    // Active
                    event_context.schedule(event_ta, (long)ta + 1, m_phase);
                }
                else
                {
                    // Inactive
                    event_context.cancel(event_ta);
                }
                break;

            case CRB:
                // Reset the underflow flipflop for the data port
                if (((data & 1) != 0) && ((crb & 1) == 0))
                {
                    tb           = tb_latch;
                    tb_underflow = true;
                }
                // Check for forced load
                crb = data;
                if ((data & 0x10) != 0)
                {
                    crb &= (~0x10 & 0xff);
                    tb   = tb_latch;
                }

                if ((data & 0x61) == 0x01)
                {
                    // Active
                    event_context.schedule(event_tb, (long)tb + 1, m_phase);
                }
                else
                {
                    // Inactive
                    event_context.cancel(event_tb);
                }
                break;

            default:
                break;
            }
        }
Example #2
0
        public void write(short addr, short data)
        {
            if (addr > 0x3f)
            {
                return;
            }

            regs[addr] = data;

            // Sync up timers
            _event();

            switch (addr)
            {
            case 0x11:     // Control register 1
            {
                raster_irq = SIDEndian.endian_16hi8(raster_irq, (short)(data >> 7));
                ctrl1      = data;
                y_scroll   = data & 7;

                if (raster_x < 11)
                {
                    break;
                }

                // In line $30, the DEN bit controls if Bad Lines can occur
                if ((raster_y == first_dma_line) && ((data & 0x10) != 0))
                {
                    bad_lines_enabled = true;
                }

                // Bad Line condition?
                bad_line = (raster_y >= first_dma_line) && (raster_y <= last_dma_line) && ((raster_y & 7) == y_scroll) && bad_lines_enabled;

                // Start bad dma line now
                if (bad_line && (raster_x < 53))
                {
                    addrctrl(false);
                }
                break;
            }

            case 0x12:     // Raster counter
                raster_irq = SIDEndian.endian_16lo8(raster_irq, data);
                break;

            case 0x17:
                sprite_expand_y |= (short)(~data & 0xff);
                break;

            case 0x19:     // IRQ flags
                idr &= (short)((~data & 0x0f) | 0x80);
                if (idr == 0x80)
                {
                    trigger(0);
                }
                break;

            case 0x1a:     // IRQ mask
                icr = (short)(data & 0x0f);
                trigger(icr & idr);
                break;
            }
        }
Example #3
0
        public short read(short addr)
        {
            long cycles;

            if (addr > 0x0f)
            {
                return(0);
            }

            bool ta_pulse = false, tb_pulse = false;

            cycles       = event_context.getTime(m_accessClk, event_context.phase);
            m_accessClk += cycles;

            // Sync up timers
            if ((cra & 0x21) == 0x01)
            {
                ta -= (int)cycles;
                if (ta == 0)
                {
                    ta_event();
                    ta_pulse = true;
                }
            }
            if ((crb & 0x61) == 0x01)
            {
                tb -= (int)cycles;
                if (tb == 0)
                {
                    tb_event();
                    tb_pulse = true;
                }
            }

            switch (addr)
            {
            case PRA:     // Simulate a serial port
                return((short)(regs[PRA] | (short)(~regs[DDRA] & 0xff)));

            case PRB:
            {
                short data = (short)(regs[PRB] | (short)(~regs[DDRB] & 0xff));
                // Timers can appear on the port
                if ((cra & 0x02) != 0)
                {
                    data &= 0xbf;
                    if ((cra & 0x04) != 0 ? ta_underflow : ta_pulse)
                    {
                        data |= 0x40;
                    }
                }
                if ((crb & 0x02) != 0)
                {
                    data &= 0x7f;
                    if ((crb & 0x04) != 0 ? tb_underflow : tb_pulse)
                    {
                        data |= 0x80;
                    }
                }
                return(data);
            }

            case TAL:
                return(SIDEndian.endian_16lo8(ta));

            case TAH:
                return(SIDEndian.endian_16hi8(ta));

            case TBL:
                return(SIDEndian.endian_16lo8(tb));

            case TBH:
                return(SIDEndian.endian_16hi8(tb));

            // TOD implementation taken from Vice
            // TOD clock is latched by reading Hours, and released
            // upon reading Tenths of Seconds. The counter itself
            // keeps ticking all the time.
            // Also note that this latching is different from the input one.
            case TOD_TEN:     // Time Of Day clock 1/10 s
            case TOD_SEC:     // Time Of Day clock sec
            case TOD_MIN:     // Time Of Day clock min
            case TOD_HR:      // Time Of Day clock hour
                if (!m_todlatched)
                {
                    for (int i = 0; i < m_todlatch.Length; i++)
                    {
                        m_todlatch[i] = m_todclock[i];
                    }
                }
                if (addr == TOD_TEN)
                {
                    m_todlatched = false;
                }
                if (addr == TOD_HR)
                {
                    m_todlatched = true;
                }
                return(m_todlatch[addr - TOD_TEN]);

            case IDR:
            {
                // Clear IRQs, and return interrupt data register
                short ret = idr;
                trigger(0);
                return(ret);
            }

            case CRA:
                return(cra);

            case CRB:
                return(crb);

            default:
                return(regs[addr]);
            }
        }