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 }