Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
dave.c
Go to the documentation of this file.
1 /* Xep128: Minimalistic Enterprise-128 emulator with focus on "exotic" hardware
2  Copyright (C)2015,2016 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3  http://xep128.lgb.hu/
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18 
19 
20 #include "xep128.h"
21 #include "dave.h"
22 #include "primoemu.h"
23 #include "cpu.h"
24 #include "printer.h"
25 
26 #include <SDL.h>
27 
28 
30 Uint8 kbd_matrix[16]; // the "real" EP kbd matrix only uses the first 10 bytes though
31 static Uint8 dave_int_write;
32 static int cnt_1hz, cnt_50hz, cnt_31khz, cnt_1khz, cnt_tg0, cnt_tg1, cnt_tg2;
33 static int cnt_load_tg0, cnt_load_tg1, cnt_load_tg2;
34 static int tg0_ff, tg1_ff, tg2_ff;
38 
39 
41 
42 
43 static SDL_AudioDeviceID audio = 0;
44 static SDL_AudioSpec audio_spec;
45 #define AUDIO_BUFFER_SIZE 0x4000
46 static Uint8 audio_buffer[AUDIO_BUFFER_SIZE];
47 static Uint8 *audio_buffer_r = audio_buffer;
48 static Uint8 *audio_buffer_w = audio_buffer;
49 static int dave_ticks_per_sample_counter = 0;
50 static int dave_ticks_per_sample = 6;
51 
52 
53 
54 static inline Uint16 dave_render_audio_sample ( void )
55 {
56  int left, right;
57  /* TODO: missing noise channel, polynom counters/ops, modulation, etc */
58  if (ports[0xA7] & 8)
59  left = ports[0xA8] << 2; // left ch is in D/A mode
60  else { // left ch is in "normal" mode
61  //tg0_ff = tg1_ff = tg2_ff = 1;
62  left = tg0_ff * ports[0xA8] +
63  tg1_ff * ports[0xA9] +
64  tg2_ff * ports[0xAA];
65  }
66  if (ports[0xA7] & 16)
67  right = ports[0xAC] << 2; // right ch is in D/A mode
68  else { // right ch is in "normal" mode
69  //tg0_ff = tg1_ff = tg2_ff = 1;
70  right = tg0_ff * ports[0xAC] +
71  tg1_ff * ports[0xAD] +
72  tg2_ff * ports[0xAE];
73  }
74 #if 0
75  DEBUGPRINT("DAVE: TG: %d %d %d Vol-l=%02X,%02X,%02X,%02X Vol-r=%02X,%02X,%02X,%02X FREQ=%d,%d,%d CNT=%d,%d,%d SYNC=%d" NL, tg0_ff, tg1_ff, tg2_ff,
76  ports[0xA8], ports[0xA9], ports[0xAA], ports[0xAB],
77  ports[0xAC], ports[0xAD], ports[0xAE], ports[0xAF],
78  ports[0xA0] | ((ports[0xA1] & 15) << 8),
79  ports[0xA2] | ((ports[0xA3] & 15) << 8),
80  ports[0xA4] | ((ports[0xA5] & 15) << 8),
81  cnt_tg0, cnt_tg1, cnt_tg2,
82  ports[0xA7] & 7
83  );
84 #endif
85  return (right << 8) | left;
86 }
87 
88 
89 
90 static void audio_fill_stereo ( Uint16 stereo_sample )
91 {
92  *(Uint16*)(audio_buffer_w) = stereo_sample;
93  audio_buffer_w += 2;
94  if (audio_buffer_w == audio_buffer + AUDIO_BUFFER_SIZE)
95  audio_buffer_w = audio_buffer;
96 }
97 
98 
99 
100 static void audio_callback(void *userdata, Uint8 *stream, int len)
101 {
102  while (len--) {
103  if (audio_buffer_r == audio_buffer_w) {
104  //*(stream++) = 0;
105  *(stream++) = 0;
106  } else {
107  //*(stream++) = *(audio_buffer_r++);
108  *(stream++) = *(audio_buffer_r++);
109  if (audio_buffer_r == audio_buffer + AUDIO_BUFFER_SIZE)
110  audio_buffer_r = audio_buffer;
111  }
112  }
113 }
114 
115 
116 
117 void audio_start ( void )
118 {
119  if (audio)
120  SDL_PauseAudioDevice(audio, 0);
121 }
122 
123 
124 
125 void audio_stop ( void )
126 {
127  if (audio)
128  SDL_PauseAudioDevice(audio, 1);
129 }
130 
131 
132 
133 void audio_close ( void )
134 {
135  audio_stop();
136  if (audio)
137  SDL_CloseAudioDevice(audio);
138  audio = 0;
139 }
140 
141 
142 
143 void audio_init ( int enable )
144 {
145  SDL_AudioSpec want;
146  if (!enable) return;
147  SDL_memset(&want, 0, sizeof(want));
148  want.freq = 41666;
149  want.format = AUDIO_U8;
150  want.channels = 2;
151  want.samples = 4096;
152  want.callback = audio_callback;
153  want.userdata = NULL;
154  audio = SDL_OpenAudioDevice(NULL, 0, &want, &audio_spec, 0);
155  if (!audio)
156  ERROR_WINDOW("Cannot initiailze audio: %s\n", SDL_GetError());
157  else if (want.freq != audio_spec.freq || want.format != audio_spec.format || want.channels != audio_spec.channels) {
158  audio_close();
159  ERROR_WINDOW("Bad audio parameters (w/h freq=%d/%d, fmt=%d/%d, chans=%d/%d, smpls=%d/%d, cannot use sound",
160  want.freq, audio_spec.freq, want.format, audio_spec.format, want.channels, audio_spec.channels, want.samples, audio_spec.samples
161  );
162  } else
163  audio_stop(); // still stopped ... must be audio_start()'ed by the caller
164 }
165 
166 
167 
168 void dave_set_clock ( void )
169 {
170  // FIXME maybe: Currently, it's assumed that Dave and CPU has fixed relation about clock
171  //double turbo_rate = (double)CPU_CLOCK / (double)DEFAULT_CPU_CLOCK;
172  if (ports[0xBF] & 2) {
173  cpu_cycles_per_dave_tick = 24; // 12MHz (??)
174  dave_ticks_per_sample = 4;
175  } else {
176  cpu_cycles_per_dave_tick = 16; // 8MHz (??)
177  dave_ticks_per_sample = 6;
178  }
179  //DEBUG("DAVE: CLOCK: assumming %dMHz input, CPU clock divisor is %d, CPU cycles per Dave tick is %d" NL, (ports[0xBF] & 2) ? 12 : 8, CPU_CLOCK / cpu_cycles_per_dave_tick, cpu_cycles_per_dave_tick);
180  mem_wait_states = (CPU_CLOCK > 4000000) ? 2 : 1; // memory wait states (non-VRAM only!) asked by BF port is 1, but 2 for "turbo" Z80 solutions
181 }
182 
183 
184 
185 void kbd_matrix_reset ( void )
186 {
187  memset(kbd_matrix, 0xFF, sizeof(kbd_matrix));
188 }
189 
190 
191 
192 void dave_reset ( void )
193 {
194  int a;
195  //kbd_matrix_reset();
196  for (a = 0xA0; a <= 0xBF; a++)
197  z80ex_pwrite_cb(a, 0);
198  dave_int_read = 0;
199  dave_int_write = 0;
200  kbd_selector = -1;
201  cnt_1hz = 0; cnt_50hz = 0; cnt_31khz = 0; cnt_1khz = 0; cnt_tg0 = 0; cnt_tg1 = 0; cnt_tg2 = 0;
202  tg0_ff = 0; tg1_ff = 0; tg2_ff = 0;
203  //mem_ws_all = 0;
204  //mem_ws_m1 = 0;
205  //NICK_SLOTS_PER_DAVE_TICK_HI = NICK_SLOTS_PER_SEC / 250000.0;
206  //_set_timing();
207  DEBUG("DAVE: reset" NL);
208 }
209 
210 
211 
212 /* Called by Nick */
213 void dave_int1(int level)
214 {
215  if (level) {
216  dave_int_read |= 16; // set level
217  } else {
218  // the truth is here, if previous level was set (falling edge), and int1 is enabled, then set latch!
219  if ((dave_int_read & 16) && (dave_int_write & 16)) {
220  DEBUG("DAVE/VINT: LACTH is set!" NL);
221  dave_int_read |= 32; // set latch
222  if (primo_on)
224  }
225  dave_int_read &= 239; // reset level
226  }
227 }
228 
229 
230 
231 static inline void dave_int_tg ( void )
232 {
233  if (dave_int_write & 1)
234  dave_int_read |= 2; // set latch if TG int is enabled
235  dave_int_read ^= 1; // negate level
236 }
237 
238 
239 
240 void dave_tick ( void )
241 {
242  // TODO 31.25KHz counter for some reason :) what I forgot :-P
243  /* 50Hz counter */
244  if ((--cnt_50hz) < 0) {
245  cnt_50hz = 5000 - 1;
246  if ((ports[0xA7] & 96) == 32)
247  dave_int_tg();
248  }
249  /* 1KHz counter */
250  if ((--cnt_1khz) < 0) {
251  cnt_1khz = 250 - 1;
252  if ((ports[0xA7] & 96) == 0)
253  dave_int_tg();
254  }
255  /* counter for tone channel #0 */
256  if (ports[0xA7] & 1) { // sync mode?
257  cnt_tg0 = cnt_load_tg0;
258  tg0_ff = 0;
259  } else if ((--cnt_tg0) < 0) {
260  cnt_tg0 = cnt_load_tg0;
261  tg0_ff ^= 1;
262  if ((ports[0xA7] & 96) == 64)
263  dave_int_tg();
264  }
265  /* counter for tone channel #1 */
266  if (ports[0xA7] & 2) { // sync mode?
267  cnt_tg1 = cnt_load_tg1;
268  tg1_ff = 0;
269  } else if ((--cnt_tg1) < 0) {
270  cnt_tg1 = cnt_load_tg1;
271  tg1_ff ^= 1;
272  if ((ports[0xA7] & 96) == 96)
273  dave_int_tg();
274  }
275  /* counter for tone channel #2 */
276  if (ports[0xA7] & 4) { // sync mode?
277  cnt_tg2 = cnt_load_tg2;
278  tg2_ff = 0;
279  } else if ((--cnt_tg2) < 0) {
280  cnt_tg2 = cnt_load_tg2;
281  tg2_ff ^= 1;
282  }
283  /* handling the 1Hz interrupt */
284  if ((--cnt_1hz) < 0) {
285  cnt_1hz = 250000 - 1;
286  if (dave_int_write & 4)
287  dave_int_read |= 8; // set latch, if 1Hz int source is enabled
288  dave_int_read ^= 4; // negate 1Hz interrupt level bit (actually the freq is 0.5Hz, but int is generated on each edge, thus 1Hz)
289  //DEBUG("DAVE: 1HZ interrupt level: %d" NL, dave_int_read & 4);
290  }
291  // SOUND
292  if (audio) {
293  if ((--dave_ticks_per_sample_counter) < 0) {
294  switch (audio_source) {
295  case AUDIO_SOURCE_DAVE:
296  audio_fill_stereo(dave_render_audio_sample());
297  break;
299  audio_fill_stereo((printer_data_byte << 8) | printer_data_byte); // both stereo channels has the same byte ...
300  break;
302  audio_fill_stereo(
303  ((ports[0xF0] + ports[0xF1]) >> 1) | // left
304  (((ports[0xF2] + ports[0xF3]) >> 1) << 8) // right
305  );
306  break;
307  default:
308  FATAL("Audio source renderer %d is not known!", audio_source);
309  break;
310  }
311  dave_ticks_per_sample_counter = dave_ticks_per_sample - 1;
312  }
313  }
314 }
315 
316 
317 
319 {
320  dave_int_write = n;
321  dave_int_read &= (0x55 | ((~n) & 0xAA)); // this "nice" stuff resets desired latches
322  dave_int_read &= (0x55 | ((n << 1) & 0xAA)); // TODO / FIXME: not sure if it is needed!
323 }
324 
325 
326 
328 {
329  printer_disable_covox(); // disable COVOX mode, if any
331  switch (port) {
332  case 0xA0:
333  cnt_load_tg0 = (cnt_load_tg0 & 0xF00 ) | value;
334  break;
335  case 0xA1:
336  cnt_load_tg0 = (cnt_load_tg0 & 0x0FF ) | ((value & 0xF) << 8);
337  break;
338  case 0xA2:
339  cnt_load_tg1 = (cnt_load_tg1 & 0xF00 ) | value;
340  break;
341  case 0xA3:
342  cnt_load_tg1 = (cnt_load_tg1 & 0x0FF ) | ((value & 0xF) << 8);
343  break;
344  case 0xA4:
345  cnt_load_tg2 = (cnt_load_tg2 & 0xF00 ) | value;
346  break;
347  case 0xA5:
348  cnt_load_tg2 = (cnt_load_tg2 & 0x0FF ) | ((value & 0xF) << 8);
349  break;
350  case 0xA8:
351  case 0xA9:
352  case 0xAA:
353  case 0xAB:
354  case 0xAC:
355  case 0xAD:
356  case 0xAE:
357  case 0xAF:
358  ports[port] &= 63; // so we don't need to do this AND again and again ...
359  break;
360  }
361 }
kbd_selector
int kbd_selector
Definition: dave.c:35
z80ex_pwrite_cb
void z80ex_pwrite_cb(Z80EX_WORD port16, Z80EX_BYTE value)
Definition: cpu.c:396
audio_source
int audio_source
Definition: dave.c:40
dave.h
Uint8
uint8_t Uint8
Definition: fat32.c:51
kbd_matrix_reset
void kbd_matrix_reset(void)
Definition: dave.c:199
dave_configure_interrupts
void dave_configure_interrupts(Uint8 n)
Definition: dave.c:332
cpu.h
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
dave_tick
void dave_tick(void)
Definition: dave.c:254
printer.h
dave_reset
void dave_reset(void)
Definition: dave.c:206
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
NL
#define NL
Definition: fat32.c:37
audio_init
void audio_init(int enable)
Definition: dave.c:153
audio_start
void audio_start(void)
Definition: dave.c:123
primo_nmi_enabled
int primo_nmi_enabled
Definition: primoemu.c:31
audio_close
void audio_close(void)
Definition: dave.c:143
printer_data_byte
Uint8 printer_data_byte
Definition: printer.c:39
printer_disable_covox
void printer_disable_covox(void)
Definition: printer.c:136
dave_int1
void dave_int1(int level)
Definition: dave.c:227
xep128.h
AUDIO_BUFFER_SIZE
#define AUDIO_BUFFER_SIZE
Definition: dave.c:45
AUDIO_SOURCE_PRINTER_COVOX
#define AUDIO_SOURCE_PRINTER_COVOX
Definition: dave.h:23
kbd_matrix
Uint8 kbd_matrix[16]
Definition: dave.c:30
audio_stop
void audio_stop(void)
Definition: dave.c:133
dave_set_clock
void dave_set_clock(void)
Definition: dave.c:182
dave_write_audio_register
void dave_write_audio_register(Uint8 port, Uint8 value)
Definition: dave.c:341
CPU_CLOCK
#define CPU_CLOCK
Definition: tvc.h:30
AUDIO_SOURCE_DTM_DAC4
#define AUDIO_SOURCE_DTM_DAC4
Definition: dave.h:24
value
int value
Definition: dma65.c:90
stream
Uint8 * stream
Definition: inject.c:36
Uint16
uint16_t Uint16
Definition: fat32.c:50
AUDIO_SOURCE_DAVE
#define AUDIO_SOURCE_DAVE
Definition: dave.h:22
cpu_cycles_per_dave_tick
int cpu_cycles_per_dave_tick
Definition: dave.c:36
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
mem_wait_states
int mem_wait_states
Definition: dave.c:37
primoemu.h
FATAL
#define FATAL(...)
Definition: xep128.h:117
primo_on
int primo_on
Definition: primoemu.c:30
dave_int_read
Uint8 dave_int_read
Definition: dave.c:29
nmi_pending
int nmi_pending
Definition: cpu.c:47