-
Notifications
You must be signed in to change notification settings - Fork 4
/
clem_mmio_types.h
560 lines (482 loc) · 19.1 KB
/
clem_mmio_types.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
#ifndef CLEM_MMIO_TYPES_H
#define CLEM_MMIO_TYPES_H
#include "clem_shared.h"
#include "clem_types.h"
#include "clem_disk.h"
#include "clem_mmio_defs.h"
#include "clem_smartport.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Real time clock device and BRAM interface
*
*/
struct ClemensDeviceRTC {
clem_clocks_time_t xfer_started_time;
clem_clocks_duration_t xfer_latency_duration;
unsigned state;
unsigned index;
unsigned flags;
unsigned seconds_since_1904;
uint8_t bram[CLEM_RTC_BRAM_SIZE];
/* these values are set by the app */
uint8_t data_c033;
uint8_t ctl_c034;
};
/**
* These are internal data structions for the ADB - do not maniuplate manually
* unless you know what you're doing or input state may be corrupted!
*/
struct ClemensDeviceKeyboard {
uint8_t keys[CLEM_ADB_KEYB_BUFFER_LIMIT];
uint8_t states[CLEM_ADB_KEY_CODE_LIMIT]; // should be ascii, so 128
int size;
int delay_ms;
int rate_per_sec;
int timer_us;
int repeat_count;
uint8_t last_a2_key_down;
bool reset_key;
bool repeat_key_mod;
};
struct ClemensDeviceMouse {
unsigned pos[CLEM_ADB_KEYB_BUFFER_LIMIT];
int16_t mx, my; /**< Only valid if tracking mode enabled - current values */
int16_t mx0, my0; /**< Only valid if tracking mode enabled - last tracked values */
int size;
bool btn_down;
bool tracking_enabled; /**< Absolute mouse position/tracking mode enabled*/
bool valid_clamp_box; /**< Determine every VBL based on toolbox variables */
};
struct ClemensDeviceGameport {
clem_clocks_time_t ts_last_frame;
/* value is from 0 to CLEM_GAMEPORT_PADDLE_AXIS_VALUE_MAX or at UINT_MAX if
the value is not set by the host per frame. */
uint16_t paddle[4];
/* on PTRIG, paddle_timer[x] takes on the time value calculated from the
input paddle value (if the paddle value is at UINT_MAX per above, then
paddle_timer[x] == 0, which becomes a no-op during the sync()). Otherwise
every frame the timer value is decremented and when reaching 0, flips the
paddle high bit off at PADDLn */
uint32_t paddle_timer_ns[4];
/* C064...C067 bit 7 maps to items 0 - 4. */
uint8_t paddle_timer_state[4];
uint8_t btn_mask[2];
uint8_t ann_mask;
};
struct ClemensDeviceClipboard {
unsigned tail;
unsigned char keys[CLEM_ADB_CLIPBOARD_BUFFER_LIMIT];
};
struct ClemensDeviceADB {
unsigned state;
unsigned version; /* Different ROMs expect different versions */
unsigned poll_timer_us; /* 60 hz timer (machine time) */
unsigned mode_flags; /* ADB modes */
bool is_keypad_down; /* Used to determine keypad modifier status */
bool is_asciikey_down; /* Used to determine c010 anykey down status */
uint8_t io_key_last_ascii; /* The last ascii key pressed, bit 7 strobe */
/* Host-GLU registers */
uint16_t keyb_reg[4]; /**< mocked GLU keyboard registers */
uint16_t mouse_reg[4]; /**< mocked GLU mouse registers */
uint8_t cmd_reg; /**< command type */
uint8_t cmd_flags; /**< meant to reflect C026 when not data */
uint8_t cmd_status; /**< meant to approximately reflect C027 */
uint8_t cmd_data_limit; /**< expected cnt of bytes for send/recv */
uint8_t cmd_data_sent; /**< current index into cmd_data sent 2-way */
uint8_t cmd_data_recv; /**< current index into cmd_data recv 2-way */
uint8_t cmd_data[16]; /**< command data */
struct ClemensDeviceKeyboard keyb;
struct ClemensDeviceMouse mouse;
struct ClemensDeviceGameport gameport;
struct ClemensDeviceClipboard clipboard;
uint8_t ram[256]; /**< Microcontroller RAM */
uint32_t irq_dispatch; /* IRQ should be dispatched next sync */
uint32_t irq_line; /**< IRQ flags passed to machine */
};
struct ClemensDeviceSCCChannel {
unsigned serial_port;
/** Register set */
uint8_t regs[16];
uint8_t rr0, rr1;
uint8_t rr3, rr8;
uint8_t selected_reg;
uint8_t txd_internal; /* Used for loopback*/
uint8_t rxd_error; /* Tracks received byte and acts as the error byte */
uint8_t pad;
/** Applies clock mode (/1, /16, /32, /64) to calculate the master step and edges. */
clem_clocks_time_t master_clock_ts;
clem_clocks_time_t xtal_edge_ts;
clem_clocks_time_t pclk_edge_ts;
clem_clocks_duration_t master_clock_step;
/** Data buffers - FIFO queues that mimic the Z8530 recv/xmit buffers */
uint8_t recv_queue[CLEM_SCC_RECV_QUEUE_SIZE];
uint8_t recv_err_queue[CLEM_SCC_RECV_QUEUE_SIZE];
uint8_t tx_byte;
uint8_t rx_condition; /* Special Receive Condition */
uint32_t tx_register;
uint32_t tx_shift_ctr;
uint32_t rx_queue_pos;
uint32_t rx_shift_ctr;
uint32_t rx_register;
uint32_t brg_counter; /* Bit 31 = high bit is the flip-flop state*/
unsigned state;
};
struct ClemensDeviceSCC {
/** Clocks, including the XTAL oscillator @ 3.6864 mhz, CREF is defined in
clem_shared.h */
clem_clocks_duration_t xtal_step;
clem_clocks_duration_t pclk_step;
struct ClemensDeviceSCCChannel channel[2];
uint32_t irq_line; /**< IRQ flags passed to machine */
};
/**
* @brief This buffer is supplied by the host and represents a complete
* 16-bit stereo PCM buffer
*
* This buffer is written to by the clemens machine, and consumed by the host
* as input to the audio device's playback buffer.
*
*/
struct ClemensAudioMixBuffer {
uint8_t *data;
unsigned stride;
unsigned frame_count;
unsigned frames_per_second; /**< target audio frequency */
};
struct ClemensDeviceEnsoniq {
/** Clocks budget for oscillator sync */
clem_clocks_duration_t dt_budget;
/** cycle counter with 1 cycle per oscillator */
unsigned cycle;
/** PCM output (floating point per channel) */
float voice[16];
uint8_t sound_ram[65536];
uint8_t reg[256]; /**< DOC register values */
unsigned acc[32]; /**< Oscillator running accumulator */
uint16_t ptr[32]; /**< Stored pointer from last cycle */
uint8_t osc_flags[32]; /**< Oscillator table (Interrupts) */
uint8_t osc_stack[32]; /**< Oscillator completion / interrupt stack */
unsigned address; /**< 16-bit address into RAM or registers */
uint8_t data_reg; /**< For read operations on RAM, accounts for the 1 read op lag, */
bool addr_auto_inc; /**< Address auto incremented on access */
bool is_access_ram; /**< If true, sound RAM, if false, registers */
bool is_busy; /**< DOC busy */
};
struct ClemensDeviceAudio {
struct ClemensDeviceEnsoniq doc;
/* settings */
uint8_t volume; /**< 0 - 15 */
bool a2_speaker; /**< the c030 switch */
bool a2_speaker_tense; /**< the a2 speaker state tense, relax */
int32_t a2_speaker_frame_count;
int32_t a2_speaker_frame_threshold;
float a2_speaker_level;
/* host supplied mix buffer */
struct ClemensAudioMixBuffer mix_buffer;
clem_clocks_time_t ts_last_frame;
clem_clocks_duration_t dt_mix_frame;
clem_clocks_duration_t dt_mix_sample;
unsigned mix_frame_index;
/* test code */
float tone_frame_delta;
float tone_theta;
unsigned tone_frequency;
/* the device's IRQ line */
uint32_t irq_line;
#if CLEM_AUDIO_DIAGNOSTICS
unsigned diag_dt_ns;
unsigned diag_delta_frames;
clem_clocks_duration_t diag_dt;
#endif
};
/** Really, this is part of the RTC/VGC, but for separation of concerns,
* pulling out into its own component
*/
struct ClemensDeviceTimer {
uint32_t irq_1sec_us; /**< used to trigger IRQ one sec */
uint32_t irq_qtrsec_us; /**< used to trigger IRQ quarter sec */
uint32_t flags; /**< interrupt */
uint32_t irq_line; /**< IRQ flags passed to machine */
};
/**
* @brief Identifies the input event sent to the ADB controller
*
*/
enum ClemensInputType {
kClemensInputType_None, /**< No input */
kClemensInputType_KeyDown, /**< Key was pressed */
kClemensInputType_KeyUp, /**< Key was released */
kClemensInputType_MouseButtonDown, /**< Mouse button was pressed */
kClemensInputType_MouseButtonUp, /**< Mouse button was released */
kClemensInputType_MouseMove, /**< Mouse relative motion (deltas) */
kClemensInputType_MouseMoveAbsolute, /**< Mouse absolution position (screen) */
kClemensInputType_Paddle, /**< Paddle input (connected) */
kClemensInputType_PaddleDisconnected /**< Paddle disconnected from system */
};
/**
* @brief Consolidated input structure passed into the emulator
*
* Input is dispatched to the ADB device, which then provides input data to
* the ClemensMachine
*
*/
struct ClemensInputEvent {
enum ClemensInputType type;
/* Value based on the input type (ADB keycode, mouse or gamepad button.)
Mouse pointer deltas as reported by host scaled for the ADB. These are
in the range of +- 64 and are packed into the value (upper + lower 16 bits
for Y and X respectively.)
Gameport values for each paddle are stored as X = value_a, Y = value_b
Forward two joystick input by toggling the gameport_button_mask with
CLEM_GAMEPORT_BUTTON_MASK_JOYSTICK_0 or CLEM_GAMEPORT_BUTTON_MASK_JOYSTICK_1
*/
int16_t value_a;
int16_t value_b;
/* Key toggle mask */
union {
unsigned adb_key_toggle_mask;
unsigned gameport_button_mask;
};
};
/**
* @brief Each scanline contains offsets into different bank memory regions
*
*/
struct ClemensScanline {
unsigned offset;
unsigned control; /**< Used for IIgs scanline control */
};
struct ClemensVGC {
struct ClemensScanline text_1_scanlines[CLEM_VGC_TEXT_SCANLINE_COUNT];
struct ClemensScanline text_2_scanlines[CLEM_VGC_TEXT_SCANLINE_COUNT];
struct ClemensScanline hgr_1_scanlines[CLEM_VGC_HGR_SCANLINE_COUNT];
struct ClemensScanline hgr_2_scanlines[CLEM_VGC_HGR_SCANLINE_COUNT];
struct ClemensScanline shgr_scanlines[CLEM_VGC_SHGR_SCANLINE_COUNT];
/* bgr- (4:4:4) bits 0 - 11 */
uint16_t shgr_palettes[16 * CLEM_VGC_SHGR_SCANLINE_COUNT];
/* Used for timing of vertical blank and scanline irqs */
clem_clocks_time_t ts_last_frame;
clem_clocks_duration_t dt_scanline;
unsigned vbl_counter;
unsigned v_counter;
/* amalgom of possible display modes */
unsigned mode_flags;
unsigned text_fg_color;
unsigned text_bg_color;
unsigned text_language;
bool scanline_irq_enable;
bool vbl_started; /**< Limits VBL IRQ */
bool irq_vbl; /**< Used for C046 INTFLAG and cleared via C047 CLRVBLINT */
uint32_t irq_line; /**< IRQ flags passed to machine */
};
/**
* IWM emulation of c0x0-c0xf for IWM devices. Note that the IWM can only
* access one drive at a time (in tandem with the disk interface register)
*
* 1 Q3 period = 7 clock ticks (2mhz)
*/
struct ClemensDeviceIWM {
/** A reference clocks value at the last disk update. */
clem_clocks_time_t cur_clocks_ts;
/** Q3 clock accounting for PHI0 stretch cycle */
clem_clocks_time_t clocks_at_next_scanline;
/** Budget for a cycle from the prior frame */
clem_clocks_duration_t clocks_used_this_step;
clem_clocks_duration_t clocks_this_step;
unsigned scanline_phase_ctr; // 0 = non stretch, 1 = stretch
/** Used for determining if applications are actually using the IWM for RW disk access*/
uint32_t data_access_time_ns;
/** Drive I/O */
unsigned io_flags; /**< Disk port I/O flags */
unsigned out_phase; /**< PH0-PH3 bits sent to drive */
bool smartport_active; /**< SmartPort bus is active */
/** Internal Registers */
uint8_t data_r; /**< Read data register */
uint8_t data_w; /**< Write data register */
uint8_t latch; /**< data latch (work register for IWM) */
uint8_t disk_motor_on; /**< bits 0-3 represent ports 4-7 */
bool q6_switch; /**< Q6 state switch */
bool q7_switch; /**< Q7 stage switch */
bool timer_1sec_disabled; /**< Turn motor off immediately */
bool async_mode; /**< Asynchronous handshake mode */
bool latch_mode; /**< If True, latch value lasts for full 8 xfer */
bool fast_mode; /**< If True, 2us bit cells */
unsigned drive_hold_ns; /**< Time until drive motor off */
unsigned state; /**< The current IWM register state */
unsigned write_state; /**< Defines the state of the data_w and latch */
unsigned read_state; /**< Defines the state of the data_r and latch */
unsigned ns_latch_hold; /**< The latch value expiration timer */
/** Not to be serialized - just for debugging. */
bool enable_debug; /**< If True, activates file logging */
int debug_level; /**< 3 = the most/debug, 2 is detailed */
};
/* ClemensDrive Data
*/
struct ClemensWOZDisk;
struct Clemens2IMGDisk;
/**
* @brief
*
*/
struct ClemensDrive {
struct ClemensNibbleDisk disk; /**< Disk Nibble Data */
// TODO: Move the below to the host - we only care about nibblized data
// here
int qtr_track_index; /**< Current track position of the head */
unsigned track_byte_index; /**< byte index into track */
unsigned track_bit_shift; /**< bit offset into current byte */
unsigned track_bit_length; /**< current track bit length */
clem_clocks_duration_t pulse_clocks_dt; /**< TODO: remove, NOT USED ANYMORE */
unsigned read_buffer; /**< Used for MC3470 emulation */
/**
* 4-bit Q0-3 entry 5.25" = stepper control
* Control/Status/Strobe bits for 3.5"
*/
unsigned ctl_switch;
unsigned cog_orient; /**< emulated orientation of stepper cog */
clem_clocks_duration_t step_timer_35_dt; /**< 3.5" track step timer */
uint16_t status_mask_35; /**< 3.5" status mask */
bool write_pulse; /**< Changes in the write field translate as pulses */
bool is_spindle_on; /**< Drive spindle running */
bool has_disk; /**< Has a disk in the drive */
uint8_t real_track_index; /**< the index into the raw woz track data */
/** used for random pulse generation */
uint8_t random_bits[CLEM_IWM_DRIVE_RANDOM_BYTES];
unsigned random_bit_index;
uint8_t current_byte;
};
struct ClemensDriveBay {
struct ClemensDrive slot5[2];
struct ClemensDrive slot6[2];
struct ClemensSmartPortUnit smartport[CLEM_SMARTPORT_DRIVE_LIMIT];
};
struct ClemensDeviceMega2Memory {
uint8_t *e0_bank;
uint8_t *e1_bank;
};
/**
* @brief Reflects the CPU state on the MMIO
*
*/
enum ClemensMMIOStateType {
kClemensMMIOStateType_None,
kClemensMMIOStateType_Reset,
kClemensMMIOStateType_Active
};
/**
* @brief FPI + MEGA2 MMIO Interface
*
*/
typedef struct ClemensMMIO {
/** Handlers for all slots */
ClemensCard *card_slot[CLEM_CARD_SLOT_COUNT];
/** Expansion ROM area for each card. This area is paged into addressable
* memory with the correct IO instructions. Each area should be 2K in
* size. As with card slot memory, slot 3 is ignored */
uint8_t *card_slot_expansion_memory[CLEM_CARD_SLOT_COUNT];
/* Page maps are always generated; never serialized/unserialized */
/* pointer to the array of bank page map pointers initialized by the
parent machine
*/
struct ClemensMemoryPageMap **bank_page_map;
/* The different page mapping types */
struct ClemensMemoryPageMap fpi_direct_page_map;
struct ClemensMemoryPageMap fpi_main_page_map;
struct ClemensMemoryPageMap fpi_aux_page_map;
struct ClemensMemoryPageMap fpi_rom_page_map;
struct ClemensMemoryPageMap mega2_main_page_map;
struct ClemensMemoryPageMap mega2_aux_page_map;
struct ClemensMemoryPageMap empty_page_map;
/* Shadow maps for bank 00, 01 */
struct ClemensMemoryShadowMap fpi_mega2_main_shadow_map;
struct ClemensMemoryShadowMap fpi_mega2_aux_shadow_map;
/* Reflected mega2 memory used for MMIO operations that require such access:
i.e. floating bus data retrieval
*/
uint8_t *e0_bank;
uint8_t *e1_bank;
/* end non-serialized attribute block */
/* All devices */
struct ClemensDeviceDebugger *dev_debug;
struct ClemensVGC vgc;
struct ClemensDeviceRTC dev_rtc;
struct ClemensDeviceADB dev_adb;
struct ClemensDeviceTimer dev_timer;
struct ClemensDeviceAudio dev_audio;
struct ClemensDeviceIWM dev_iwm;
struct ClemensDeviceSCC dev_scc;
/* Peripherals */
struct ClemensDriveBay active_drives;
/* Registers that do not fall easily within a device struct */
enum ClemensMMIOStateType state_type;
uint32_t fpi_ram_bank_count;
uint32_t fpi_rom_bank_count;
uint32_t mmap_register; // memory map flags- CLEM_MEM_IO_MMAP_
uint32_t last_data_address; // used for c08x switches
uint32_t emulator_detect; // used for the c04f emulator test (state)
uint8_t new_video_c029; // see kClemensMMIONewVideo_xxx
uint8_t speed_c036; // see kClemensMMIOSpeed_xxx
uint64_t mega2_cycles; // number of mega2 pulses/ticks since startup
uint32_t timer_60hz_us; // used for executing logic per 1/60th second
int32_t card_expansion_rom_index; // card slot has the mutex on C800-CFFF
/* All ticks are mega2 cycles */
uint32_t irq_line; // see CLEM_IRQ_XXX flags, if !=0 triggers irqb
uint32_t nmi_line; // see ClEM_NMI_XXX flags
} ClemensMMIO;
/**
* @brief
*
*/
enum ClemensVideoFormat {
kClemensVideoFormat_None,
kClemensVideoFormat_Text,
kClemensVideoFormat_Lores,
kClemensVideoFormat_Hires,
kClemensVideoFormat_Double_Lores,
kClemensVideoFormat_Double_Hires,
kClemensVideoFormat_Super_Hires
};
/**
* @brief
*
*/
typedef struct {
struct ClemensScanline *scanlines;
int scanline_byte_cnt;
int scanline_start;
int scanline_count;
int scanline_limit;
enum ClemensVideoFormat format;
unsigned vbl_counter;
/** Pointer to 200 scanlines of 16 colors (4:4:4) each = 3200 * 2 bytes. RGB word
where bits 0-3 are blue, 4-7 are green and 8-11 are red. This pointer is
owned by the internal VGC data structure and remains valid until the next call to
clemens_emulate_cpu(). */
uint16_t *rgb;
unsigned rgb_buffer_size;
/** These values can be used by hosts to handle specific video situations like
* mouse pointer tracking
*/
bool has_640_mode_scanlines;
} ClemensVideo;
typedef struct {
unsigned int signal; /**< See CLEM_MONITOR_xxx */
unsigned int color; /**< See CLEM_MONITOR_xxx */
unsigned width;
unsigned height;
unsigned border_color; /**< See CLEM_VGC_COLOR_xxx */
unsigned text_color; /**< bits 0-3 = foreground, 4-7 = background */
} ClemensMonitor;
typedef struct {
uint8_t *data; /** format will always by 32-bit float stereo */
unsigned frame_total; /** total number of frames in the buffer */
unsigned frame_start; /** --frame-- index into the data buffer */
unsigned frame_count; /** --frame-- count (this can wrap around) */
unsigned frame_stride; /** each frame is this size */
} ClemensAudio;
#ifdef __cplusplus
}
#endif
#endif