|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2024 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // SSG (YM2149)
9: //
10:
11: #include "ssg.h"
12:
13: // コンストラクタ
14: SSGDevice::SSGDevice()
15: : inherited(OBJ_SSG)
16: {
17: monitor.func = ToMonitorCallback(&SSGDevice::MonitorUpdate);
18: monitor.SetSize(45, 12);
19: monitor.Regist(ID_MONITOR_SSG);
20: }
21:
22: // デストラクタ
23: SSGDevice::~SSGDevice()
24: {
25: }
26:
27: // リセット
28: void
29: SSGDevice::ResetHard(bool poweron)
30: {
31: }
32:
33: // A0 でアドレスポートとデータポートを分けるみたいなのではなく、
34: // 謎の BDIR と BC1 を R/W と A0 につないであるっぽい感じなので、
35: // トラップみたいな配置になっている。(紙資料も間違えている…)
36: //
37: // BDIR BC1 -> XP I/O
38: // 0 0 Inactive
39: // 0 1 Read 0x83 R
40: // 1 0 Write 0x82 W
41: // 1 1 Address 0x83 W
42:
43: busdata
44: SSGDevice::Read1(uint32 addr)
45: {
46: uint32 offset = addr & 1;
47: uint32 data;
48:
49: if (offset == 0) {
50: data = 0xff; // ?
51: } else {
52: // 読み込み
53: data = reg.Get(regno);
54: putlog(3, "R%x -> $%02x", regno, data);
55: }
56:
57: return data;
58: }
59:
60: busdata
61: SSGDevice::Write1(uint32 addr, uint32 data)
62: {
63: uint32 offset = addr & 1;
64:
65: if (offset == 0) {
66: // データ書き込み
67: putlog(2, "R%x <- $%02x", regno, data);
68: switch (regno) {
69: case 0x0: // Frequency of channel A (Low)
70: reg.freq[0] &= 0xf00;
71: reg.freq[0] |= data;
72: break;
73: case 0x1: // Frequency of channel A (High)
74: reg.freq[0] &= 0x0ff;
75: reg.freq[0] |= data << 8;
76: break;
77: case 0x2: // Frequency of channel B (Low)
78: reg.freq[1] &= 0xf00;
79: reg.freq[1] |= data;
80: break;
81: case 0x3: // Frequency of channel B (High)
82: reg.freq[1] &= 0x0ff;
83: reg.freq[1] |= data << 8;
84: break;
85: case 0x4: // Frequency of channel C (Low)
86: reg.freq[2] &= 0xf00;
87: reg.freq[2] |= data;
88: break;
89: case 0x5: // Frequency of channel C (High)
90: reg.freq[2] &= 0x0ff;
91: reg.freq[2] |= data << 8;
92: break;
93:
94: case 0x6: // Frequency of noise
95: reg.noise_freq = data & 0x1f;
96: break;
97:
98: case 0x7: // I/O port and mixer settings
99: reg.settings = data;
100: break;
101:
102: case 0x8: // Level of channel A
103: reg.ampmode[0] = (data & 0x10);
104: reg.amplevel[0] = data & 0x0f;
105: break;
106: case 0x9: // Level of channel B
107: reg.ampmode[1] = (data & 0x10);
108: reg.amplevel[1] = data & 0x0f;
109: break;
110: case 0xa: // Level of channel C
111: reg.ampmode[2] = (data & 0x10);
112: reg.amplevel[2] = data & 0x0f;
113: break;
114:
115: case 0xb: // Frequency of envelope (Low)
116: reg.envelope_freq &= 0xff00;
117: reg.envelope_freq |= data;
118: break;
119: case 0xc: // Frequency of envelope (Hight)
120: reg.envelope_freq &= 0x00ff;
121: reg.envelope_freq |= data << 8;
122: break;
123:
124: case 0xd: // Shape of envelope
125: reg.envelope_shape = data & 0x0f;
126: break;
127:
128: case 0xe: // Data of I/O port A
129: reg.dataA = data;
130: break;
131: case 0xf: // Data of I/O port B
132: reg.dataB = data;
133: break;
134:
135: default:
136: assertmsg(false, "regno=$%x", regno);
137: break;
138: }
139: } else {
140: // アドレス書き込み
141: regno = data & 0x0f;
142: putlog(4, "reg <- $%x", regno);
143: }
144:
145: return 0;
146: }
147:
148: busdata
149: SSGDevice::Peek1(uint32 addr)
150: {
151: return reg.Get(regno);
152: }
153:
154: void
155: SSGDevice::MonitorUpdate(Monitor *, TextScreen& screen)
156: {
157: // 012345678901234567890
158: // R1/R0 Freq ChA $xxx f=
159: // R3/R2 Freq ChB $xxx
160: // R5/R4 Freq ChC $xxx
161: // R6 FreqNoise $xx
162: // R7 Settings $xx(IB IA NC NB NA TC TB TA)
163: // R8 Level A $xx
164: // R9 Level B $xx
165: // Ra Level C $xx
166: // Rc/Rb EnvFreq $xxxx
167: // Rd EnvShape $xx
168: // Re Data A $xx
169: // Rf Data A $xx
170:
171: uint f;
172: int y = 0;
173:
174: screen.Clear();
175:
176: SSG tmp = reg;
177:
178: for (int i = 0; i < 3; i++) {
179: if (__predict_false(tmp.freq[i] == 0)) {
180: f = 0;
181: } else {
182: f = fMaster / (16 * tmp.freq[i]);
183: }
184: screen.Print(0, y, "R%u/R%u Freq Ch%c $%03x f=%u",
185: i * 2 + 1, i * 2, 'A' + i, tmp.freq[i], f);
186: y++;
187: }
188:
189: if (__predict_false(tmp.noise_freq == 0)) {
190: f = 0;
191: } else {
192: f = fMaster / (16 * tmp.noise_freq);
193: }
194: screen.Print(0, y++, "R6 FreqNoise $%02x f=%u", tmp.noise_freq, f);
195:
196: screen.Print(0, y, "R7 Settings $%02x(", tmp.settings);
197: screen.Puts(21, y, TA::OnOff(tmp.settings & 0x80), "IB");
198: screen.Puts(24, y, TA::OnOff(tmp.settings & 0x40), "IA");
199: screen.Puts(27, y, TA::OnOff(tmp.settings & 0x20), "NC");
200: screen.Puts(30, y, TA::OnOff(tmp.settings & 0x10), "NB");
201: screen.Puts(33, y, TA::OnOff(tmp.settings & 0x08), "NA");
202: screen.Puts(36, y, TA::OnOff(tmp.settings & 0x04), "TA");
203: screen.Puts(39, y, TA::OnOff(tmp.settings & 0x02), "TA");
204: screen.Puts(42, y, TA::OnOff(tmp.settings & 0x01), "TA");
205: screen.Putc(44, y, ')');
206: y++;
207:
208: for (int i = 0; i < 3; i++) {
209: screen.Print(0, y++, "R%x Level %c $%02x",
210: 8 + i, 'A' + i, tmp.GetLevelReg(i));
211: }
212:
213: if (__predict_false(tmp.envelope_freq == 0)) {
214: f = 0;
215: } else {
216: f = fMaster / (256 * tmp.envelope_freq);
217: }
218: screen.Print(0, y++, "Rc/Rb EnvFreq $%04x f=%u", tmp.envelope_freq, f);
219:
220: // モニタはソースコードのマルチバイト文字(UTF-8) を SJIS に変換する所は
221: // (まだ?)用意してないので、こっちで SJIS 文字列を用意する必要がある。
222: #define H "\x81\x50"
223: #define L "\x81\x51"
224: #define U "\x81\x5e"
225: #define D "\x81\x5f"
226: static const char *shape8[8] = {
227: D D D D D, // "\\\\\"
228: D L L L L, // "\____"
229: D U D U D, // "\/\/\"
230: D H H H H, // "\ ̄ ̄ ̄ ̄"
231: U U U U U, // "/////"
232: U H H H H, // "/ ̄ ̄ ̄ ̄"
233: U D U D U, // "/\/\/"
234: U L L L L, // "/____"
235: };
236: const char *shape;
237: uint es = tmp.envelope_shape;
238: if (es >= 8) {
239: shape = shape8[es - 8];
240: } else if (es >= 4) {
241: shape = shape8[7];
242: } else {
243: shape = shape8[1];
244: }
245: screen.Print(0, y++, "Rd EnvShape $%02x %s",
246: tmp.envelope_shape, shape);
247: screen.Print(0, y++, "Re Data A $%02x", tmp.dataA);
248: screen.Print(0, y++, "Rf Data B $%02x", tmp.dataB);
249: }
250:
251: // レジスタの内容を副作用なく返す。
252: uint32
253: SSG::Get(uint n) const
254: {
255: switch (n) {
256: case 0x0:
257: return freq[0] & 0xff;
258: case 0x1:
259: return freq[0] >> 8;
260: case 0x2:
261: return freq[1] & 0xff;
262: case 0x3:
263: return freq[1] >> 8;
264: case 0x4:
265: return freq[2] & 0xff;
266: case 0x5:
267: return freq[2] >> 8;
268: case 0x6:
269: return noise_freq;
270: case 0x7:
271: return settings;
272: case 0x8:
273: return GetLevelReg(0);
274: case 0x9:
275: return GetLevelReg(1);
276: case 0xa:
277: return GetLevelReg(2);
278: case 0xb:
279: return envelope_freq & 0xff;
280: case 0xc:
281: return envelope_freq >> 8;
282: case 0xd:
283: return envelope_shape;
284: case 0xe:
285: return dataA;
286: case 0xf:
287: return dataB;
288: default:
289: __unreachable();
290: }
291: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.