Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
dave.c
Go to the documentation of this file.
1 /* Minimalistic Enterprise-128 emulator with focus on "exotic" hardware
2  Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3  Copyright (C)2015-2016,2020 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
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 "xemu/emutools.h"
21 #include "xemu/emutools_hid.h"
22 #include "enterprise128.h"
23 #include "dave.h"
24 #include "primoemu.h"
25 #include "cpu.h"
26 #include "printer.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 int audio_stopped = 0;
45 static SDL_AudioSpec audio_spec;
46 #define AUDIO_BUFFER_SIZE 0x4000
47 static Uint8 audio_buffer[AUDIO_BUFFER_SIZE];
48 static Uint8 *audio_buffer_r = audio_buffer;
49 static Uint8 *audio_buffer_w = audio_buffer;
50 static int dave_ticks_per_sample_counter = 0;
51 static int dave_ticks_per_sample = 6;
52 
53 
54 
55 static inline Uint16 dave_render_audio_sample ( void )
56 {
57  int left, right;
58  /* TODO: missing noise channel, polynom counters/ops, modulation, etc */
59  if (ports[0xA7] & 8)
60  left = ports[0xA8] << 2; // left ch is in D/A mode
61  else { // left ch is in "normal" mode
62  //tg0_ff = tg1_ff = tg2_ff = 1;
63  left = tg0_ff * ports[0xA8] +
64  tg1_ff * ports[0xA9] +
65  tg2_ff * ports[0xAA];
66  }
67  if (ports[0xA7] & 16)
68  right = ports[0xAC] << 2; // right ch is in D/A mode
69  else { // right ch is in "normal" mode
70  //tg0_ff = tg1_ff = tg2_ff = 1;
71  right = tg0_ff * ports[0xAC] +
72  tg1_ff * ports[0xAD] +
73  tg2_ff * ports[0xAE];
74  }
75 #if 0
76  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,
77  ports[0xA8], ports[0xA9], ports[0xAA], ports[0xAB],
78  ports[0xAC], ports[0xAD], ports[0xAE], ports[0xAF],
79  ports[0xA0] | ((ports[0xA1] & 15) << 8),
80  ports[0xA2] | ((ports[0xA3] & 15) << 8),
81  ports[0xA4] | ((ports[0xA5] & 15) << 8),
82  cnt_tg0, cnt_tg1, cnt_tg2,
83  ports[0xA7] & 7
84  );
85 #endif
86  return (right << 8) | left;
87 }
88 
89 
90 
91 static void audio_fill_stereo ( Uint16 stereo_sample )
92 {
93  *(Uint16*)(audio_buffer_w) = stereo_sample;
94  audio_buffer_w += 2;
95  if (audio_buffer_w == audio_buffer + AUDIO_BUFFER_SIZE)
96  audio_buffer_w = audio_buffer;
97 }
98 
99 
100 
101 static void audio_callback(void *userdata, Uint8 *stream, int len)
102 {
103  while (len--) {
104  if (audio_buffer_r == audio_buffer_w) {
105  //*(stream++) = 0;
106  *(stream++) = 0;
107  } else {
108  //*(stream++) = *(audio_buffer_r++);
109  *(stream++) = *(audio_buffer_r++);
110  if (audio_buffer_r == audio_buffer + AUDIO_BUFFER_SIZE)
111  audio_buffer_r = audio_buffer;
112  }
113  }
114 }
115 
116 
118 {
119  return (audio != 0 && !audio_stopped);
120 }
121 
122 
123 void audio_start ( void )
124 {
125  if (audio) {
126  SDL_PauseAudioDevice(audio, 0);
127  audio_stopped = 0;
128  }
129 }
130 
131 
132 
133 void audio_stop ( void )
134 {
135  if (audio) {
136  SDL_PauseAudioDevice(audio, 1);
137  audio_stopped = 1;
138  }
139 }
140 
141 
142 
143 void audio_close ( void )
144 {
145  audio_stop();
146  if (audio)
147  SDL_CloseAudioDevice(audio);
148  audio = 0;
149 }
150 
151 
152 
153 void audio_init ( int enable )
154 {
155  if (audio)
156  return;
157  SDL_AudioSpec want;
158  if (!enable)
159  return;
160  SDL_memset(&want, 0, sizeof(want));
161  want.freq = 41666;
162  want.format = AUDIO_U8;
163  want.channels = 2;
164  want.samples = 4096;
165  want.callback = audio_callback;
166  want.userdata = NULL;
167  audio = SDL_OpenAudioDevice(NULL, 0, &want, &audio_spec, 0);
168  if (!audio)
169  ERROR_WINDOW("Cannot initiailze audio: %s\n", SDL_GetError());
170  else if (want.freq != audio_spec.freq || want.format != audio_spec.format || want.channels != audio_spec.channels) {
171  audio_close();
172  ERROR_WINDOW("Bad audio parameters (w/h freq=%d/%d, fmt=%d/%d, chans=%d/%d, smpls=%d/%d, cannot use sound",
173  want.freq, audio_spec.freq, want.format, audio_spec.format, want.channels, audio_spec.channels, want.samples, audio_spec.samples
174  );
175  } else {
176  audio_stop(); // still stopped ... must be audio_start()'ed by the caller
177  }
178 }
179 
180 
181 
182 void dave_set_clock ( void )
183 {
184  // FIXME maybe: Currently, it's assumed that Dave and CPU has fixed relation about clock
185  //double turbo_rate = (double)CPU_CLOCK / (double)DEFAULT_CPU_CLOCK;
186  if (ports[0xBF] & 2) {
187  cpu_cycles_per_dave_tick = 24; // 12MHz (??)
188  dave_ticks_per_sample = 4;
189  } else {
190  cpu_cycles_per_dave_tick = 16; // 8MHz (??)
191  dave_ticks_per_sample = 6;
192  }
193  //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);
194  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
195 }
196 
197 
198 
199 void kbd_matrix_reset ( void )
200 {
201  memset(kbd_matrix, 0xFF, sizeof(kbd_matrix));
202 }
203 
204 
205 
206 void dave_reset ( void )
207 {
208  int a;
209  //kbd_matrix_reset();
210  for (a = 0xA0; a <= 0xBF; a++)
211  z80ex_pwrite_cb(a, 0);
212  dave_int_read = 0;
213  dave_int_write = 0;
214  kbd_selector = -1;
215  cnt_1hz = 0; cnt_50hz = 0; cnt_31khz = 0; cnt_1khz = 0; cnt_tg0 = 0; cnt_tg1 = 0; cnt_tg2 = 0;
216  tg0_ff = 0; tg1_ff = 0; tg2_ff = 0;
217  //mem_ws_all = 0;
218  //mem_ws_m1 = 0;
219  //NICK_SLOTS_PER_DAVE_TICK_HI = NICK_SLOTS_PER_SEC / 250000.0;
220  //_set_timing();
221  DEBUG("DAVE: reset" NL);
222 }
223 
224 
225 
226 /* Called by Nick */
227 void dave_int1(int level)
228 {
229  if (level) {
230  dave_int_read |= 16; // set level
231  } else {
232  // the truth is here, if previous level was set (falling edge), and int1 is enabled, then set latch!
233  if ((dave_int_read & 16) && (dave_int_write & 16)) {
234  DEBUG("DAVE/VINT: LACTH is set!" NL);
235  dave_int_read |= 32; // set latch
236  if (primo_on)
238  }
239  dave_int_read &= 239; // reset level
240  }
241 }
242 
243 
244 
245 static inline void dave_int_tg ( void )
246 {
247  if (dave_int_write & 1)
248  dave_int_read |= 2; // set latch if TG int is enabled
249  dave_int_read ^= 1; // negate level
250 }
251 
252 
253 
254 void dave_tick ( void )
255 {
256  // TODO 31.25KHz counter for some reason :) what I forgot :-P
257  /* 50Hz counter */
258  if ((--cnt_50hz) < 0) {
259  cnt_50hz = 5000 - 1;
260  if ((ports[0xA7] & 96) == 32)
261  dave_int_tg();
262  }
263  /* 1KHz counter */
264  if ((--cnt_1khz) < 0) {
265  cnt_1khz = 250 - 1;
266  if ((ports[0xA7] & 96) == 0)
267  dave_int_tg();
268  }
269  /* counter for tone channel #0 */
270  if (ports[0xA7] & 1) { // sync mode?
271  cnt_tg0 = cnt_load_tg0;
272  tg0_ff = 0;
273  } else if ((--cnt_tg0) < 0) {
274  cnt_tg0 = cnt_load_tg0;
275  tg0_ff ^= 1;
276  if ((ports[0xA7] & 96) == 64)
277  dave_int_tg();
278  }
279  /* counter for tone channel #1 */
280  if (ports[0xA7] & 2) { // sync mode?
281  cnt_tg1 = cnt_load_tg1;
282  tg1_ff = 0;
283  } else if ((--cnt_tg1) < 0) {
284  cnt_tg1 = cnt_load_tg1;
285  tg1_ff ^= 1;
286  if ((ports[0xA7] & 96) == 96)
287  dave_int_tg();
288  }
289  /* counter for tone channel #2 */
290  if (ports[0xA7] & 4) { // sync mode?
291  cnt_tg2 = cnt_load_tg2;
292  tg2_ff = 0;
293  } else if ((--cnt_tg2) < 0) {
294  cnt_tg2 = cnt_load_tg2;
295  tg2_ff ^= 1;
296  }
297  /* handling the 1Hz interrupt */
298  if ((--cnt_1hz) < 0) {
299  cnt_1hz = 250000 - 1;
300  if (dave_int_write & 4)
301  dave_int_read |= 8; // set latch, if 1Hz int source is enabled
302  dave_int_read ^= 4; // negate 1Hz interrupt level bit (actually the freq is 0.5Hz, but int is generated on each edge, thus 1Hz)
303  //DEBUG("DAVE: 1HZ interrupt level: %d" NL, dave_int_read & 4);
304  }
305  // SOUND
306  if (audio) {
307  if ((--dave_ticks_per_sample_counter) < 0) {
308  switch (audio_source) {
309  case AUDIO_SOURCE_DAVE:
310  audio_fill_stereo(dave_render_audio_sample());
311  break;
313  audio_fill_stereo((printer_data_byte << 8) | printer_data_byte); // both stereo channels has the same byte ...
314  break;
316  audio_fill_stereo(
317  ((ports[0xF0] + ports[0xF1]) >> 1) | // left
318  (((ports[0xF2] + ports[0xF3]) >> 1) << 8) // right
319  );
320  break;
321  default:
322  FATAL("Audio source renderer %d is not known!", audio_source);
323  break;
324  }
325  dave_ticks_per_sample_counter = dave_ticks_per_sample - 1;
326  }
327  }
328 }
329 
330 
331 
333 {
334  dave_int_write = n;
335  dave_int_read &= (0x55 | ((~n) & 0xAA)); // this "nice" stuff resets desired latches
336  dave_int_read &= (0x55 | ((n << 1) & 0xAA)); // TODO / FIXME: not sure if it is needed!
337 }
338 
339 
340 
342 {
343  printer_disable_covox(); // disable COVOX mode, if any
345  switch (port) {
346  case 0xA0:
347  cnt_load_tg0 = (cnt_load_tg0 & 0xF00 ) | value;
348  break;
349  case 0xA1:
350  cnt_load_tg0 = (cnt_load_tg0 & 0x0FF ) | ((value & 0xF) << 8);
351  break;
352  case 0xA2:
353  cnt_load_tg1 = (cnt_load_tg1 & 0xF00 ) | value;
354  break;
355  case 0xA3:
356  cnt_load_tg1 = (cnt_load_tg1 & 0x0FF ) | ((value & 0xF) << 8);
357  break;
358  case 0xA4:
359  cnt_load_tg2 = (cnt_load_tg2 & 0xF00 ) | value;
360  break;
361  case 0xA5:
362  cnt_load_tg2 = (cnt_load_tg2 & 0x0FF ) | ((value & 0xF) << 8);
363  break;
364  case 0xA8:
365  case 0xA9:
366  case 0xAA:
367  case 0xAB:
368  case 0xAC:
369  case 0xAD:
370  case 0xAE:
371  case 0xAF:
372  ports[port] &= 63; // so we don't need to do this AND again and again ...
373  break;
374  }
375 }
kbd_selector
int kbd_selector
Definition: dave.c:35
primoemu.h
emutools.h
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
is_audio_emulation_active
int is_audio_emulation_active(void)
Definition: dave.c:117
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
AUDIO_BUFFER_SIZE
#define AUDIO_BUFFER_SIZE
Definition: dave.c:46
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
printer.h
dave_tick
void dave_tick(void)
Definition: dave.c:254
dave_reset
void dave_reset(void)
Definition: dave.c:206
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
cpu.h
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
dave.h
printer_disable_covox
void printer_disable_covox(void)
Definition: printer.c:136
dave_int1
void dave_int1(int level)
Definition: dave.c:227
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
emutools_hid.h
cpu_cycles_per_dave_tick
int cpu_cycles_per_dave_tick
Definition: dave.c:36
enterprise128.h
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
mem_wait_states
int mem_wait_states
Definition: dave.c:37
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