Mercurial > repos > blastem
comparison ym2612.c @ 288:a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 05 May 2013 22:56:42 -0700 |
parents | |
children | cc39629e8d06 |
comparison
equal
deleted
inserted
replaced
287:fb840e0a48cd | 288:a8ee7934a1f8 |
---|---|
1 #include <string.h> | |
2 #include "ym2612.h" | |
3 | |
4 #define BUSY_CYCLES 17 | |
5 #define TIMERA_UPDATE_PERIOD 144 | |
6 | |
7 #define REG_TIMERA_HIGH 0x3 // 0x24 | |
8 #define REG_TIMERA_LOW 0x4 // 0x25 | |
9 #define REG_TIMERB 0x5 // 0x26 | |
10 #define REG_TIME_CTRL 0x6 // 0x27 | |
11 | |
12 #define BIT_TIMERA_ENABLE 0x1 | |
13 #define BIT_TIMERB_ENABLE 0x2 | |
14 #define BIT_TIMERA_OVEREN 0x4 | |
15 #define BIT_TIMERB_OVEREN 0x8 | |
16 #define BIT_TIMERA_RESET 0x10 | |
17 #define BIT_TIMERB_RESET 0x20 | |
18 | |
19 #define BIT_STATUS_TIMERA 0x1 | |
20 #define BIT_STATUS_TIMERB 0x2 | |
21 | |
22 void ym_init(ym2612_context * context) | |
23 { | |
24 memset(context, 0, sizeof(*context)); | |
25 } | |
26 | |
27 void ym_run(ym2612_context * context, uint32_t to_cycle) | |
28 { | |
29 uint32_t delta = to_cycle - context->current_cycle; | |
30 //Timers won't be perfect with this, but it's good enough for now | |
31 //once actual FM emulation is in place the timers should just be | |
32 //decremented/reloaded on the appropriate ticks | |
33 uint32_t timer_delta = to_cycle / TIMERA_UPDATE_PERIOD; | |
34 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_ENABLE) { | |
35 if (timer_delta > context->timer_a) { | |
36 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_OVEREN) { | |
37 context->status |= BIT_STATUS_TIMERA; | |
38 } | |
39 uint32_t rem_delta = timer_delta - (context->timer_a+1); | |
40 uint16_t timer_val = (context->part1_regs[REG_TIMERA_HIGH] << 2) | (context->part1_regs[REG_TIMERA_LOW] & 0x3); | |
41 context->timer_a = timer_val - (rem_delta % (timer_val + 1)); | |
42 } else { | |
43 context->timer_a -= timer_delta; | |
44 } | |
45 } | |
46 timer_delta /= 16; //Timer B runs at 1/16th the speed of Timer A | |
47 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_ENABLE) { | |
48 if (timer_delta > context->timer_b) { | |
49 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_OVEREN) { | |
50 context->status |= BIT_STATUS_TIMERB; | |
51 } | |
52 uint32_t rem_delta = timer_delta - (context->timer_b+1); | |
53 uint8_t timer_val = context->part1_regs[REG_TIMERB]; | |
54 context->timer_b = timer_val - (rem_delta % (timer_val + 1)); | |
55 } else { | |
56 context->timer_a -= timer_delta; | |
57 } | |
58 } | |
59 context->current_cycle = to_cycle; | |
60 if (to_cycle >= context->write_cycle + BUSY_CYCLES) { | |
61 context->status &= 0x7F; | |
62 } | |
63 } | |
64 | |
65 void ym_address_write_part1(ym2612_context * context, uint8_t address) | |
66 { | |
67 if (address >= 0x21 && address < 0xB7) { | |
68 context->selected_reg = context->part1_regs + address - 0x21; | |
69 } else { | |
70 context->selected_reg = NULL; | |
71 } | |
72 } | |
73 | |
74 void ym_address_write_part2(ym2612_context * context, uint8_t address) | |
75 { | |
76 if (address >= 0x30 && address < 0xB7) { | |
77 context->selected_reg = context->part1_regs + address - 0x30; | |
78 } else { | |
79 context->selected_reg = NULL; | |
80 } | |
81 } | |
82 | |
83 void ym_data_write(ym2612_context * context, uint8_t value) | |
84 { | |
85 if (context->selected_reg && !(context->status & 0x80)) { | |
86 *context->selected_reg = value; | |
87 context->write_cycle = context->current_cycle; | |
88 context->selected_reg = NULL;//TODO: Verify this | |
89 } | |
90 } | |
91 | |
92 uint8_t ym_read_status(ym2612_context * context) | |
93 { | |
94 return context->status; | |
95 } | |
96 |