1 // license:BSD-3-Clause
2 // copyright-holders:Jean-Francois DEL NERO
3 
4 /*********************************************************************
5 
6     ef9365.c
7 
8     Thomson EF9365/EF9366 video controller emulator code
9 
10     The EF9365/EF9366 is a video controller driving a frame buffer
11     and having built-in vectors and characters drawing engines.
12     This is natively a "black and white" chip (1 bitplane),
13     but it is possible to add more bitplanes to have colors with a
14     hardware trick. The system don't have direct access to the video
15     memory, but indirect access is possible through the 0x0F command
16     and some hardware glue logics.
17     The current implementation emulate the main functions :
18 
19     Video modes supported (Hardware implementation dependent):
20         - 256 x 256 (EF9365 with 4 bits shifters per bitplane and FMAT to VSS)
21         - 512 x 512 interlaced (EF9365 with 8 bits shifters per bitplane and FMAT to VCC)
22         - 512 x 256 non interlaced (EF9366 with 8 bits shifters per bitplane)
23         - 128 x 128 (EF9365 with 2 bits shifters per bitplane and FMAT to VSS)
24         - 64 x 64 (EF9365 with FMAT to VSS)
25 
26         - 1 bitplane up to 8 bitplanes hardware configuration.
27         - 2 up to 256 colors fixed palette.
28 
29     Character & block drawing :
30         - Normal / Titled mode
31         - Horizontal / Vertical orientation
32         - P & Q Zoom factors (1 up to 16)
33 
34     Vector drawing :
35         - Normal / Dotted / Dashed / Dotted-Dashed mode
36         - All directions and size supported.
37 
38     General :
39         - Clear Screen
40         - Fill Screen
41         - Clear X & Y registers
42         - Video RAM readback supported (Command 0x0F)
43 
44     What is NOT yet currently implemented:
45         - Light pen support
46         (To be done when i will find a software using the lightpen)
47 
48     What is implemented but not really tested:
49         - Interrupts output.
50         My target system (Squale Apollo 7) doesn't use the interruption
51         for this chip. So i add the interrupt line support, but
52         bug(s) is possible.
53 
54     To see how to use this driver, have a look to the Squale machine
55     driver (squale.cpp).
56     If you have any question, don't hesitate to contact me at the email
57     present on this website : http://hxc2001.free.fr/
58 
59     12/29/2015
60     Jean-Francois DEL NERO
61 *********************************************************************/
62 
63 #include "emu.h"
64 #include "ef9365.h"
65 
66 #include "screen.h"
67 
68 //#define VERBOSE 1
69 #include "logmacro.h"
70 
71 
72 namespace {
73 
74 #define EF936X_REG_STATUS 0x00
75 #define EF936X_REG_CMD    0x00
76 #define EF936X_REG_CTRL1  0x01
77 #define EF936X_REG_CTRL2  0x02
78 #define EF936X_REG_CSIZE  0x03
79 #define EF936X_REG_DELTAX 0x05
80 #define EF936X_REG_DELTAY 0x07
81 #define EF936X_REG_X_MSB  0x08
82 #define EF936X_REG_X_LSB  0x09
83 #define EF936X_REG_Y_MSB  0x0A
84 #define EF936X_REG_Y_LSB  0x0B
85 #define EF936X_REG_XLP    0x0C
86 #define EF936X_REG_YLP    0x0D
87 
88 
89 //-------------------------------------------------
90 // Some debug mode const strings
91 // to trace the commands and registers accesses.
92 //-------------------------------------------------
93 
94 // Registers list
95 const char *const register_names[]=
96 {
97 	"0x00 - CMD / STATUS",
98 	"0x01 - CTRL 1      ",
99 	"0x02 - CTRL 2      ",
100 	"0x03 - CSIZE       ",
101 	"0x04 - RESERVED    ",
102 	"0x05 - DELTA X     ",
103 	"0x06 - RESERVED    ",
104 	"0x07 - DELTA Y     ",
105 	"0x08 - X MSBs      ",
106 	"0x09 - X LSBs      ",
107 	"0x0A - Y MSBs      ",
108 	"0x0B - Y LSBs      ",
109 	"0x0C - XLP         ",
110 	"0x0D - YLP         ",
111 	"0x0E - RESERVED    ",
112 	"0x0F - RESERVED    "
113 };
114 
115 // Commands list
116 const char *const commands_names[]=
117 {
118 	"0x00 - Set bit 1 of CTRL1   : Pen selection",
119 	"0x01 - Clear bit 1 of CTRL1 : Eraser selection",
120 	"0x02 - Set bit 0 of CTRL1   : Pen/Eraser down selection",
121 	"0x03 - Clear bit 0 of CTRL1 : Pen/Eraser up selection",
122 	"0x04 - Clear screen",
123 	"0x05 - X and Y registers reset to 0",
124 	"0x06 - X and Y registers reset to 0 and clear screen",
125 	"0x07 - Clear screen, set CSIZE to code \"minsize\". All other registers reset to 0",
126 	"0x08 - Light-pen initialization (/White forced low)",
127 	"0x09 - Light-pen initialization",
128 	"0x0A - 5x8 block drawing (size according to CSIZE)",
129 	"0x0B - 4x4 block drawing (size according to CSIZE)",
130 	"0x0C - Screen scanning : pen or Eraser as defined by CTRL1",
131 	"0x0D - X  reset to 0",
132 	"0x0E - Y  reset to 0",
133 	"0x0F - Direct image memory access request for the next free cycle.",
134 	"0x10<>0x17 - Vector generation",
135 	"0x18<>0x1F - Special direction vectors",
136 	"0x20<>0x7F - Character Drawing",
137 	"0x80<>0xFF - Small vector generation",
138 };
139 
140 } // anonymous namespace
141 
142 
143 // devices
144 DEFINE_DEVICE_TYPE(EF9365, ef9365_device, "ef9365", "Thomson EF9365")
145 
ROM_START(ef9365)146 ROM_START( ef9365 )
147 	ROM_REGION( 0x1E0, "ef9365", 0 )
148 	ROM_LOAD( "charset_ef9365.rom", 0x0000, 0x01E0, CRC(8d3053be) SHA1(0f9a64d217a0f7f04ee0720d49c5b680ad0ae359) )
149 ROM_END
150 
151 //-------------------------------------------------
152 //  rom_region - return a pointer to the device's
153 //  internal ROM region
154 //-------------------------------------------------
155 
156 const tiny_rom_entry *ef9365_device::device_rom_region() const
157 {
158 	return ROM_NAME( ef9365 );
159 }
160 
161 //-------------------------------------------------
162 // default address map
163 // Up to 512*512 per bitplane, 8 bitplanes max.
164 //-------------------------------------------------
ef9365(address_map & map)165 void ef9365_device::ef9365(address_map &map)
166 {
167 	if (!has_configured_map(0))
168 		map(0x00000, ef9365_device::BITPLANE_MAX_SIZE * ef9365_device::MAX_BITPLANES - 1).ram();
169 }
170 
171 //-------------------------------------------------
172 //  memory_space_config - return a description of
173 //  any address spaces owned by this device
174 //-------------------------------------------------
175 
memory_space_config() const176 device_memory_interface::space_config_vector ef9365_device::memory_space_config() const
177 {
178 	return space_config_vector {
179 		std::make_pair(0, &m_space_config)
180 	};
181 }
182 
183 //**************************************************************************
184 //  INLINE HELPERS
185 //**************************************************************************
186 
187 
188 //**************************************************************************
189 //  live device
190 //**************************************************************************
191 
192 //-------------------------------------------------
193 //  ef9365_device - constructor
194 //-------------------------------------------------
195 
ef9365_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)196 ef9365_device::ef9365_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
197 	device_t(mconfig, EF9365, tag, owner, clock),
198 	device_memory_interface(mconfig, *this),
199 	device_video_interface(mconfig, *this),
200 	m_space_config("videoram", ENDIANNESS_LITTLE, 8, 18, 0, address_map_constructor(FUNC(ef9365_device::ef9365), this)),
201 	m_charset(*this, "ef9365"),
202 	m_palette(*this, finder_base::DUMMY_TAG),
203 	m_irq_handler(*this)
204 {
205 	clock_freq = clock;
206 }
207 
208 //-------------------------------------------------
209 //  set_nb_of_bitplanes: Set the number of bitplanes
210 //-------------------------------------------------
211 
set_nb_bitplanes(int nb_bitplanes)212 void ef9365_device::set_nb_bitplanes(int nb_bitplanes)
213 {
214 	if( nb_bitplanes > 0 && nb_bitplanes <= 8 )
215 	{
216 		nb_of_bitplanes = nb_bitplanes;
217 		nb_of_colors = pow(2, nb_bitplanes);
218 	}
219 }
220 
221 //-------------------------------------------------
222 //  set_display_mode: Set the display mode
223 //-------------------------------------------------
224 
set_display_mode(int display_mode)225 void ef9365_device::set_display_mode(int display_mode)
226 {
227 	switch(display_mode)
228 	{
229 	case DISPLAY_MODE_256x256:
230 		bitplane_xres = 256;
231 		bitplane_yres = 256;
232 		vsync_scanline_pos = 250;
233 		overflow_mask_x = 0xFF00;
234 		overflow_mask_y = 0xFF00;
235 		break;
236 	case DISPLAY_MODE_512x512:
237 		bitplane_xres = 512;
238 		bitplane_yres = 512;
239 		vsync_scanline_pos = 506;
240 		overflow_mask_x = 0xFE00;
241 		overflow_mask_y = 0xFE00;
242 		break;
243 	case DISPLAY_MODE_512x256:
244 		bitplane_xres = 512;
245 		bitplane_yres = 256;
246 		vsync_scanline_pos = 250;
247 		overflow_mask_x = 0xFE00;
248 		overflow_mask_y = 0xFF00;
249 		break;
250 	case DISPLAY_MODE_128x128:
251 		bitplane_xres = 128;
252 		bitplane_yres = 128;
253 		vsync_scanline_pos = 124;
254 		overflow_mask_x = 0xFF80;
255 		overflow_mask_y = 0xFF80;
256 		break;
257 	case DISPLAY_MODE_64x64:
258 		bitplane_xres = 64;
259 		bitplane_yres = 64;
260 		vsync_scanline_pos = 62;
261 		overflow_mask_x = 0xFFC0;
262 		overflow_mask_y = 0xFFC0;
263 		break;
264 	default:
265 		logerror("Invalid EF9365 Display mode: %02x\n", display_mode);
266 		bitplane_xres = 256;
267 		bitplane_yres = 256;
268 		vsync_scanline_pos = 250;
269 		overflow_mask_x = 0xFF00;
270 		overflow_mask_y = 0xFF00;
271 		break;
272 	}
273 }
274 
275 //-------------------------------------------------
276 //  set_color_entry: Set the color value
277 //  into the palette
278 //-------------------------------------------------
279 
set_color_entry(int index,uint8_t r,uint8_t g,uint8_t b)280 void ef9365_device::set_color_entry( int index, uint8_t r, uint8_t g, uint8_t b )
281 {
282 	if( index < nb_of_colors )
283 	{
284 		m_palette->set_pen_color(index, rgb_t(r, g, b));
285 	}
286 	else
287 	{
288 		logerror("Invalid EF9365 Palette entry : %02x\n", index);
289 	}
290 }
291 
292 //-------------------------------------------------
293 //  set_color_filler: Set the color number
294 //  used by the chip to draw/fill the memory
295 //-------------------------------------------------
296 
set_color_filler(uint8_t color)297 void ef9365_device::set_color_filler( uint8_t color )
298 {
299 	m_current_color = color;
300 }
301 
302 //-------------------------------------------------
303 //  device_start - device-specific startup
304 //-------------------------------------------------
305 
device_start()306 void ef9365_device::device_start()
307 {
308 	m_irq_handler.resolve_safe();
309 
310 	m_busy_timer = timer_alloc(BUSY_TIMER);
311 
312 	m_videoram = &space(0);
313 	m_current_color = 0x00;
314 
315 	m_irq_vb = 0;
316 	m_irq_lb = 0;
317 	m_irq_rdy = 0;
318 	m_irq_state = 0;
319 
320 	m_screen_out.allocate( bitplane_xres, screen().height() );
321 
322 	save_item(NAME(m_border));
323 	save_item(NAME(m_registers));
324 	save_item(NAME(m_bf));
325 	save_item(NAME(m_state));
326 
327 	save_item(NAME(m_irq_state));
328 	save_item(NAME(m_irq_vb));
329 	save_item(NAME(m_irq_lb));
330 	save_item(NAME(m_irq_rdy));
331 
332 	save_item(NAME(m_screen_out));
333 }
334 
335 //-------------------------------------------------
336 //  device_reset - device-specific reset
337 //-------------------------------------------------
338 
device_reset()339 void ef9365_device::device_reset()
340 {
341 	m_state = 0;
342 
343 	m_bf = 0;
344 	m_irq_state = 0;
345 	m_irq_vb = 0;
346 	m_irq_lb = 0;
347 	m_irq_rdy = 0;
348 
349 	memset(m_registers, 0, sizeof(m_registers));
350 	memset(m_border, 0, sizeof(m_border));
351 
352 	m_screen_out.fill(0);
353 
354 	set_video_mode();
355 	screen_scanning(1);
356 
357 	m_irq_handler(false);
358 }
359 
360 //-------------------------------------------------
361 //  update_interrupts
362 //-------------------------------------------------
update_interrupts()363 void ef9365_device::update_interrupts()
364 {
365 	int new_state = ( m_irq_vb  && (m_registers[EF936X_REG_CTRL1] & 0x20) )
366 					|| ( m_irq_rdy && (m_registers[EF936X_REG_CTRL1] & 0x40) )
367 					|| ( m_irq_lb  && (m_registers[EF936X_REG_CTRL1] & 0x10) );
368 
369 	if (new_state != m_irq_state)
370 	{
371 		m_irq_state = new_state;
372 		m_irq_handler(m_irq_state);
373 	}
374 }
375 
376 //-------------------------------------------------
377 //  device_timer - handler timer events
378 //-------------------------------------------------
379 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)380 void ef9365_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
381 {
382 	switch(id)
383 	{
384 		case BUSY_TIMER:
385 			m_bf = 0;
386 
387 			if( m_registers[EF936X_REG_CTRL1] & 0x40 )
388 			{
389 				m_irq_rdy = 1;
390 			}
391 
392 			update_interrupts();
393 
394 			break;
395 	}
396 }
397 
398 //-------------------------------------------------
399 //  set_busy_flag: set busy flag and
400 //  timer to clear it
401 //-------------------------------------------------
402 
set_busy_flag(int period)403 void ef9365_device::set_busy_flag(int period)
404 {
405 	m_bf = 1;
406 	m_busy_timer->adjust(attotime::from_usec(period));
407 }
408 
409 //-------------------------------------------------
410 //  get_x_reg: Get the X register value
411 //-------------------------------------------------
412 
get_x_reg()413 uint16_t ef9365_device::get_x_reg()
414 {
415 	return ((m_registers[EF936X_REG_X_MSB] & 0x0F)<<8) | m_registers[EF936X_REG_X_LSB];
416 }
417 
418 //-------------------------------------------------
419 //  get_y_reg: Get the Y register value
420 //-------------------------------------------------
421 
get_y_reg()422 uint16_t ef9365_device::get_y_reg()
423 {
424 	return ((m_registers[EF936X_REG_Y_MSB] & 0x0F)<<8) | m_registers[EF936X_REG_Y_LSB];
425 }
426 
427 //-------------------------------------------------
428 //  set_x_reg: Set the X register value
429 //-------------------------------------------------
430 
set_x_reg(uint16_t x)431 void ef9365_device::set_x_reg(uint16_t x)
432 {
433 	m_registers[EF936X_REG_X_MSB] = ( x >> 8 ) & 0x0F;
434 	m_registers[EF936X_REG_X_LSB] = x & 0xFF;
435 }
436 
437 //-------------------------------------------------
438 //  set_y_reg: Set the Y register value
439 //-------------------------------------------------
440 
set_y_reg(uint16_t y)441 void ef9365_device::set_y_reg(uint16_t y)
442 {
443 	m_registers[EF936X_REG_Y_MSB] = ( y >> 8 ) & 0x0F;
444 	m_registers[EF936X_REG_Y_LSB] = y & 0xFF;
445 }
446 
447 //-------------------------------------------------
448 //  set_video_mode: Set output screen format
449 //-------------------------------------------------
450 
set_video_mode(void)451 void ef9365_device::set_video_mode(void)
452 {
453 	uint16_t new_width = bitplane_xres;
454 
455 	if (screen().width() != new_width)
456 	{
457 		rectangle visarea = screen().visible_area();
458 		visarea.max_x = new_width - 1;
459 
460 		screen().configure(new_width, screen().height(), visarea, screen().frame_period().attoseconds());
461 	}
462 
463 	//border color
464 	memset(m_border, 0, sizeof(m_border));
465 }
466 
467 //-------------------------------------------------
468 //  get_last_readback_word: Read back the latched
469 //  bitplane words
470 //-------------------------------------------------
471 
get_last_readback_word(int bitplane_number,int * pixel_offset)472 uint8_t ef9365_device::get_last_readback_word(int bitplane_number, int * pixel_offset)
473 {
474 	if( pixel_offset )
475 		*pixel_offset = m_readback_latch_pix_offset;
476 
477 	if( bitplane_number < nb_of_bitplanes )
478 	{
479 		return m_readback_latch[bitplane_number];
480 	}
481 	else
482 	{
483 		return 0x00;
484 	}
485 }
486 
487 //-------------------------------------------------
488 //  draw_border: Draw the left and right borders
489 //  ( No border for the moment ;) )
490 //-------------------------------------------------
491 
draw_border(uint16_t line)492 void ef9365_device::draw_border(uint16_t line)
493 {
494 }
495 
496 //-------------------------------------------------
497 //  plot: Plot a pixel to the bitplanes
498 //  at the x & y position with the m_current_color color
499 //-------------------------------------------------
500 
plot(int x_pos,int y_pos)501 void ef9365_device::plot(int x_pos,int y_pos)
502 {
503 	int p;
504 
505 	if( ( x_pos >= 0 && y_pos >= 0 ) && ( x_pos < bitplane_xres && y_pos < bitplane_yres ) )
506 	{
507 		if ( m_registers[EF936X_REG_CTRL1] & 0x01 )
508 		{
509 			y_pos = ( (bitplane_yres - 1) - y_pos );
510 
511 			if( (m_registers[EF936X_REG_CTRL1] & 0x02) )
512 			{
513 				// Pen
514 				for( p = 0 ; p < nb_of_bitplanes ; p++ )
515 				{
516 					if( m_current_color & (0x01 << p) )
517 						m_videoram->write_byte ( (BITPLANE_MAX_SIZE*p) + (((y_pos*bitplane_xres) + x_pos)>>3), m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (((y_pos*bitplane_xres) + x_pos)>>3)) |  (0x80 >> (((y_pos*bitplane_xres) + x_pos)&7) ) );
518 					else
519 						m_videoram->write_byte ( (BITPLANE_MAX_SIZE*p) + (((y_pos*bitplane_xres) + x_pos)>>3), m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (((y_pos*bitplane_xres) + x_pos)>>3)) & ~(0x80 >> (((y_pos*bitplane_xres) + x_pos)&7) ) );
520 				}
521 			}
522 			else
523 			{
524 				// Eraser
525 				for( p = 0 ; p < nb_of_bitplanes ; p++ )
526 				{
527 					m_videoram->write_byte ( (BITPLANE_MAX_SIZE*p) + (((y_pos*bitplane_xres) + x_pos)>>3), m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (((y_pos*bitplane_xres) + x_pos)>>3)) | (0x80 >> (((y_pos*bitplane_xres) + x_pos)&7) ) );
528 				}
529 			}
530 		}
531 	}
532 }
533 
534 
535 const static unsigned int vectortype_code[][8] =
536 {
537 	{0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // Continuous drawing
538 	{0x82,0x02,0x00,0x00,0x00,0x00,0x00,0x00}, // Dotted - 2 dots on, 2 dots off
539 	{0x84,0x04,0x00,0x00,0x00,0x00,0x00,0x00}, // Dashed - 4 dots on, 4 dots off
540 	{0x8A,0x02,0x82,0x02,0x00,0x00,0x00,0x00}  // Dotted-Dashed - 10 dots on, 2 dots off, 2 dots on, 2 dots off
541 };
542 
543 //-------------------------------------------------
544 //  draw_vector: Vector drawing function
545 //  from the start_x & start_y position to the start_x+delta_x & start_y+delta_y position
546 //  with the m_current_color color
547 //  (Bresenham's line algorithm)
548 //-------------------------------------------------
549 
draw_vector(uint16_t start_x,uint16_t start_y,short delta_x,short delta_y)550 int ef9365_device::draw_vector(uint16_t start_x,uint16_t start_y,short delta_x,short delta_y)
551 {
552 	int dx;
553 	int dy,t;
554 	int e;
555 	int x,y,dest_x,dest_y,end_x,end_y;
556 	int incy;
557 	int diago,horiz;
558 	unsigned char c1;
559 
560 	int pen_state;
561 	unsigned int state_counter;
562 	int dot_code_ptr;
563 	int compute_cycles;
564 
565 	LOG("EF9365 draw_vector : Start=(%d,%d) End=(%d,%d)\n", start_x,start_y,start_x+delta_x,start_y+delta_y);
566 
567 	compute_cycles = 0;
568 
569 	dest_x = start_x + delta_x;
570 	dest_y = start_y + delta_y;
571 
572 	end_x = dest_x;
573 	end_y = dest_y;
574 
575 	c1=0;
576 	incy=1;
577 
578 	dot_code_ptr = 0;
579 	state_counter = vectortype_code[m_registers[EF936X_REG_CTRL2] & 0x3][dot_code_ptr&7];
580 	if(state_counter&0x80)
581 		pen_state = 1;
582 	else
583 		pen_state = 0;
584 	state_counter &= ~0x80;
585 
586 	if( dest_x > start_x )
587 		dx = dest_x - start_x;
588 	else
589 		dx = start_x - dest_x;
590 
591 	if( dest_y > start_y )
592 		dy = dest_y - start_y;
593 	else
594 		dy = start_y - dest_y;
595 
596 	if( dy > dx )
597 	{
598 		t = dest_y;
599 		dest_y = dest_x;
600 		dest_x = t;
601 
602 		t = start_y;
603 		start_y = start_x;
604 		start_x = t;
605 
606 		t = dx;
607 		dx = dy;
608 		dy = t;
609 
610 		c1 = 1;
611 	}
612 
613 	if( start_x > dest_x )
614 	{
615 		t = dest_y;
616 		dest_y = start_y;
617 		start_y = t;
618 
619 		t = start_x;
620 		start_x = dest_x;
621 		dest_x = t;
622 	}
623 
624 	horiz = dy<<1;
625 	diago = ( dy - dx )<<1;
626 	e = ( dy<<1 ) - dx;
627 
628 	if( start_y <= dest_y )
629 		incy = 1;
630 	else
631 		incy = -1;
632 
633 	x = start_x;
634 	y = start_y;
635 
636 	if(c1)
637 	{
638 		do
639 		{
640 			if(pen_state)
641 				plot(y % bitplane_xres, x % bitplane_yres);
642 
643 			compute_cycles++;
644 
645 			set_x_reg(y);
646 			set_y_reg(x);
647 
648 			state_counter--;
649 
650 			if( !state_counter )
651 			{
652 				dot_code_ptr++;
653 
654 				state_counter = vectortype_code[m_registers[EF936X_REG_CTRL2] & 0x3][dot_code_ptr&7];
655 
656 				if(!state_counter)
657 				{
658 					dot_code_ptr = 0;
659 					state_counter = vectortype_code[m_registers[EF936X_REG_CTRL2] & 0x3][dot_code_ptr&7];
660 				}
661 
662 				if( state_counter & 0x80 )
663 				{
664 					pen_state = 1;
665 				}
666 				else
667 				{
668 					pen_state = 0;
669 				}
670 
671 				state_counter &= ~0x80;
672 			}
673 
674 			if( e > 0 )
675 			{
676 				y = y + incy;
677 				e = e + diago;
678 			}
679 			else
680 			{
681 				e = e + horiz;
682 			}
683 
684 			x++;
685 
686 		} while (x <= dest_x);
687 	}
688 	else
689 	{
690 		do
691 		{
692 			if(pen_state)
693 				plot(x % bitplane_xres, y % bitplane_yres);
694 
695 			compute_cycles++;
696 
697 			set_x_reg(x);
698 			set_y_reg(y);
699 
700 			state_counter--;
701 
702 			if( !state_counter )
703 			{
704 				dot_code_ptr++;
705 
706 				state_counter = vectortype_code[m_registers[EF936X_REG_CTRL2] & 0x3][dot_code_ptr&7];
707 
708 				if(!state_counter)
709 				{
710 					dot_code_ptr = 0;
711 					state_counter = vectortype_code[m_registers[EF936X_REG_CTRL2] & 0x3][dot_code_ptr&7];
712 				}
713 
714 				if( state_counter & 0x80 )
715 				{
716 					pen_state = 1;
717 				}
718 				else
719 				{
720 					pen_state = 0;
721 				}
722 
723 				state_counter &= ~0x80;
724 			}
725 
726 			if( e > 0 )
727 			{
728 				y = y + incy;
729 				e = e + diago;
730 			}
731 			else
732 			{
733 				e = e + horiz;
734 			}
735 
736 			x++;
737 
738 		} while (x <= dest_x);
739 	}
740 
741 	set_x_reg(end_x);
742 	set_y_reg(end_y);
743 
744 	return compute_cycles;
745 }
746 
747 //-------------------------------------------------
748 //  get_char_pix: Get a character pixel state
749 //  from the charset.
750 //-------------------------------------------------
751 
get_char_pix(unsigned char c,int x,int y)752 int ef9365_device::get_char_pix( unsigned char c, int x, int y )
753 {
754 	int char_base,char_pix;
755 
756 	if(c<96)
757 	{
758 		if( x < 5 && y < 8 )
759 		{
760 			char_base =  c * 5;
761 			char_pix = ( y * 5 ) + x;
762 
763 			if ( m_charset[char_base + (char_pix>>3)] & ( 0x80 >> (char_pix&7)) )
764 				return 1;
765 			else
766 				return 0;
767 		}
768 	}
769 
770 	return 0;
771 }
772 
773 //-------------------------------------------------
774 //  draw_character: Character and block drawing function
775 //  Set smallblock to draw a 4x4 block
776 //  Set block to draw a 5x8 block
777 //-------------------------------------------------
778 
draw_character(unsigned char c,int block,int smallblock)779 int ef9365_device::draw_character( unsigned char c, int block, int smallblock )
780 {
781 	int x_char,y_char;
782 	unsigned int x, y;
783 	int x_char_res,y_char_res;
784 	int p_factor,q_factor,p,q;
785 	int compute_cycles;
786 
787 	x = get_x_reg();
788 	y = get_y_reg();
789 
790 	x_char_res = 5;
791 	y_char_res = 8;
792 
793 	if( smallblock )
794 	{
795 		block = 1;
796 		x_char_res = 4;
797 		y_char_res = 4;
798 	}
799 
800 	p_factor = (m_registers[EF936X_REG_CSIZE] >> 4);
801 	if(!p_factor)
802 		p_factor = 16;
803 
804 	q_factor = (m_registers[EF936X_REG_CSIZE] &  0xF);
805 	if(!q_factor)
806 		q_factor = 16;
807 
808 	compute_cycles = ( ( x_char_res + 1 ) * p_factor ) * ( y_char_res * q_factor );
809 
810 	if(c<96)
811 	{
812 		for( x_char=0 ; x_char < x_char_res ; x_char++ )
813 		{
814 			for( y_char = y_char_res - 1 ; y_char >= 0 ; y_char-- )
815 			{
816 				if ( block || get_char_pix( c, x_char, ( (y_char_res - 1) - y_char ) ) )
817 				{
818 					if( m_registers[EF936X_REG_CTRL2] & 0x04) // Tilted character
819 					{
820 						for(q = 0; q < q_factor; q++)
821 						{
822 							for(p = 0; p < p_factor; p++)
823 							{
824 								if( !(m_registers[EF936X_REG_CTRL2] & 0x08) )
825 								{ // Tilted - Horizontal orientation
826 									plot(
827 											x + ( (y_char*q_factor) + q ) + ( (x_char*p_factor) + p ),
828 											y + ( (y_char*q_factor) + q )
829 										);
830 								}
831 								else
832 								{ // Tilted - Vertical orientation
833 									plot(
834 											x - ( (y_char*q_factor)+ q ),
835 											y + ( (x_char*p_factor)+ p ) - ( ( ( (y_char_res - 1 ) - y_char) * q_factor ) + ( q_factor - q ) )
836 										);
837 								}
838 							}
839 						}
840 					}
841 					else
842 					{
843 						for(q = 0; q < q_factor; q++)
844 						{
845 							for(p = 0; p < p_factor; p++)
846 							{
847 								if( !(m_registers[EF936X_REG_CTRL2] & 0x08) )
848 								{ // Normal - Horizontal orientation
849 									plot(
850 											x + ( (x_char*p_factor) + p ),
851 											y + ( (y_char*q_factor) + q )
852 										);
853 								}
854 								else
855 								{ // Normal - Vertical orientation
856 									plot(
857 											x - ( (y_char*q_factor) + q ),
858 											y + ( (x_char*p_factor) + p )
859 										);
860 								}
861 							}
862 						}
863 					}
864 				}
865 			}
866 		}
867 
868 		if(!(m_registers[EF936X_REG_CTRL2] & 0x08))
869 		{
870 			x = x + ( (x_char_res + 1 ) * p_factor ) ;
871 			set_x_reg(x);
872 		}
873 		else
874 		{
875 			y = y + ( (x_char_res + 1 ) * p_factor ) ;
876 			set_y_reg(y);
877 		}
878 	}
879 
880 	return compute_cycles;
881 }
882 
883 //-------------------------------------------------
884 //  cycles_to_us: Convert a number of clock cycles to us
885 //-------------------------------------------------
886 
cycles_to_us(int cycles)887 int ef9365_device::cycles_to_us(int cycles)
888 {
889 	return ( (float)cycles * ( (float)1000000 / (float)clock_freq ) );
890 }
891 
892 //-------------------------------------------------
893 // dump_bitplanes_word: Latch the bitplane words
894 // pointed by the x & y registers
895 // (Memory read back function)
896 //-------------------------------------------------
897 
dump_bitplanes_word()898 void ef9365_device::dump_bitplanes_word()
899 {
900 	int p;
901 	int pixel_ptr;
902 
903 	pixel_ptr = ( ( ( ( bitplane_yres - 1 ) - ( get_y_reg() & ( bitplane_yres - 1 ) ) ) * bitplane_xres ) + ( get_x_reg() & ( bitplane_xres - 1 ) ) );
904 
905 	LOG("dump : x = %d , y = %d\n", get_x_reg() ,get_y_reg());
906 
907 	for( p = 0; p < nb_of_bitplanes ; p++ )
908 	{
909 		if( pixel_ptr & 0x4 )
910 		{
911 			m_readback_latch[p] = ( m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (pixel_ptr>>3) )  ) & 0xF ;
912 		}
913 		else
914 		{
915 			m_readback_latch[p] = ( m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (pixel_ptr>>3) ) >> 4 ) & 0xF ;
916 		}
917 
918 	}
919 
920 	m_readback_latch_pix_offset = pixel_ptr & 0x3;
921 }
922 
923 //-------------------------------------------------
924 // screen_scanning: Fill / Clear framebuffer memory
925 //-------------------------------------------------
926 
screen_scanning(int force_clear)927 void ef9365_device::screen_scanning( int force_clear )
928 {
929 	int x,y,p;
930 
931 	if( (m_registers[EF936X_REG_CTRL1] & 0x02) && !force_clear )
932 	{
933 		for( y = 0; y < bitplane_yres; y++ )
934 		{
935 			for( x = 0; x < bitplane_xres; x++ )
936 			{
937 				for( p = 0 ; p < nb_of_bitplanes ; p++ )
938 				{
939 					if( m_current_color & (0x01 << p) )
940 						m_videoram->write_byte ( (BITPLANE_MAX_SIZE*p) + (((y*bitplane_xres) + x)>>3), m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (((y*bitplane_xres) + x)>>3)) |  (0x80 >> (((y*bitplane_xres) + x)&7) ) );
941 					else
942 						m_videoram->write_byte ( (BITPLANE_MAX_SIZE*p) + (((y*bitplane_xres) + x)>>3), m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (((y*bitplane_xres) + x)>>3)) & ~(0x80 >> (((y*bitplane_xres) + x)&7) ) );
943 				}
944 			}
945 		}
946 	}
947 	else
948 	{
949 		for( y = 0; y < bitplane_yres; y++)
950 		{
951 			for( x = 0; x < bitplane_xres; x++)
952 			{
953 				for( p = 0 ; p < nb_of_bitplanes ; p++ )
954 				{
955 					m_videoram->write_byte ( (BITPLANE_MAX_SIZE*p) + (((y*bitplane_xres) + x)>>3), m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (((y*bitplane_xres) + x)>>3)) | (0x80 >> (((y*bitplane_xres) + x)&7) ) );
956 				}
957 			}
958 		}
959 	}
960 }
961 
962 //-------------------------------------------------
963 // ef9365_exec: EF936X Command decoder and execution
964 //-------------------------------------------------
965 
ef9365_exec(uint8_t cmd)966 void ef9365_device::ef9365_exec(uint8_t cmd)
967 {
968 	int tmp_delta_x,tmp_delta_y;
969 	int busy_cycles = 0;
970 	m_state = 0;
971 
972 	if( ( cmd>>4 ) == 0 )
973 	{
974 		LOG("EF9365 Command : %s\n", commands_names[cmd & 0xF]);
975 
976 		switch(cmd & 0xF)
977 		{
978 			case 0x0: // Set bit 1 of CTRL1 : Pen Selection
979 				m_registers[EF936X_REG_CTRL1] |= 0x02;
980 				set_busy_flag( cycles_to_us( 4 ) ); // Timing to check on the real hardware
981 			break;
982 			case 0x1: // Clear bit 1 of CTRL1 : Eraser Selection
983 				m_registers[EF936X_REG_CTRL1] &= (~0x02);
984 				set_busy_flag( cycles_to_us( 4 ) ); // Timing to check on the real hardware
985 			break;
986 			case 0x2: // Set bit 0 of CTRL1 : Pen/Eraser down selection
987 				m_registers[EF936X_REG_CTRL1] |= 0x01;
988 				set_busy_flag( cycles_to_us( 4 ) ); // Timing to check on the real hardware
989 			break;
990 			case 0x3: // Clear bit 0 of CTRL1 : Pen/Eraser up selection
991 				m_registers[EF936X_REG_CTRL1] &= (~0x01);
992 				set_busy_flag( cycles_to_us( 4 ) ); // Timing to check on the real hardware
993 			break;
994 			case 0x4: // Clear screen
995 				screen_scanning(1);
996 				set_busy_flag( cycles_to_us( bitplane_xres*bitplane_yres ) ); // Timing to check on the real hardware
997 			break;
998 			case 0x5: // X and Y registers reset to 0
999 				set_x_reg(0);
1000 				set_y_reg(0);
1001 				set_busy_flag( cycles_to_us( 4 ) ); // Timing to check on the real hardware
1002 			break;
1003 			case 0x6: // X and Y registers reset to 0 and clear screen
1004 				set_x_reg(0);
1005 				set_y_reg(0);
1006 				screen_scanning(1);
1007 				set_busy_flag( cycles_to_us( bitplane_xres*bitplane_yres ) ); // Timing to check on the real hardware
1008 			break;
1009 			case 0x7: // Clear screen, set CSIZE to code "minsize". All other registers reset to 0
1010 				m_registers[EF936X_REG_CSIZE] = 0x11;
1011 				screen_scanning(1);
1012 				set_busy_flag( cycles_to_us( bitplane_xres*bitplane_yres ) ); // Timing to check on the real hardware
1013 			break;
1014 			case 0x8: // Light-pen initialization (/White forced low)
1015 				set_busy_flag( cycles_to_us( 4 ) ); // Timing to check on the real hardware
1016 			break;
1017 			case 0x9: // Light-pen initialization
1018 				set_busy_flag( cycles_to_us( 4 ) ); // Timing to check on the real hardware
1019 			break;
1020 			case 0xA: // 5x8 block drawing (size according to CSIZE)
1021 				busy_cycles = draw_character( 0x00 , 1 , 0 );
1022 				set_busy_flag( cycles_to_us( busy_cycles ) );
1023 			break;
1024 			case 0xB: // 4x4 block drawing (size according to CSIZE)
1025 				busy_cycles = draw_character( 0x00 , 1 , 1 );
1026 				set_busy_flag( cycles_to_us( busy_cycles ) );
1027 			break;
1028 			case 0xC: // Screen scanning : pen or Eraser as defined by CTRL1
1029 				screen_scanning(0);
1030 				set_busy_flag( cycles_to_us( bitplane_xres*bitplane_yres ) ); // Timing to check on the real hardware
1031 			break;
1032 			case 0xD: // X  reset to 0
1033 				set_x_reg(0);
1034 				set_busy_flag( cycles_to_us( 4 ) ); // Timing to check on the real hardware
1035 			break;
1036 			case 0xE: // Y  reset to 0
1037 				set_y_reg(0);
1038 				set_busy_flag( cycles_to_us( 4 ) ); // Timing to check on the real hardware
1039 			break;
1040 			case 0xF: // Direct image memory access request for the next free cycle.
1041 				set_busy_flag( cycles_to_us( 64 ) ); // Timing to check on the real hardware
1042 				dump_bitplanes_word();
1043 			break;
1044 			default:
1045 				logerror("Unemulated EF9365 cmd: %02x\n", cmd);
1046 		}
1047 	}
1048 	else
1049 	{
1050 		if ( ( cmd>>4 ) == 1 )
1051 		{
1052 			if( cmd & 0x08 )
1053 				LOG("EF9365 Command : [0x%.2X] %s\n", cmd, commands_names[0x11]);
1054 			else
1055 				LOG("EF9365 Command : [0x%.2X] %s\n", cmd, commands_names[0x10]);
1056 
1057 			tmp_delta_x = m_registers[EF936X_REG_DELTAX];
1058 			tmp_delta_y = m_registers[EF936X_REG_DELTAY];
1059 
1060 			if( cmd & 0x08 )
1061 			{
1062 				if(tmp_delta_x > tmp_delta_y )
1063 					tmp_delta_y = tmp_delta_x;
1064 				if(tmp_delta_y > tmp_delta_x )
1065 					tmp_delta_y = tmp_delta_x;
1066 			}
1067 
1068 			// Vector / Special direction vector generation
1069 			switch ( cmd & 0x7 ) // Direction code
1070 			{
1071 				case 0x1:
1072 					busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(),  tmp_delta_x,  tmp_delta_y );
1073 				break;
1074 				case 0x3:
1075 					busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), -tmp_delta_x,  tmp_delta_y );
1076 				break;
1077 				case 0x5:
1078 					busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(),  tmp_delta_x, -tmp_delta_y );
1079 				break;
1080 				case 0x7:
1081 					busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), -tmp_delta_x, -tmp_delta_y );
1082 				break;
1083 
1084 				case 0x0:
1085 					busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(),  tmp_delta_x, 0 );
1086 				break;
1087 				case 0x2:
1088 					busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), 0, tmp_delta_y );
1089 				break;
1090 				case 0x4:
1091 					busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), 0, -tmp_delta_y );
1092 				break;
1093 				case 0x6:
1094 					busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), -tmp_delta_x , 0 );
1095 				break;
1096 			}
1097 			set_busy_flag( cycles_to_us( busy_cycles ) );
1098 		}
1099 		else
1100 		{
1101 			if( ( cmd>>4 ) >= 0x8 )
1102 			{
1103 				LOG("EF9365 Command : [0x%.2X] %s\n", cmd, commands_names[0x13]);
1104 
1105 				tmp_delta_x = ( cmd >> 5 ) & 3;
1106 				tmp_delta_y = ( cmd >> 3 ) & 3;
1107 
1108 				// Small vector.
1109 				switch ( cmd & 0x7 ) // Direction code
1110 				{
1111 					case 0x1:
1112 						busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(),  tmp_delta_x,  tmp_delta_y );
1113 					break;
1114 					case 0x3:
1115 						busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), -tmp_delta_x,  tmp_delta_y );
1116 					break;
1117 					case 0x5:
1118 						busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(),  tmp_delta_x, -tmp_delta_y );
1119 					break;
1120 					case 0x7:
1121 						busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), -tmp_delta_x, -tmp_delta_y );
1122 					break;
1123 
1124 					case 0x0:
1125 						busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), tmp_delta_x, 0 );
1126 					break;
1127 					case 0x2:
1128 						busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), 0,  tmp_delta_y );
1129 					break;
1130 					case 0x4:
1131 						busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), 0, -tmp_delta_y );
1132 					break;
1133 					case 0x6:
1134 						busy_cycles = draw_vector   ( get_x_reg(), get_y_reg(), -tmp_delta_x, 0 );
1135 					break;
1136 				}
1137 
1138 				set_busy_flag( cycles_to_us( busy_cycles ) );
1139 			}
1140 			else
1141 			{
1142 				// Draw character
1143 
1144 				LOG("EF9365 Command : [0x%.2X] %s\n", cmd, commands_names[0x12]);
1145 
1146 				busy_cycles = draw_character( cmd - 0x20, 0 , 0 );
1147 				set_busy_flag( cycles_to_us( busy_cycles ) );
1148 			}
1149 		}
1150 	}
1151 }
1152 
1153 //-------------------------------------------------
1154 // screen_update: Framebuffer video output
1155 //-------------------------------------------------
1156 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)1157 uint32_t ef9365_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1158 {
1159 	for(int j=0;j<bitplane_yres;j++)
1160 	{
1161 		for(int i=0;i<bitplane_xres;i++)
1162 		{
1163 			unsigned char color_index = 0x00;
1164 
1165 			int ptr = ( bitplane_xres * j ) + i;
1166 
1167 			for(int p = 0; p < nb_of_bitplanes; p++)
1168 			{
1169 				if( m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (ptr>>3)) & (0x80>>(ptr&7)))
1170 				{
1171 					color_index |= (0x01<<p);
1172 				}
1173 			}
1174 
1175 			m_screen_out.pix(j, i) = m_palette->pen( color_index );
1176 		}
1177 	}
1178 
1179 	copybitmap(bitmap, m_screen_out, 0, 0, 0, 0, cliprect);
1180 	return 0;
1181 }
1182 
1183 //-------------------------------------------------
1184 // update_scanline: Scanline callback
1185 //-------------------------------------------------
1186 
update_scanline(uint16_t scanline)1187 void ef9365_device::update_scanline(uint16_t scanline)
1188 {
1189 	if (scanline == vsync_scanline_pos)
1190 	{
1191 		m_state |= (0x02); // vsync
1192 		if( m_registers[EF936X_REG_CTRL1] & 0x20 )
1193 		{
1194 			m_irq_vb = 1;
1195 		}
1196 
1197 		update_interrupts();
1198 	}
1199 
1200 	if (scanline == 0)
1201 	{
1202 		m_state &= (~0x02);
1203 		draw_border(0);
1204 	}
1205 }
1206 
1207 //-------------------------------------------------
1208 // data_r: Registers read access callback
1209 //-------------------------------------------------
1210 
data_r(offs_t offset)1211 uint8_t ef9365_device::data_r(offs_t offset)
1212 {
1213 	unsigned char return_value;
1214 
1215 	switch(offset & 0xF)
1216 	{
1217 		case EF936X_REG_STATUS:
1218 			if (m_bf)
1219 				m_state &= (~0x04);
1220 			else
1221 				m_state |= 0x04;
1222 
1223 			if ( ( overflow_mask_x & get_x_reg() ) || ( overflow_mask_y & get_y_reg() ) )
1224 			{
1225 				m_state |= 0x08;
1226 			}
1227 
1228 			if( m_irq_vb || m_irq_lb || m_irq_rdy )
1229 			{
1230 				m_state |= 0x80;
1231 			}
1232 
1233 			if( m_irq_lb )
1234 			{
1235 				m_state |= 0x10;
1236 				m_irq_lb = 0;
1237 			}
1238 
1239 			if( m_irq_vb )
1240 			{
1241 				m_state |= 0x20;
1242 				m_irq_vb = 0;
1243 			}
1244 
1245 			if( m_irq_rdy )
1246 			{
1247 				m_state |= 0x40;
1248 				m_irq_rdy = 0;
1249 			}
1250 
1251 			update_interrupts();
1252 
1253 			return_value = m_state;
1254 		break;
1255 		case EF936X_REG_CTRL1:
1256 			return_value = m_registers[EF936X_REG_CTRL1] & 0x7F;
1257 		break;
1258 		case EF936X_REG_CTRL2:
1259 			return_value = m_registers[EF936X_REG_CTRL2] & 0x0F;
1260 		break;
1261 		case EF936X_REG_CSIZE:
1262 			return_value = m_registers[EF936X_REG_CSIZE];
1263 		break;
1264 		case EF936X_REG_DELTAX:
1265 			return_value = m_registers[EF936X_REG_DELTAX];
1266 		break;
1267 		case EF936X_REG_DELTAY:
1268 			return_value = m_registers[EF936X_REG_DELTAY];
1269 		break;
1270 		case EF936X_REG_X_MSB:
1271 			return_value = m_registers[EF936X_REG_X_MSB] & 0x0F;
1272 		break;
1273 		case EF936X_REG_X_LSB:
1274 			return_value = m_registers[EF936X_REG_X_LSB];
1275 		break;
1276 		case EF936X_REG_Y_MSB:
1277 			return_value = m_registers[EF936X_REG_Y_MSB] & 0x0F;
1278 		break;
1279 		case EF936X_REG_Y_LSB:
1280 			return_value = m_registers[EF936X_REG_Y_LSB];
1281 		break;
1282 		case EF936X_REG_XLP:
1283 			return_value = m_registers[EF936X_REG_XLP] & 0xFD;
1284 		break;
1285 		case EF936X_REG_YLP:
1286 			return_value = m_registers[EF936X_REG_YLP];
1287 		break;
1288 		default:
1289 			return_value = 0xFF;
1290 		break;
1291 	}
1292 
1293 	LOG("EF9365 [ %s ] RD> [ 0x%.2X ] - %s\n", register_names[offset&0xF],return_value, machine().describe_context() );
1294 
1295 	return return_value;
1296 }
1297 
1298 //-------------------------------------------------
1299 // data_w: Registers write access callback
1300 //-------------------------------------------------
1301 
data_w(offs_t offset,uint8_t data)1302 void ef9365_device::data_w(offs_t offset, uint8_t data)
1303 {
1304 	LOG("EF9365 [ %s ] <WR [ 0x%.2X ] - %s\n", register_names[offset&0xF],data, machine().describe_context() );
1305 
1306 	switch(offset & 0xF)
1307 	{
1308 		case EF936X_REG_CMD:
1309 			ef9365_exec( data & 0xff);
1310 		break;
1311 		case EF936X_REG_CTRL1:
1312 			m_registers[EF936X_REG_CTRL1] = data & 0x7F;
1313 		break;
1314 		case EF936X_REG_CTRL2:
1315 			m_registers[EF936X_REG_CTRL2] = data & 0x0F;
1316 		break;
1317 		case EF936X_REG_CSIZE:
1318 			m_registers[EF936X_REG_CSIZE] = data;
1319 		break;
1320 		case EF936X_REG_DELTAX:
1321 			m_registers[EF936X_REG_DELTAX] = data;
1322 		break;
1323 		case EF936X_REG_DELTAY:
1324 			m_registers[EF936X_REG_DELTAY] = data;
1325 		break;
1326 		case EF936X_REG_X_MSB:
1327 			m_registers[EF936X_REG_X_MSB] = data & 0x0F;
1328 		break;
1329 		case EF936X_REG_X_LSB:
1330 			m_registers[EF936X_REG_X_LSB] = data;
1331 		break;
1332 		case EF936X_REG_Y_MSB:
1333 			m_registers[EF936X_REG_Y_MSB] = data & 0x0F;
1334 		break;
1335 		case EF936X_REG_Y_LSB:
1336 			m_registers[EF936X_REG_Y_LSB] = data;
1337 		break;
1338 		case EF936X_REG_XLP:
1339 		break;
1340 		case EF936X_REG_YLP:
1341 		break;
1342 		default:
1343 		break;
1344 	}
1345 }
1346