Mercurial > repos > blastem
comparison lc8951.c @ 2058:70260f6051dd segacd
Initial work on CDC emulation
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 21 Jan 2022 20:24:48 -0800 |
parents | |
children | 07ed42bd7b4c |
comparison
equal
deleted
inserted
replaced
2057:88deea42caf0 | 2058:70260f6051dd |
---|---|
1 #include "lc8951.h" | |
2 | |
3 enum { | |
4 COMIN, | |
5 IFSTAT, | |
6 DBCL, | |
7 DBCH, | |
8 HEAD0, | |
9 HEAD1, | |
10 HEAD2, | |
11 HEAD3, | |
12 PTL, | |
13 PTH, | |
14 WAL, | |
15 WAH, | |
16 STAT0, | |
17 STAT1, | |
18 STAT2, | |
19 STAT3, | |
20 | |
21 SBOUT = COMIN, | |
22 IFCTRL = IFSTAT, | |
23 DACL = HEAD0, | |
24 DACH = HEAD1, | |
25 DTTRG = HEAD2, | |
26 DTACK = HEAD3, | |
27 WAL_WRITE = PTL, | |
28 WAH_WRITE = PTH, | |
29 CTRL0 = WAL, | |
30 CTRL1 = WAH, | |
31 PTL_WRITE = STAT0, | |
32 PTH_WRITE = STAT1, | |
33 RESET = STAT3 | |
34 }; | |
35 | |
36 //IFCTRL | |
37 #define BIT_CMDIEN 0x80 | |
38 #define BIT_DTEIEN 0x40 | |
39 #define BIT_CECIEN 0x20 | |
40 #define BIT_CMDBK 0x10 | |
41 #define BIT_DTWAI 0x08 | |
42 #define BIT_STWAI 0x04 | |
43 #define BIT_DOUTEN 0x02 | |
44 #define BIT_SOUTEN 0x01 | |
45 | |
46 //IFSTAT | |
47 #define BIT_CMDI 0x80 | |
48 #define BIT_DTEI 0x40 | |
49 #define BIT_DECI 0x20 | |
50 #define BIT_DTBSY 0x08 | |
51 #define BIT_STBSY 0x04 | |
52 #define BIT_DTEN 0x02 | |
53 #define BIT_STEN 0x01 | |
54 | |
55 //datasheet timing info | |
56 //3 cycles for memory operation | |
57 //6 cycles min for DMA-mode host transfer | |
58 | |
59 void lc8951_init(lc8951 *context) | |
60 { | |
61 //This seems to vary somewhat between Sega CD models | |
62 //unclear if the difference is in the lc8951 or gate array | |
63 context->regs[IFSTAT] = 0xFF; | |
64 context->ar_mask = 0x1F; | |
65 } | |
66 | |
67 void lc8951_reg_write(lc8951 *context, uint8_t value) | |
68 { | |
69 switch (context->ar) | |
70 { | |
71 case SBOUT: | |
72 context->regs[context->ar] = value; | |
73 if (context->ifctrl & BIT_SOUTEN) { | |
74 context->regs[IFSTAT] &= ~BIT_STBSY; | |
75 } | |
76 break; | |
77 case IFCTRL: | |
78 context->ifctrl = value; | |
79 if (!(value & BIT_SOUTEN)) { | |
80 context->regs[IFSTAT] |= BIT_STBSY; | |
81 } | |
82 if (!(value & BIT_DOUTEN)) { | |
83 context->regs[IFSTAT] |= BIT_DTBSY; | |
84 } | |
85 break; | |
86 case DBCL: | |
87 context->regs[context->ar] = value; | |
88 break; | |
89 case DBCH: | |
90 context->regs[context->ar] = value & 0xF; | |
91 break; | |
92 case DACL: | |
93 context->dac &= 0xFF00; | |
94 context->dac |= value; | |
95 break; | |
96 case DACH: | |
97 context->dac &= 0xFF; | |
98 context->dac |= value << 8; | |
99 break; | |
100 case DTTRG: | |
101 if (value & BIT_DOUTEN) { | |
102 context->regs[IFSTAT] &= ~BIT_DTBSY; | |
103 } | |
104 break; | |
105 case DTACK: | |
106 context->regs[IFSTAT] |= BIT_DTEI; | |
107 break; | |
108 case WAL_WRITE: | |
109 context->regs[WAL] = value; | |
110 break; | |
111 case WAH_WRITE: | |
112 context->regs[WAH] = value; | |
113 break; | |
114 case PTL_WRITE: | |
115 context->regs[PTL] = value; | |
116 break; | |
117 case PTH_WRITE: | |
118 context->regs[PTH] = value; | |
119 break; | |
120 case RESET: | |
121 context->comin_count = 0; | |
122 context->regs[IFSTAT] = 0xFF; | |
123 break; | |
124 default: | |
125 break; | |
126 } | |
127 if (context->ar != SBOUT) { | |
128 context->ar++; | |
129 context->ar &= context->ar_mask; | |
130 } | |
131 } | |
132 | |
133 uint8_t lc8951_reg_read(lc8951 *context) | |
134 { | |
135 uint8_t value; | |
136 if (context->ar == COMIN) { | |
137 if (!context->comin_count) { | |
138 return 0xFF; | |
139 } | |
140 value = context->comin[(context->comin_write - context->comin_count)&sizeof(context->comin)]; | |
141 context->comin_count--; | |
142 if (!context->comin_count) { | |
143 context->regs[IFSTAT] |= BIT_CMDI; | |
144 } | |
145 return value; | |
146 } | |
147 if (context->ar == STAT3) { | |
148 context->regs[IFSTAT] |= BIT_DECI; | |
149 } | |
150 if (context->ar >= sizeof(context->regs)) { | |
151 value = 0xFF; | |
152 } else { | |
153 value = context->regs[context->ar]; | |
154 } | |
155 context->ar++; | |
156 context->ar &= context->ar_mask; | |
157 return value; | |
158 } | |
159 | |
160 void lc8951_ar_write(lc8951 *context, uint8_t value) | |
161 { | |
162 context->ar = value & context->ar_mask; | |
163 } |