summaryrefslogtreecommitdiff
path: root/libsidplay2/sidplay-libs-2.1.0/libsidplay/src/sid6526/sid6526.cpp
blob: 8737f7f0a2ec4c3cb2e3a1b99b2ca95dece6d059 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/***************************************************************************
                          sid6526.cpp  -  description
                             -------------------
    begin                : Wed Jun 7 2000
    copyright            : (C) 2000 by Simon White
    email                : s_a_white@email.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
/***************************************************************************
 *  $Log: sid6526.cpp,v $
 *  Revision 1.7  2002/10/02 19:48:15  s_a_white
 *  Make CIA control register reflect that the timer cannot be disabled.
 *
 *  Revision 1.6  2002/03/11 18:00:29  s_a_white
 *  Better mirror sidplay1s handling of random numbers.
 *
 *  Revision 1.5  2002/03/03 22:03:49  s_a_white
 *  Tidy.
 *
 *  Revision 1.4  2001/10/02 18:01:36  s_a_white
 *  Support for cleaned c64env.
 *
 *  Revision 1.3  2001/09/18 02:22:37  jpaana
 *  Fixed include filename to lowercase
 *
 *  Revision 1.2  2001/09/03 22:24:09  s_a_white
 *  New counts for timer A are correctly formed.
 *
 *  Revision 1.1  2001/09/01 11:11:19  s_a_white
 *  This is the old fake6526 code required for sidplay1 environment modes.
 *
 ***************************************************************************/

#include <time.h>
#include "sidendian.h"
#include "sid6526.h"

const char * const SID6526::credit =
{   // Optional information
    "*SID6526 (SIDPlay1 Fake CIA) Emulation:\0"
    "\tCopyright (C) 2001 Simon White <sidplay2@email.com>\0"
};

SID6526::SID6526 (c64env *env)
:m_env(*env),
 m_eventContext(m_env.context ()),
 rnd(0),
 m_taEvent(*this)
{
    clock (0xffff);
    reset ();
}

void SID6526::reset (void)
{
    locked = false;
    ta   = ta_latch = m_count;
    cra  = 0;
    rnd += time(NULL) & 0xff;
    m_accessClk = 0;
}

uint8_t SID6526::read (uint_least8_t addr)
{
    if (addr > 0x0f)
        return 0;

    switch (addr)
    {
    case 0x04:
    case 0x05:
    case 0x11:
    case 0x12:
        rnd = rnd * 13 + 1;
        return (uint8_t) (rnd >> 3);
    break;
    default:
        return regs[addr];
    }
}

void SID6526::write (uint_least8_t addr, uint8_t data)
{
    if (addr > 0x0f)
        return;

    regs[addr] = data;

    if (locked)
        return; // Stop program changing time interval

    {   // Sync up timer
        event_clock_t cycles;
        cycles       = m_eventContext.getTime (m_accessClk);
        m_accessClk += cycles;
        ta          -= cycles;
    }

    switch (addr)
    {
    case 0x4: endian_16lo8 (ta_latch, data); break;
    case 0x5:
        endian_16hi8 (ta_latch, data);
        if (!(cra & 0x01)) // Reload timer if stopped
            ta = ta_latch;
    break;
    case 0x0e:
        cra = data | 0x01;
        if (data & 0x10)
        {
            cra &= (~0x10);
            ta   = ta_latch;
        }
        m_eventContext.schedule (&m_taEvent, (event_clock_t) ta + 1);
    break;
    default:
    break;
    }
}

void SID6526::event (void)
{   // Timer Modes
    m_accessClk = m_eventContext.getTime ();
    ta = ta_latch;
    m_eventContext.schedule (&m_taEvent, (event_clock_t) ta + 1);
    m_env.interruptIRQ (true);
}