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