1 // license:BSD-3-Clause
2 // copyright-holders:David Viens
3 /***************************************************************************
4
5 gic.c
6
7 GI AY-3-8800-1 (Datasheet exists as AY-3-8500-1 Graphics Interface Chip)
8 For the GIMINI "Challenger" programmable game system.
9
10 Really only ever used in the Unisonic Champion 2711
11
12 More LA tests made by plgDavid on hardware pretty much confirmed what is found
13 in the AY-3-8950-1 datasheet, but with more fine grained detail.
14
15 the GIC does not have internal ram of any sort apart from shift registers,
16 instead it relies on the external shared ram, (see page 7-85) Appendix AY-3-8950-1
17
18 Unverified on LA (since the video pins are all connected into a composite mix):
19 at line 46 it lowers GIC_BUSY, until line 240
20
21 Verified using LA:
22 It will read the external ram areas continuously while GIC_BUSY is low (for 12.36ms)
23
24 (NOTE: OCTAL)
25
26 000,001,002,003,004,005, 110,111,112,113,114,115,116,117,120,121,122,123,124,125 (15 times - No first bg line?)
27 006,007,010,011,012,013, 110,111,112,113,114,115,116,117,120,121,122,123,124,125 (16 times)
28
29 014,015,016,017,020,021, 125,126,127,130,131,132,133,134,135,136,137,140,141,142 (16 times)
30 022,023,024,025,026,027, 125,126,127,130,131,132,133,134,135,136,137,140,141,142 (16 times)
31
32 030,031,032,033,034,035, 142,143,144,145,146,147,150,151,152,153,154,155,156,157 (16 times)
33 036,037,040,041,042,043, 142,143,144,145,146,147,150,151,152,153,154,155,156,157 (16 times)
34
35 044,045,046,047,050,051, 157,160,161,162,163,164,165,166,167,170,171,172,173,174 (16 times)
36 052,053,054,055,056,057, 157,160,161,162,163,164,165,166,167,170,171,172,173,174 (16 times)
37
38 060,061,062,063,064,065, 174,175,176,177,200,201,202,203,204,205,206,207,210,211 (16 times)
39 066,067,070,071,072,073, 174,175,176,177,200,201,202,203,204,205,206,207,210,211 (16 times)
40
41 074,075,076,077,100,101, 211,212,213,214,215,216,217,220,221,222,223,224,225,226 (16 times)
42 102,103,104,105,106,107, 211,212,213,214,215,216,217,220,221,222,223,224,225,226 (16 times)
43
44 000,001,002,003,004,005, 000,001,002,003,004,005,006,007,010,011,012,013,014,015 (once! padding?)
45
46 for a total of (12*20*16) = 3840 RAM reads (3 clocks per read at 1.79MHz)
47
48 Then it relinquishes control to the CPU by raising BUSREQ.
49
50 Clocking in more detail: (in 1.79MHz clocks)
51 boot:
52 busy:1 5360 clocks
53 busy:0 22116 clocks
54 busy:1 7752 clocks
55 busy:0 22116 clocks
56 busy:1 7752 clocks
57 (...)
58
59 There are NO IRQ handshakes, just BUSREQ sync shared RAM
60
61 ***************************************************************************/
62
63 #include "emu.h"
64 #include "gic.h"
65 #include "screen.h"
66
67 // device type definition
68 DEFINE_DEVICE_TYPE(GIC, gic_device, "gic", "AY-3-8800-1 GIC")
69
70
71 //Font data taken from Paul Robson's simulator
72 //http://worstconsole.blogspot.ca/2012/12/the-worstconsoleever.html
73 //A real AY-3-8800-1 (dead) is going to decap for a good dump
ROM_START(gic_font)74 ROM_START( gic_font )
75 ROM_REGION( 0x200, "cgrom", 0 )
76 ROM_LOAD( "ay-3-8800-1.bin", 0x0000, 0x200, BAD_DUMP CRC(d9f11d2b) SHA1(60ef45d51d102cd3af78787008d9aed848137bee))
77 ROM_END
78
79
80 //-------------------------------------------------
81 // gic_device - constructor
82 //-------------------------------------------------
83
84 gic_device::gic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
85 : gic_device(mconfig, GIC, tag, owner, clock)
86 {
87 }
88
89
gic_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)90 gic_device::gic_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
91 : device_t(mconfig, type, tag, owner, clock)
92 , device_sound_interface(mconfig, *this)
93 , device_video_interface(mconfig, *this)
94 , m_cgrom(*this, "cgrom")
95 , m_audiocnt(0)
96 , m_audioval(0)
97 , m_audioreset(0)
98 , m_ram(*this)
99 {
100 }
101
device_rom_region() const102 const tiny_rom_entry *gic_device::device_rom_region() const
103 {
104 //there is only one... how do I get rid of this?
105 return ROM_NAME( gic_font );
106 }
107
108 //-------------------------------------------------
109 // device_start - device-specific startup
110 //-------------------------------------------------
111
device_start()112 void gic_device::device_start()
113 {
114 // Let the screen create our temporary bitmap with the screen's dimensions
115 screen().register_screen_bitmap(m_bitmap);
116
117 m_vblank_timer = timer_alloc(TIMER_VBLANK);
118 m_vblank_timer->adjust( screen().time_until_pos(1, END_ACTIVE_SCAN + 18 ), 0, screen().scan_period() );
119
120 // allocate the audio stream
121 m_stream = stream_alloc( 0, 1, clock()/(2*228) );
122
123 m_ram.resolve_safe(0xff);
124 }
125
126
127 //-------------------------------------------------
128 // device_reset - device-specific reset
129 //-------------------------------------------------
130
device_reset()131 void gic_device::device_reset()
132 {
133 m_audiocnt=0;
134 m_audioval=0;
135 m_audioreset=0;
136 }
137
138 #define GIC_CLUB 28
139 #define GIC_SPACE 0
140
draw_char_left(int startx,int starty,uint8_t code,bitmap_ind16 & bitmap)141 void gic_device::draw_char_left(int startx, int starty, uint8_t code, bitmap_ind16 &bitmap){
142 uint8_t*ptr = &m_cgrom[code*GIC_CHAR_H];
143
144 for (size_t y=0;y<GIC_CHAR_H;y++){
145 uint8_t current = *ptr++;
146 uint8_t nextx=0;
147 uint8_t curry= starty+y;
148 for(uint8_t x=0x20;x!=0;x=x/2){
149 if (current&x)
150 m_bitmap.pix(curry,startx+nextx) = GIC_WHITE;
151 nextx++;
152 }
153 }
154 }
155
draw_char_right(int startx,int starty,uint8_t code,bitmap_ind16 & bitmap,int bg_col)156 void gic_device::draw_char_right(int startx, int starty, uint8_t code, bitmap_ind16 &bitmap, int bg_col){
157 uint8_t*ptr = &m_cgrom[code*GIC_CHAR_H];
158
159 for (size_t y=0;y<GIC_CHAR_H;y++){
160 uint8_t current = *ptr++;
161 uint8_t nextx=0;
162 uint8_t curry= starty+y;
163
164 m_bitmap.pix(curry,startx+nextx) = bg_col;
165 nextx++;
166 for(uint8_t x=0x20;x!=0;x=x/2){
167 m_bitmap.pix(curry,startx+nextx) = (current&x)?GIC_WHITE:bg_col;
168 nextx++;
169 }
170 m_bitmap.pix(curry,startx+nextx) = bg_col;
171 nextx++;
172 m_bitmap.pix(curry,startx+nextx) = bg_col;
173 }
174 }
175
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)176 uint32_t gic_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
177 {
178 m_bitmap.fill(GIC_GREEN);
179
180 size_t XSTART = BORDER_SIZE;
181 size_t YSTART = START_ACTIVE_SCAN;
182
183 //left hand side first
184 uint8_t current=0;
185 for(uint8_t cy=0;cy<GIC_LEFT_H;cy++){
186 for(uint8_t cx=0;cx<GIC_LEFT_W;cx++){
187 draw_char_left(XSTART+(cx*GIC_CHAR_W),
188 YSTART+(cy*GIC_CHAR_H),
189 m_ram(current),
190 m_bitmap);
191 current++;
192 }
193 }
194
195 //right hand side is next
196 current=0x48;//110 octal
197 XSTART+=(GIC_LEFT_W*GIC_CHAR_W)+1;
198
199 for(uint8_t cy=0;cy<GIC_RIGHT_H;cy++){
200 for(uint8_t cx=0;cx<GIC_RIGHT_W;cx++){
201 //complex case
202 uint8_t data = m_ram(current++);
203
204 size_t currX = (XSTART+ (cx*(3+GIC_CHAR_W)));
205 size_t currUP = (YSTART+ (cy*(2*GIC_CHAR_H)));
206 size_t currLOW = (YSTART+GIC_CHAR_H+(cy*(2*GIC_CHAR_H)));
207
208 switch(data&0xC0){
209 case 0x00:{
210 //lower rectangle only, normal char
211 draw_char_right(currX,currLOW,data,m_bitmap,GIC_GREEN);
212 }break;
213
214 //White block
215 case 0xC0:{
216 //upper rectangle
217 draw_char_right(currX,currUP, GIC_SPACE,m_bitmap,GIC_WHITE);
218 //lower rectangle
219 draw_char_right(currX,currLOW,GIC_SPACE,m_bitmap,GIC_WHITE);
220 }break;
221
222 //Draw a card
223 case 0x40:{
224 int bgColor = (data&0x10)?GIC_RED:GIC_BLACK;
225 //upper rectangle
226 draw_char_right(currX,currUP, (data&0xF)+0x30,m_bitmap,bgColor);
227 //lower rectangle
228 draw_char_right(currX,currLOW,GIC_CLUB+((data&0x30)>>4),m_bitmap,bgColor);
229 }break;
230
231 default:printf("gic unknown char! %02X\n",data); break;
232 }
233 }
234 }
235
236 copybitmap( bitmap, m_bitmap, 0, 0, 0, 0, cliprect );
237 return 0;
238 }
239
240 /* AUDIO SECTION */
241
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)242 void gic_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
243 {
244 switch ( id )
245 {
246 case TIMER_VBLANK:
247 //flag the audio to reset
248 m_audioreset = 1;//phase need to reset! on next clock/228
249 break;
250 }
251 }
252
253 #define GIC_AUDIO_BYTE 0x96
254
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)255 void gic_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
256 {
257 auto &buffer = outputs[0];
258
259 //Audio is basic and badly implemented (doubt that was the intent)
260 //The datasheet lists the 3 different frequencies the GIC can generate: 500,1000 and 2000Hz
261 //but it is clear (for an audio guy at least) that the resulting spectrum
262 //is not a pure square wave. In fact, the counter is reset on vertical sync!
263 //http://twitter.com/plgDavid/status/527269086016077825
264 //...thus creating a buzzing sound.
265
266 //Dumping the audio pin value each time
267 // either (PHI2 made a 0->1 transition (1.789MHz)
268 // or (PHI1 made a 1->1 transition (1.789MHz)
269 //I found that the granularity of audio transitions
270 //(including phase resets and silences) was 228 clocks
271 //The audio subsystem thus runs at 1.789MHz/228 = 7849.88Hz
272
273 //when 1
274 //normal period:912 clocks (228*4)
275 //hi for 456 clocks
276 //lo for 456 clocks
277 //reset period: (each frame)
278 //hi for 228 clocks
279 //lo for 456 clocks
280 //when 2
281 //normal period lasts 1824 clocks (228*8)
282 //hi for 912 clocks
283 //lo for 912 clocks
284 //reset period: (each frame)
285 //hi for 912 (228*4)
286 //lo for 1596 (228*7)
287 //hi for 912 (228*4)
288 //when 4
289 //normal period lasts 3648 clocks (228*16)
290 //hi for 1824(228*8)
291 //lo for 1824(228*8)
292 //Reset period:
293 //lo for 1824(228*8)
294 //hi for 2508(228*11)
295 //lo for 1824(228*8)
296 //hi for 1824(228*8)
297
298 uint8_t audioByte = m_ram(GIC_AUDIO_BYTE)*2;
299
300 if(!audioByte){
301 buffer.fill(0);
302
303 m_audioval = 0;
304 m_audiocnt = 0;
305 m_audioreset = 0;
306 return;//early
307 }
308
309 //forced resynch @ 59.95Hz
310 if(m_audioreset){
311 m_audioval = 0;//forced low
312 m_audiocnt = 0;
313 m_audioreset = 0;
314 }
315
316 for(size_t i=0; i < buffer.samples(); i++){
317 m_audiocnt++;
318 if(m_audiocnt >= audioByte){
319 m_audioval = !m_audioval;
320 m_audiocnt=0;
321 }
322 buffer.put(i, m_audioval ? 1.0 : 0.0);
323 }
324 }
325