OSDN Git Service

[INITIAL] Import 20141226 version of http://homepage3.nifty.com/takeda-toshiya/common...
[csp-qt/common_source_project-fm7.git] / source / src / vm / sn76489an.cpp
1 /*\r
2         Skelton for retropc emulator\r
3 \r
4         Author : Takeda.Toshiya\r
5         Date   : 2006.08.18 -\r
6 \r
7         [ SN76489AN ]\r
8 */\r
9 \r
10 #include "sn76489an.h"\r
11 \r
12 #ifdef HAS_SN76489\r
13 // SN76489\r
14 #define NOISE_FB        0x4000\r
15 #define NOISE_DST_TAP   1\r
16 #define NOISE_SRC_TAP   2\r
17 #else\r
18 // SN76489A, SN76496\r
19 #define NOISE_FB        0x10000\r
20 #define NOISE_DST_TAP   4\r
21 #define NOISE_SRC_TAP   8\r
22 #endif\r
23 #define NOISE_MODE      ((regs[6] & 4) ? 1 : 0)\r
24 \r
25 void SN76489AN::initialize()\r
26 {\r
27         mute = false;\r
28         cs = we = true;\r
29 }\r
30 \r
31 void SN76489AN::reset()\r
32 {\r
33         for(int i = 0; i < 4; i++) {\r
34                 ch[i].count = 0;\r
35                 ch[i].period = 1;\r
36                 ch[i].volume = 0;\r
37                 ch[i].signal = false;\r
38         }\r
39         for(int i = 0; i < 8; i += 2) {\r
40                 regs[i + 0] = 0;\r
41                 regs[i + 1] = 0x0f;     // volume = 0\r
42         }\r
43         noise_gen = NOISE_FB;\r
44         ch[3].signal = false;\r
45 }\r
46 \r
47 void SN76489AN::write_io8(uint32 addr, uint32 data)\r
48 {\r
49         if(data & 0x80) {\r
50                 index = (data >> 4) & 7;\r
51                 int c = index >> 1;\r
52                 \r
53                 switch(index & 7) {\r
54                 case 0: case 2: case 4:\r
55                         // tone : frequency\r
56                         regs[index] = (regs[index] & 0x3f0) | (data & 0x0f);\r
57                         ch[c].period = regs[index] ? regs[index] : 0x400;\r
58 //                      ch[c].count = 0;\r
59                         break;\r
60                 case 1: case 3: case 5: case 7:\r
61                         // tone / noise : volume\r
62                         regs[index] = data & 0x0f;\r
63                         ch[c].volume = volume_table[data & 0x0f];\r
64                         break;\r
65                 case 6:\r
66                         // noise : frequency, mode\r
67                         regs[6] = data;\r
68                         data &= 3;\r
69                         ch[3].period = (data == 3) ? (ch[2].period << 1) : (1 << (data + 5));\r
70 //                      ch[3].count = 0;\r
71                         noise_gen = NOISE_FB;\r
72                         ch[3].signal = false;\r
73                         break;\r
74                 }\r
75         } else {\r
76                 int c = index >> 1;\r
77                 \r
78                 switch(index & 0x07) {\r
79                 case 0: case 2: case 4:\r
80                         // tone : frequency\r
81                         regs[index] = (regs[index] & 0x0f) | (((uint16)data << 4) & 0x3f0);\r
82                         ch[c].period = regs[index] ? regs[index] : 0x400;\r
83 //                      ch[c].count = 0;\r
84                         // update noise shift frequency\r
85                         if(index == 4 && (regs[6] & 3) == 3) {\r
86                                 ch[3].period = ch[2].period << 1;\r
87                         }\r
88                         break;\r
89                 }\r
90         }\r
91 }\r
92 \r
93 void SN76489AN::write_signal(int id, uint32 data, uint32 mask)\r
94 {\r
95         if(id == SIG_SN76489AN_MUTE) {\r
96                 mute = ((data & mask) != 0);\r
97         } else if(id == SIG_SN76489AN_DATA) {\r
98                 val = data & mask;\r
99         } else if(id == SIG_SN76489AN_CS) {\r
100                 bool next = ((data & mask) != 0);\r
101                 if(cs != next) {\r
102                         if(!(cs = next) && !we) {\r
103                                 write_io8(0, val);\r
104                         }\r
105                 }\r
106         } else if(id == SIG_SN76489AN_CS) {\r
107                 bool next = ((data & mask) != 0);\r
108                 if(cs != next) {\r
109                         cs = next;\r
110                         if(!cs && !we) {\r
111                                 write_io8(0, val);\r
112                         }\r
113                 }\r
114         } else if(id == SIG_SN76489AN_WE) {\r
115                 bool next = ((data & mask) != 0);\r
116                 if(we != next) {\r
117                         we = next;\r
118                         if(!cs && !we) {\r
119                                 write_io8(0, val);\r
120                         }\r
121                 }\r
122         }\r
123 }\r
124 \r
125 void SN76489AN::mix(int32* buffer, int cnt)\r
126 {\r
127         if(mute) {\r
128                 return;\r
129         }\r
130         for(int i = 0; i < cnt; i++) {\r
131                 int32 vol = 0;\r
132                 for(int j = 0; j < 4; j++) {\r
133                         if(!ch[j].volume) {\r
134                                 continue;\r
135                         }\r
136                         ch[j].count -= diff;\r
137                         if(ch[j].count < 0) {\r
138                                 ch[j].count += ch[j].period << 8;\r
139                                 if(j == 3) {\r
140                                         if(((noise_gen & NOISE_DST_TAP) ? 1 : 0) ^ (((noise_gen & NOISE_SRC_TAP) ? 1 : 0) * NOISE_MODE)) {\r
141                                                 noise_gen >>= 1;\r
142                                                 noise_gen |= NOISE_FB;\r
143                                         } else {\r
144                                                 noise_gen >>= 1;\r
145                                         }\r
146                                         ch[3].signal = ((noise_gen & 1) != 0);\r
147                                 } else {\r
148                                         ch[j].signal = !ch[j].signal;\r
149                                 }\r
150                         }\r
151                         vol += ch[j].signal ? ch[j].volume : -ch[j].volume;\r
152                 }\r
153                 *buffer++ += vol; // L\r
154                 *buffer++ += vol; // R\r
155         }\r
156 }\r
157 \r
158 void SN76489AN::init(int rate, int clock, int volume)\r
159 {\r
160         // create gain\r
161         double vol = volume;\r
162         for(int i = 0; i < 15; i++) {\r
163                 volume_table[i] = (int)vol;\r
164                 vol /= 1.258925412;\r
165         }\r
166         volume_table[15] = 0;\r
167         diff = 16 * clock / rate;\r
168 }\r
169 \r