summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/video
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2012-08-21 10:41:19 +0000
committer Miodrag Milanovic <mmicko@gmail.com>2012-08-21 10:41:19 +0000
commit7285b359d259b2ae0fdf85096571c386ec8c991a (patch)
treea027aff57f1a255f9ec6cfd3b68cabe4b6683998 /src/mess/video
parent67c425e90757876a6716b7867df30c0149912e74 (diff)
Merge of MESS sources (no whatsnew)
Diffstat (limited to 'src/mess/video')
-rw-r--r--src/mess/video/733_asr.c746
-rw-r--r--src/mess/video/733_asr.h95
-rw-r--r--src/mess/video/911_chr.h3516
-rw-r--r--src/mess/video/911_key.h4026
-rw-r--r--src/mess/video/911_vdt.c701
-rw-r--r--src/mess/video/911_vdt.h163
-rw-r--r--src/mess/video/a7800.c584
-rw-r--r--src/mess/video/abc1600.c1130
-rw-r--r--src/mess/video/abc80.c224
-rw-r--r--src/mess/video/abc800.c380
-rw-r--r--src/mess/video/abc802.c255
-rw-r--r--src/mess/video/abc806.c554
-rw-r--r--src/mess/video/ac1.c61
-rw-r--r--src/mess/video/advision.c115
-rw-r--r--src/mess/video/apollo.c882
-rw-r--r--src/mess/video/apple1.c401
-rw-r--r--src/mess/video/apple2.c537
-rw-r--r--src/mess/video/apple2gs.c164
-rw-r--r--src/mess/video/apple3.c401
-rw-r--r--src/mess/video/aquarius.c104
-rw-r--r--src/mess/video/arcadia.c682
-rw-r--r--src/mess/video/atarist.c1182
-rw-r--r--src/mess/video/atarist.h39
-rw-r--r--src/mess/video/avigo.c117
-rw-r--r--src/mess/video/b2m.c59
-rw-r--r--src/mess/video/bbc.c694
-rw-r--r--src/mess/video/bk.c39
-rw-r--r--src/mess/video/busicom.c1859
-rw-r--r--src/mess/video/cbmb.c100
-rw-r--r--src/mess/video/cgc7900.c255
-rw-r--r--src/mess/video/cgenie.c422
-rw-r--r--src/mess/video/channelf.c71
-rw-r--r--src/mess/video/cirrus.c233
-rw-r--r--src/mess/video/cirrus.h38
-rw-r--r--src/mess/video/comquest.c22
-rw-r--r--src/mess/video/comx35.c152
-rw-r--r--src/mess/video/crt.c223
-rw-r--r--src/mess/video/crt.h33
-rw-r--r--src/mess/video/crtc_ega.c695
-rw-r--r--src/mess/video/crtc_ega.h226
-rw-r--r--src/mess/video/dai.c768
-rw-r--r--src/mess/video/dgn_beta.c303
-rw-r--r--src/mess/video/dl1416.c325
-rw-r--r--src/mess/video/dl1416.h75
-rw-r--r--src/mess/video/ef9345.c1038
-rw-r--r--src/mess/video/ef9345.h123
-rw-r--r--src/mess/video/electron.c274
-rw-r--r--src/mess/video/epnick.c1044
-rw-r--r--src/mess/video/fm7.c1613
-rw-r--r--src/mess/video/fmtowns.c1867
-rw-r--r--src/mess/video/galaxy.c137
-rw-r--r--src/mess/video/galeb.c45
-rw-r--r--src/mess/video/gamecom.c72
-rw-r--r--src/mess/video/gb.c2392
-rw-r--r--src/mess/video/gba.c1811
-rw-r--r--src/mess/video/gbam345.c399
-rw-r--r--src/mess/video/gbamode0.c585
-rw-r--r--src/mess/video/gbamode1.c525
-rw-r--r--src/mess/video/gbamode2.c465
-rw-r--r--src/mess/video/gf4500.c172
-rw-r--r--src/mess/video/gf4500.h18
-rw-r--r--src/mess/video/gime.c2044
-rw-r--r--src/mess/video/gime.h297
-rw-r--r--src/mess/video/hd44352.c456
-rw-r--r--src/mess/video/hd44352.h87
-rw-r--r--src/mess/video/hd44780.c344
-rw-r--r--src/mess/video/hd44780.h96
-rw-r--r--src/mess/video/hd66421.c254
-rw-r--r--src/mess/video/hd66421.h80
-rw-r--r--src/mess/video/hec2video.c144
-rw-r--r--src/mess/video/hp48.c202
-rw-r--r--src/mess/video/intv.c855
-rw-r--r--src/mess/video/iq151_grafik.c198
-rw-r--r--src/mess/video/iq151_grafik.h62
-rw-r--r--src/mess/video/iq151_video32.c148
-rw-r--r--src/mess/video/iq151_video32.h46
-rw-r--r--src/mess/video/iq151_video64.c156
-rw-r--r--src/mess/video/iq151_video64.h47
-rw-r--r--src/mess/video/irisha.c43
-rw-r--r--src/mess/video/isa_cga.c2035
-rw-r--r--src/mess/video/isa_cga.h187
-rw-r--r--src/mess/video/isa_ega.c1408
-rw-r--r--src/mess/video/isa_ega.h106
-rw-r--r--src/mess/video/isa_mda.c740
-rw-r--r--src/mess/video/isa_mda.h91
-rw-r--r--src/mess/video/isa_svga_cirrus.c93
-rw-r--r--src/mess/video/isa_svga_cirrus.h36
-rw-r--r--src/mess/video/isa_svga_s3.c93
-rw-r--r--src/mess/video/isa_svga_s3.h36
-rw-r--r--src/mess/video/isa_svga_tseng.c91
-rw-r--r--src/mess/video/isa_svga_tseng.h36
-rw-r--r--src/mess/video/k1ge.c928
-rw-r--r--src/mess/video/k1ge.h44
-rw-r--r--src/mess/video/kaypro.c320
-rw-r--r--src/mess/video/kc.c236
-rw-r--r--src/mess/video/kramermc.c45
-rw-r--r--src/mess/video/kyocera.c84
-rw-r--r--src/mess/video/llc.c97
-rw-r--r--src/mess/video/lviv.c91
-rw-r--r--src/mess/video/mac.c1063
-rw-r--r--src/mess/video/mbc55x.c201
-rw-r--r--src/mess/video/mbee.c638
-rw-r--r--src/mess/video/mc68328.c66
-rw-r--r--src/mess/video/mc6847.c1627
-rw-r--r--src/mess/video/mc6847.h631
-rw-r--r--src/mess/video/mc80.c174
-rw-r--r--src/mess/video/microtan.c58
-rw-r--r--src/mess/video/mikro80.c39
-rw-r--r--src/mess/video/mikromik.c169
-rw-r--r--src/mess/video/mos6566.c2818
-rw-r--r--src/mess/video/mos6566.h488
-rw-r--r--src/mess/video/mz700.c135
-rw-r--r--src/mess/video/mz80.c145
-rw-r--r--src/mess/video/nascom1.c61
-rw-r--r--src/mess/video/nc.c119
-rw-r--r--src/mess/video/nes.c70
-rw-r--r--src/mess/video/newbrain.c132
-rw-r--r--src/mess/video/newport.c1689
-rw-r--r--src/mess/video/newport.h15
-rw-r--r--src/mess/video/nubus_48gc.c354
-rw-r--r--src/mess/video/nubus_48gc.h61
-rw-r--r--src/mess/video/nubus_cb264.c306
-rw-r--r--src/mess/video/nubus_cb264.h48
-rw-r--r--src/mess/video/nubus_m2hires.c320
-rw-r--r--src/mess/video/nubus_m2hires.h52
-rw-r--r--src/mess/video/nubus_radiustpd.c218
-rw-r--r--src/mess/video/nubus_radiustpd.h52
-rw-r--r--src/mess/video/nubus_spec8.c360
-rw-r--r--src/mess/video/nubus_spec8.h60
-rw-r--r--src/mess/video/nubus_specpdq.c490
-rw-r--r--src/mess/video/nubus_specpdq.h58
-rw-r--r--src/mess/video/nubus_vikbw.c178
-rw-r--r--src/mess/video/nubus_vikbw.h48
-rw-r--r--src/mess/video/nubus_wsportrait.c316
-rw-r--r--src/mess/video/nubus_wsportrait.h52
-rw-r--r--src/mess/video/odyssey2.c827
-rw-r--r--src/mess/video/ondra.c48
-rw-r--r--src/mess/video/orao.c40
-rw-r--r--src/mess/video/oric.c308
-rw-r--r--src/mess/video/orion.c116
-rw-r--r--src/mess/video/osi.c182
-rw-r--r--src/mess/video/p2000m.c60
-rw-r--r--src/mess/video/pc1251.c167
-rw-r--r--src/mess/video/pc1350.c170
-rw-r--r--src/mess/video/pc1401.c218
-rw-r--r--src/mess/video/pc1403.c264
-rw-r--r--src/mess/video/pc1512.c646
-rw-r--r--src/mess/video/pc1640.c401
-rw-r--r--src/mess/video/pc4.c194
-rw-r--r--src/mess/video/pc8401a.c114
-rw-r--r--src/mess/video/pc_aga.c879
-rw-r--r--src/mess/video/pc_aga.h43
-rw-r--r--src/mess/video/pc_t1t.c975
-rw-r--r--src/mess/video/pc_t1t.h10
-rw-r--r--src/mess/video/pcw.c188
-rw-r--r--src/mess/video/pcw16.c265
-rw-r--r--src/mess/video/pdp1.c609
-rw-r--r--src/mess/video/pecom.c121
-rw-r--r--src/mess/video/pet.c113
-rw-r--r--src/mess/video/pk8020.c58
-rw-r--r--src/mess/video/pmd85.c66
-rw-r--r--src/mess/video/pocketc.c70
-rw-r--r--src/mess/video/poly88.c103
-rw-r--r--src/mess/video/pp01.c57
-rw-r--r--src/mess/video/primo.c46
-rw-r--r--src/mess/video/psion.c107
-rw-r--r--src/mess/video/radio86.c129
-rw-r--r--src/mess/video/rm380z.c409
-rw-r--r--src/mess/video/rmnimbus.c679
-rw-r--r--src/mess/video/saa505x.c3581
-rw-r--r--src/mess/video/saa505x.h27
-rw-r--r--src/mess/video/samcoupe.c176
-rw-r--r--src/mess/video/sapi1.c150
-rw-r--r--src/mess/video/special.c155
-rw-r--r--src/mess/video/spectrum.c608
-rw-r--r--src/mess/video/ssystem3.c238
-rw-r--r--src/mess/video/stic.c187
-rw-r--r--src/mess/video/stic.h449
-rw-r--r--src/mess/video/super80.c469
-rw-r--r--src/mess/video/t6a04.c260
-rw-r--r--src/mess/video/t6a04.h71
-rw-r--r--src/mess/video/thomson.c1344
-rw-r--r--src/mess/video/ti85.c196
-rw-r--r--src/mess/video/timex.c262
-rw-r--r--src/mess/video/tmc1800.c123
-rw-r--r--src/mess/video/tmc600.c156
-rw-r--r--src/mess/video/tms3556.c584
-rw-r--r--src/mess/video/tms3556.h113
-rw-r--r--src/mess/video/trs80.c593
-rw-r--r--src/mess/video/tx0.c484
-rw-r--r--src/mess/video/upd7220.c1667
-rw-r--r--src/mess/video/upd7220.h233
-rw-r--r--src/mess/video/ut88.c44
-rw-r--r--src/mess/video/uv201.c603
-rw-r--r--src/mess/video/uv201.h165
-rw-r--r--src/mess/video/v1050.c147
-rw-r--r--src/mess/video/vc4000.c655
-rw-r--r--src/mess/video/vdc8563.c673
-rw-r--r--src/mess/video/vdc8563.h48
-rw-r--r--src/mess/video/vector06.c60
-rw-r--r--src/mess/video/vic4567.c2165
-rw-r--r--src/mess/video/vic4567.h157
-rw-r--r--src/mess/video/vic6567.c2815
-rw-r--r--src/mess/video/vic6567.h164
-rw-r--r--src/mess/video/vtech2.c313
-rw-r--r--src/mess/video/vtvideo.c477
-rw-r--r--src/mess/video/vtvideo.h57
-rw-r--r--src/mess/video/wswan.c584
-rw-r--r--src/mess/video/x68k.c1322
-rw-r--r--src/mess/video/z88.c173
-rw-r--r--src/mess/video/zx.c217
-rw-r--r--src/mess/video/zx8301.c346
-rw-r--r--src/mess/video/zx8301.h138
213 files changed, 94029 insertions, 0 deletions
diff --git a/src/mess/video/733_asr.c b/src/mess/video/733_asr.c
new file mode 100644
index 00000000000..dbc66b14da8
--- /dev/null
+++ b/src/mess/video/733_asr.c
@@ -0,0 +1,746 @@
+/*
+ 733 ASR emulation
+
+ We are emulating a TI Model 733 ASR ("Silent 700") data terminal,
+ interfaced through a TI asynchronous EIA/TTY interface module.
+
+ The ASR features a printer, a keyboard and a tape unit (which is not
+ emulated). The ASR is attached to the computer with a serial interface.
+
+ References:
+ 945401-9701 Model 990/4 Computer System Field Maintainance Manual p. C-1,
+ 945250-9701 990 Computer Family Systems Handbook pp. 5-9 through 5-16,
+ 0943442-9701 Model 990 Computer Reference Manual Preliminary pp. 3-13
+ through 3-21 and 3-39 through 3-44.
+
+ TODO:
+ * separate ASR emulation from EIA interface emulation?
+ * implement tape interface?
+
+ Raphael Nabet 2003
+*/
+
+#include "emu.h"
+#include "733_asr.h"
+
+enum
+{
+ /*ASROutQueueSize = 32,*/
+
+ asr_window_offset_x = 0,
+ asr_window_offset_y = 0,
+ asr_window_width = 640,
+ asr_window_height = 480,
+ asr_scroll_step = 8
+};
+
+typedef struct
+{
+#if 0
+ UINT8 OutQueue[ASROutQueueSize];
+ int OutQueueHead;
+ int OutQueueLen;
+#endif
+
+ UINT8 recv_buf;
+ UINT8 xmit_buf;
+
+ UINT8 status;
+ UINT8 mode;
+ UINT8 last_key_pressed;
+ int last_modifier_state;
+
+ unsigned char repeat_timer;
+ int new_status_flag;
+
+ int x;
+
+ void (*int_callback)(running_machine &, int state);
+
+ bitmap_ind16 *bitmap;
+} asr_t;
+
+enum
+{
+ AS_wrq_mask = 1 << 3,
+ AS_rrq_mask = 1 << 4,
+ AS_dsr_mask = 1 << 6,
+ AS_int_mask = 1 << 7,
+
+ AM_dtr_mask = 1 << 1,
+ AM_rts_mask = 1 << 2,
+ AM_enint_mask = 1 << 6
+};
+
+enum
+{
+ asrfontdata_size = 96/*128*/*8
+};
+
+static const gfx_layout fontlayout =
+{
+ 6, 8, /* 6*8 characters */
+ /*96*/128, /* 96 characters */
+ 1, /* 1 bit per pixel */
+ { 0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, /* straightforward layout */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8 /* every char takes 8 consecutive bytes */
+};
+
+GFXDECODE_START( asr733 )
+ GFXDECODE_ENTRY( asr733_chr_region, 0, fontlayout, 0, 1 )
+GFXDECODE_END
+
+PALETTE_INIT( asr733 )
+{
+ palette_set_color(machine,0,RGB_WHITE); /* white */
+ palette_set_color(machine,1,RGB_BLACK); /* black */
+}
+
+/*
+ Initialize the asr core
+*/
+void asr733_init(running_machine &machine)
+{
+ UINT8 *dst;
+
+ static const unsigned char fontdata6x8[asrfontdata_size] =
+ { /* ASCII characters */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,
+ 0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0xf8,0x50,0xf8,0x50,0x00,0x00,
+ 0x20,0x70,0xc0,0x70,0x18,0xf0,0x20,0x00,0x40,0xa4,0x48,0x10,0x20,0x48,0x94,0x08,
+ 0x60,0x90,0xa0,0x40,0xa8,0x90,0x68,0x00,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00,
+ 0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x00,0x10,0x08,0x08,0x08,0x08,0x08,0x10,0x00,
+ 0x20,0xa8,0x70,0xf8,0x70,0xa8,0x20,0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
+ 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x00,
+ 0x70,0x88,0x08,0x10,0x20,0x40,0xf8,0x00,0x70,0x88,0x08,0x30,0x08,0x88,0x70,0x00,
+ 0x10,0x30,0x50,0x90,0xf8,0x10,0x10,0x00,0xf8,0x80,0xf0,0x08,0x08,0x88,0x70,0x00,
+ 0x70,0x80,0xf0,0x88,0x88,0x88,0x70,0x00,0xf8,0x08,0x08,0x10,0x20,0x20,0x20,0x00,
+ 0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x70,0x00,
+ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,
+ 0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,
+ 0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x70,0x88,0x08,0x10,0x20,0x00,0x20,0x00,
+ 0x70,0x88,0xb8,0xa8,0xb8,0x80,0x70,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,
+ 0xf0,0x88,0x88,0xf0,0x88,0x88,0xf0,0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00,
+ 0xf0,0x88,0x88,0x88,0x88,0x88,0xf0,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,
+ 0xf8,0x80,0x80,0xf0,0x80,0x80,0x80,0x00,0x70,0x88,0x80,0x98,0x88,0x88,0x70,0x00,
+ 0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,
+ 0x08,0x08,0x08,0x08,0x88,0x88,0x70,0x00,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00,0x88,0xd8,0xa8,0x88,0x88,0x88,0x88,0x00,
+ 0x88,0xc8,0xa8,0x98,0x88,0x88,0x88,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,
+ 0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x08,
+ 0xf0,0x88,0x88,0xf0,0x88,0x88,0x88,0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00,
+ 0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,
+ 0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00,0x88,0x88,0x88,0x88,0xa8,0xd8,0x88,0x00,
+ 0x88,0x50,0x20,0x20,0x20,0x50,0x88,0x00,0x88,0x88,0x88,0x50,0x20,0x20,0x20,0x00,
+ 0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00,0x30,0x20,0x20,0x20,0x20,0x20,0x30,0x00,
+ 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x30,0x10,0x10,0x10,0x10,0x10,0x30,0x00,
+ 0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,
+ 0x40,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x08,0x78,0x88,0x78,0x00,
+ 0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x00,0x00,0x00,0x70,0x88,0x80,0x80,0x78,0x00,
+ 0x08,0x08,0x78,0x88,0x88,0x88,0x78,0x00,0x00,0x00,0x70,0x88,0xf8,0x80,0x78,0x00,
+ 0x18,0x20,0x70,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x70,
+ 0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x00,
+ 0x20,0x00,0x20,0x20,0x20,0x20,0x20,0xc0,0x80,0x80,0x90,0xa0,0xe0,0x90,0x88,0x00,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xf0,0xa8,0xa8,0xa8,0xa8,0x00,
+ 0x00,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,
+ 0x00,0x00,0xf0,0x88,0x88,0xf0,0x80,0x80,0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x08,
+ 0x00,0x00,0xb0,0xc8,0x80,0x80,0x80,0x00,0x00,0x00,0x78,0x80,0x70,0x08,0xf0,0x00,
+ 0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00,
+ 0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00,0x00,0x00,0xa8,0xa8,0xa8,0xa8,0x50,0x00,
+ 0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00,0x00,0x88,0x88,0x88,0x78,0x08,0x70,
+ 0x00,0x00,0xf8,0x10,0x20,0x40,0xf8,0x00,0x08,0x10,0x10,0x20,0x10,0x10,0x08,0x00,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00,
+ 0x00,0x68,0xb0,0x00,0x00,0x00,0x00,0x00,0x20,0x50,0x20,0x50,0xa8,0x50,0x00,0x00
+ };
+
+ dst = machine.root_device().memregion(asr733_chr_region)->base();
+
+ memcpy(dst, fontdata6x8, asrfontdata_size);
+}
+
+INLINE asr_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == ASR733);
+
+ return (asr_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+static DEVICE_START( asr733 )
+{
+ asr_t *asr = get_safe_token(device);
+ const asr733_init_params_t *params = (const asr733_init_params_t *)device->static_config();
+ screen_device *screen = device->machine().first_screen();
+ int width = screen->width();
+ int height = screen->height();
+ const rectangle &visarea = screen->visible_area();
+
+ asr->last_key_pressed = 0x80;
+ asr->bitmap = auto_bitmap_ind16_alloc(device->machine(), width, height);
+
+ asr->bitmap->fill(0, visarea);
+
+ asr->int_callback = params->int_callback;
+}
+
+static void asr_field_interrupt(device_t *device)
+{
+ asr_t *asr = get_safe_token(device);
+ if ((asr->mode & AM_enint_mask) && (asr->new_status_flag)) /* right??? */
+ {
+ asr->status |= AS_int_mask;
+ if (asr->int_callback)
+ (*asr->int_callback)(device->machine(), 1);
+ }
+ else
+ {
+ asr->status &= ~AS_int_mask;
+ if (asr->int_callback)
+ (*asr->int_callback)(device->machine(), 0);
+ }
+}
+
+static DEVICE_RESET( asr733 )
+{
+ asr_t *asr = get_safe_token(device);
+
+ /*asr->OutQueueLen = 0;*/
+
+ asr->status = AS_dsr_mask | AS_wrq_mask;
+ asr->mode = 0;
+
+ asr_field_interrupt(device);
+}
+
+DEVICE_GET_INFO( asr733 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(asr_t); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(asr733); break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(asr733); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "733 ASR"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "733 ASR Video"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(ASR733, asr733);
+
+/* write a single char on screen */
+static void asr_draw_char(device_t *device, int character, int x, int y, int color)
+{
+ asr_t *asr = get_safe_token(device);
+
+ drawgfx_opaque(*asr->bitmap, asr->bitmap->cliprect(), device->machine().gfx[0], character-32, color, 0, 0,
+ x+1, y);
+}
+
+static void asr_linefeed(device_t *device)
+{
+ asr_t *asr = get_safe_token(device);
+ UINT8 buf[asr_window_width];
+ int y;
+
+ for (y=asr_window_offset_y; y<asr_window_offset_y+asr_window_height-asr_scroll_step; y++)
+ {
+ extract_scanline8(*asr->bitmap, asr_window_offset_x, y+asr_scroll_step, asr_window_width, buf);
+ draw_scanline8(*asr->bitmap, asr_window_offset_x, y, asr_window_width, buf, device->machine().pens);
+ }
+
+ const rectangle asr_scroll_clear_window(
+ asr_window_offset_x, /* min_x */
+ asr_window_offset_x+asr_window_width-1, /* max_x */
+ asr_window_offset_y+asr_window_height-asr_scroll_step, /* min_y */
+ asr_window_offset_y+asr_window_height-1 /* max_y */
+ );
+ asr->bitmap->fill(0, asr_scroll_clear_window);
+}
+
+static void asr_transmit(device_t *device, UINT8 data)
+{
+ asr_t *asr = get_safe_token(device);
+
+ switch (data)
+ {
+ /* aux device control chars */
+ case 0x05:
+ /* ENQ -> "WRU": ??? */
+ break;
+
+ case 0x11:
+ /* DC1 -> "X-ON": transmit on??? */
+ break;
+
+ case 0x12:
+ /* DC2 -> "X-OFF": transmit off??? */
+ break;
+
+ case 0x13:
+ /* DC3 -> "TAPE": tape on??? */
+ break;
+
+ case 0x14:
+ /* DC4 -> "-T-A-P-E-" ("TAPE" with overstrike): tape off??? */
+ break;
+
+
+ /* printer control chars */
+ case 0x07:
+ /* BELL: 250ms beep */
+ break;
+
+ case 0x08:
+ /* BS: backspace */
+ if (asr->x > 0)
+ asr->x--;
+ break;
+
+ case 0x0A:
+ /* LF: line feed */
+ asr_linefeed(device);
+ break;
+
+ case 0x0D:
+ /* CR: carriage return */
+ asr->x = 0;
+ break;
+
+
+ default:
+ if ((data < 0x20) || (data == 0x7f) || (data >= 0x80))
+ /* ignore control characters */
+ break;
+
+ if (asr->x == 80)
+ {
+ asr->x = 0;
+ asr_linefeed(device);
+ }
+ asr_draw_char(device, data, asr_window_offset_x+asr->x*8, asr_window_offset_y+asr_window_height-8, 0);
+ asr->x++;
+ break;
+ }
+
+ asr->status |= AS_wrq_mask;
+ asr->new_status_flag = 1; /* right??? */
+ asr_field_interrupt(device);
+}
+
+#if 0
+static void asr_receive_callback(int dummy)
+{
+ asr_t *asr = get_safe_token(device);
+ (void) dummy;
+
+ asr->recv_buf = asr->OutQueue[asr->OutQueueHead];
+ asr->OutQueueHead = (asr->OutQueueHead + 1) % ASROutQueueSize;
+ asr->OutQueueLen--;
+
+ asr->status |= AS_rrq_mask;
+ asr->new_status_flag = 1; /* right??? */
+ asr_field_interrupt(device);
+}
+#endif
+
+/*
+ 0-7: receive buffer
+ 8: XMITING transmit in progress, 1 if transmitting
+ 9: TIMERR timing error, 1 if error
+ 10: RCR reverse channel receive, not used
+ "ASR733/33 ID" 1 -> TTY (???) (2270509-9701 pp. G-9 & G-10)
+ 11: WRQ write request, 1 if ready to transmit
+ 12: RRQ read request, 1 if ready to receive
+ 13: DCD data carrier detect, not used
+ 14: DSR data set ready, 1 if online
+ 15: INT interrupt, 1 if interrupt
+*/
+READ8_DEVICE_HANDLER( asr733_cru_r )
+{
+ asr_t *asr = get_safe_token(device);
+ int reply = 0;
+
+ switch (offset)
+ {
+ case 0:
+ /* receive buffer */
+ reply = asr->recv_buf;
+ break;
+
+ case 1:
+ /* status register */
+ reply = asr->status;
+ break;
+ }
+
+ return reply;
+}
+
+/*
+ 0-7: transmit buffer
+ 8: not used
+ 9: DTR data terminal ready (set to 1)
+ 10: RTS request to send (set to 1)
+ 11: CLRWRQ clear write request (write any value to execute)
+ 12: CLRRRQ clear read request (write any value to execute)
+ 13: CLRNSF clear new status flag - clear DSR/DCD interrupts (write any value to execute)
+ 14: enable interrupts, 1 to enable interrupts
+ 15: diagnostic mode, 0 for normal mode
+*/
+WRITE8_DEVICE_HANDLER( asr733_cru_w )
+{
+ asr_t *asr = get_safe_token(device);
+
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ /* transmit buffer */
+ if (data)
+ asr->xmit_buf |= 1 << offset;
+ else
+ asr->xmit_buf &= ~ (1 << offset);
+ if ((offset == 7) && (asr->mode & AM_dtr_mask) && (asr->mode & AM_rts_mask)) /* right??? */
+ asr_transmit(device, asr->xmit_buf);
+ break;
+
+ case 8: /* not used */
+ break;
+
+ case 9: /* data terminal ready (set to 1) */
+ case 10: /* request to send (set to 1) */
+ case 14: /* enable interrupts, 1 to enable interrupts */
+ case 15: /* diagnostic mode, 0 for normal mode */
+ if (data)
+ asr->mode |= 1 << (offset - 8);
+ else
+ asr->mode &= ~ (1 << (offset - 8));
+ if (offset == 14)
+ asr_field_interrupt(device);
+ break;
+
+ case 11: /* clear write request (write any value to execute) */
+ case 12: /* clear read request (write any value to execute) */
+ asr->status &= ~ (1 << (offset - 8));
+ asr_field_interrupt(device);
+ break;
+
+ case 13: /* clear new status flag - whatever it means (write any value to execute) */
+ asr->new_status_flag = 0;
+ asr_field_interrupt(device);
+ break;
+ }
+}
+
+/*
+ Video refresh
+*/
+void asr733_refresh(device_t *device, bitmap_ind16 &bitmap, int x, int y)
+{
+ asr_t *asr = get_safe_token(device);
+ copybitmap(bitmap, *asr->bitmap, 0, 0, x, y, asr->bitmap->cliprect());
+}
+
+
+static const unsigned char key_translate[3][51] =
+{
+ { /* unshifted */
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '0',
+ ':',
+ '-',
+
+ 0x1b,
+ 'Q',
+ 'W',
+ 'E',
+ 'R',
+ 'T',
+ 'Y',
+ 'U',
+ 'I',
+ 'O',
+ 'P',
+ 0x0a,
+ 0x0d,
+
+ 0,
+ 'A',
+ 'S',
+ 'D',
+ 'F',
+ 'G',
+ 'H',
+ 'J',
+ 'K',
+ 'L',
+ ';',
+ 0x08,
+ 0,
+
+ 0,
+ 'Z',
+ 'X',
+ 'C',
+ 'V',
+ 'B',
+ 'N',
+ 'M',
+ ',',
+ '.',
+ '/',
+ 0,
+
+ ' '
+ },
+ { /* shifted */
+ '!',
+ '"',
+ '#',
+ '$',
+ '%',
+ '&',
+ '^',
+ '(',
+ ')',
+ ' ',
+ '*',
+ '=',
+
+ 0x1b,
+ 'Q',
+ 'W',
+ 'E',
+ 'R',
+ 'T',
+ 'Y',
+ 'U',
+ 'I',
+ '_',
+ '@',
+ 0x0a,
+ 0x0d,
+
+ 0,
+ 'A',
+ 'S',
+ 'D',
+ 'F',
+ 'G',
+ 'H',
+ 'J',
+ 0,
+ '/',
+ '+',
+ 0x08,
+ 0,
+
+ 0,
+ 'Z',
+ 'X',
+ 'C',
+ 'V',
+ 'B',
+ '^',
+ '|',
+ '<',
+ '>',
+ '?',
+ 0,
+
+ ' '
+ },
+ { /* control */
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '0',
+ ':',
+ '-',
+
+ 0x1b,
+ 0x11,
+ 0x17,
+ 0x05,
+ 0x12,
+ 0x14,
+ 0x19,
+ 0x15,
+ 0x09,
+ 0x0f,
+ 0x10,
+ 0x0a,
+ 0x0d,
+
+ 0,
+ 0x01,
+ 0x13,
+ 0x04,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x0a,
+ 0x0b,
+ 0x0c,
+ ';',
+ 0x08,
+ 0,
+
+ 0,
+ 0x1a,
+ 0x18,
+ 0x03,
+ 0x16,
+ 0x02,
+ 0x0e,
+ 0x0d,
+ ',',
+ '.',
+ '/',
+ 0,
+
+ ' '
+ }
+};
+
+
+/*
+ keyboard handler: should be called regularly by machine code, for instance
+ every Video Blank Interrupt.
+*/
+void asr733_keyboard(device_t *device)
+{
+ asr_t *asr = get_safe_token(device);
+ typedef enum
+ {
+ /* key modifier states */
+ unshifted = 0, shift, control,
+ /* special value to stop repeat if the modifier state changes */
+ special_debounce = -1
+ } modifier_state_t;
+
+ enum { repeat_delay = 5 /* approx. 1/10s */ };
+
+ UINT16 key_buf[6];
+ int i, j;
+ modifier_state_t modifier_state;
+ int repeat_mode;
+
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3" };
+
+ /* read current key state */
+ /* 2008-05 FP: in 733_asr.h there are only 4 input ports defined... */
+ /* for (i = 0; i < 6; i++) */
+ for (i = 0; i < 4; i++)
+ {
+ key_buf[i] = device->machine().root_device().ioport(keynames[i])->read();
+ }
+
+ /* process key modifiers */
+ if (key_buf[1] & 0x0200)
+ modifier_state = control;
+ else if ((key_buf[2] & 0x0040) || (key_buf[3] & 0x0002))
+ modifier_state = shift;
+ else
+ modifier_state = unshifted;
+
+ /* test repeat key */
+ repeat_mode = key_buf[2] & 0x0020;
+
+ /* remove modifier keys */
+ key_buf[1] &= ~0x0200;
+ key_buf[2] &= ~0x0060;
+ key_buf[3] &= ~0x0002;
+
+ if (! repeat_mode)
+ /* reset REPEAT timer if the REPEAT key is not pressed */
+ asr->repeat_timer = 0;
+
+ if ( ! (asr->last_key_pressed & 0x80) && (key_buf[asr->last_key_pressed >> 4] & (1 << (asr->last_key_pressed & 0xf))))
+ {
+ /* last key has not been released */
+ if (modifier_state == asr->last_modifier_state)
+ {
+ /* handle REPEAT mode if applicable */
+ if ((repeat_mode) && (++asr->repeat_timer == repeat_delay))
+ {
+ if (asr->status & AS_rrq_mask)
+ { /* keyboard buffer full */
+ asr->repeat_timer--;
+ }
+ else
+ { /* repeat current key */
+ asr->status |= AS_rrq_mask;
+ asr->new_status_flag = 1; /* right??? */
+ asr_field_interrupt(device);
+ asr->repeat_timer = 0;
+ }
+ }
+ }
+ else
+ {
+ asr->repeat_timer = 0;
+ asr->last_modifier_state = special_debounce;
+ }
+ }
+ else
+ {
+ asr->last_key_pressed = 0x80;
+
+ if (asr->status & AS_rrq_mask)
+ { /* keyboard buffer full */
+ /* do nothing */
+ }
+ else
+ {
+ for (i=0; i<6; i++)
+ {
+ for (j=0; j<16; j++)
+ {
+ if (key_buf[i] & (1 << j))
+ {
+ asr->last_key_pressed = (i << 4) | j;
+ asr->last_modifier_state = modifier_state;
+
+ asr->recv_buf = (int)key_translate[modifier_state][asr->last_key_pressed];
+ asr->status |= AS_rrq_mask;
+ asr->new_status_flag = 1; /* right??? */
+ asr_field_interrupt(device);
+ return;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/mess/video/733_asr.h b/src/mess/video/733_asr.h
new file mode 100644
index 00000000000..643cdca3a05
--- /dev/null
+++ b/src/mess/video/733_asr.h
@@ -0,0 +1,95 @@
+
+#define asr733_chr_region "gfx1"
+
+enum
+{
+ /* 8 bytes per character definition */
+ asr733_single_char_len = 8,
+
+ asr733_chr_region_len = 128*asr733_single_char_len
+};
+
+typedef struct asr733_init_params_t
+{
+ void (*int_callback)(running_machine &machine, int state);
+} asr733_init_params_t;
+
+GFXDECODE_EXTERN( asr733 );
+
+PALETTE_INIT( asr733 );
+
+void asr733_init(running_machine &machine);
+DECLARE_LEGACY_DEVICE(ASR733, asr733);
+
+#define MCFG_ASR733_VIDEO_ADD(_tag, _intf) \
+ MCFG_DEVICE_ADD(_tag, ASR733, 0) \
+ MCFG_DEVICE_CONFIG(_intf)
+
+READ8_DEVICE_HANDLER(asr733_cru_r);
+WRITE8_DEVICE_HANDLER(asr733_cru_w);
+
+void asr733_refresh(device_t *device, bitmap_ind16 &bitmap, int x, int y);
+
+void asr733_keyboard(device_t *device);
+
+#define ASR733_KEY_PORTS \
+ PORT_START("KEY0") /* keys 1-16 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) \
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4) \
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5) \
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6) \
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7) \
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8) \
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) \
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) \
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(":") PORT_CODE(KEYCODE_MINUS) \
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_EQUALS) \
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) \
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) \
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) \
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) \
+ \
+ PORT_START("KEY1") /* keys 17-32 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) \
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) \
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) \
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) \
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) \
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("LINE FEED") PORT_CODE(KEYCODE_CLOSEBRACE) \
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) \
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) \
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) \
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) \
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) \
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) \
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) \
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) \
+ \
+ PORT_START("KEY2") /* keys 33-48 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) \
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) \
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RUB OUT") PORT_CODE(KEYCODE_BACKSPACE) \
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("REPEAT") PORT_CODE(KEYCODE_RALT) \
+ /* hack for my mac that does not disciminate the right ALT key */ \
+ /* PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("REPEAT") PORT_CODE(KEYCODE_LALT) */ \
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) \
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) \
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) \
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) \
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) \
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) \
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) \
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) \
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) \
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP) \
+ \
+ PORT_START("KEY3") /* keys 49-51 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_RSHIFT) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(SPACE)") PORT_CODE(KEYCODE_SPACE)
diff --git a/src/mess/video/911_chr.h b/src/mess/video/911_chr.h
new file mode 100644
index 00000000000..85da783835f
--- /dev/null
+++ b/src/mess/video/911_chr.h
@@ -0,0 +1,3516 @@
+/*
+ 911_chr.h: character definitions for 911_vdt.c
+
+ We define the character matrix for each character.
+
+ The US terminal uses the standard 7-bit ASCII character set, with
+ additional graphic characters in the 32 first positions.
+
+ The various European terminals use variants of the 7-bit ASCII character
+ set with national characters instead of various punctuation characters.
+ I think these national character sets were standardized at a point, but
+ I don't know how close to this standard the character sets used by the
+ 911 VDT are.
+
+ The japanese terminal uses 8-bit character codes. The 128 first characters
+ are identical to the US character set (except that '\' is replaced by the
+ Yen symbol), and the next 128 characters include the katakana syllabus.
+ Kanji ideograms are not supported in this scheme.
+
+ The arabic terminal uses 8-bit character codes, too. It requires
+ additional code in the TI990 OS for correct operation, as the keyboard
+ returns codes for isolated characters (i.e. without ligatures), which need
+ to be substituted with codes with correct context-dependent ligatures.
+ And both OS and application programs need to support the fact that the
+ writing direction can be either right-to-left or left-to-right, according
+ to whether the characters are latin or arabic.
+
+ As the original ROMs have not been dumped yet, I recreated the matrices
+ from various matrix printouts in TI documentation.
+*/
+/*
+ The arabic character set is not implemented, because documentation is ambiguous
+ (it says there are 115 characters, but I can hardly see 80 characters in the
+ attached table), and the character matrices are not documented.
+*/
+
+
+/*
+ Offsets in the char_defs array
+*/
+enum
+{
+ /* US ASCII: 128 characters (32 symbols + 95 ASCII + 1 blank (delete character)) */
+ char_defs_US_base = 0,
+ /* additionnal katakana set (128 characters, including JIS set) */
+ char_defs_katakana_base = char_defs_US_base+128,
+ /* extra symbols for national character sets */
+ char_defs_pound = char_defs_katakana_base+128, /* pound sign (UK 0x23, French WP 0x23) */
+ char_defs_yen, /* yen sign (Japan 0x5C) */
+ char_defs_auml, /* latin small letter a with diaeresis (Swedish/Finish 0x7B, German 0x7B) */
+ char_defs_Auml, /* latin capital letter A with diaeresis (Swedish/Finish 0x5B, German 0x5B) */
+ char_defs_Aring, /* latin capital letter A with ring above (Swedish/Finish 0x5D, Norwegian/Danish 0x5D) */
+ char_defs_uuml, /* latin small letter u with diaeresis (Swedish/Finish 0x7E, German 0x7D) */
+ char_defs_aring, /* latin small letter a with ring above (Swedish/Finish 0x7D, Norwegian/Danish 0x7D) */
+ char_defs_Uuml, /* latin capital letter U with diaeresis (German 0x5D) */
+ char_defs_ouml, /* latin small letter o with diaeresis (German 0x7C) */
+ char_defs_Ouml, /* latin capital letter O with diaeresis (German 0x5C) */
+ char_defs_szlig, /* latin small letter sharp s (German 0x7E) */
+ char_defs_aelig, /* latin small letter ae (Norwegian/Danish 0x7B) */
+ char_defs_AElig, /* latin capital letter AE (Norwegian/Danish 0x5B) */
+ char_defs_oslash, /* latin small letter o with stroke (Norwegian/Danish 0x7C) */
+ char_defs_Oslash, /* latin capital letter O with stroke (Norwegian/Danish 0x5C) */
+ char_defs_agrave, /* latin small letter a with grave (French WP 0x40) */
+ char_defs_deg, /* degree sign (French WP 0x5B) */
+ char_defs_ccedil, /* latin small letter c with cedilla (French WP 0x5C) */
+ char_defs_sect, /* section sign (French WP 0x5D) */
+ char_defs_egrave, /* latin small letter e with grave (French WP 0x7B) */
+ char_defs_ugrave, /* latin small letter u with grave (French WP 0x7C) */
+ char_defs_eacute, /* latin small letter e with acute (French WP 0x7D) */
+ char_defs_uml, /* diaeresis (French WP 0x7E) */
+
+ char_defs_count /* total character count */
+};
+
+/* structure used to describe differences between national character sets and
+US character set */
+/* much more compact than defining the complete 128-char vector */
+typedef struct char_override_t
+{
+ unsigned char char_index; /* char to replace */
+ unsigned short symbol_index; /* replacement symbol */
+} char_override_t;
+
+/* One UK-specific character */
+static const char_override_t UK_overrides[1] =
+{
+ { 0x23, char_defs_pound }
+};
+
+/* One japan-specific character (see below for the 128 additionnal characters) */
+static const char_override_t japanese_overrides[1] =
+{
+ { 0x5C, char_defs_yen }
+};
+
+/* 5 sweden/finland-specific characters */
+static const char_override_t swedish_overrides[/*5*/7] =
+{
+ { 0x7B, char_defs_auml },
+ { 0x5B, char_defs_Auml },
+ { 0x5D, char_defs_Aring },
+ { 0x7E, char_defs_uuml },
+ { 0x7D, char_defs_aring },
+ /* next characters described in D-4 but not 1-10 */
+ { 0x5C, char_defs_Ouml },
+ { 0x7C, char_defs_ouml }
+};
+
+/* 7 german-specific characters */
+static const char_override_t german_overrides[7] =
+{
+ { 0x5D, char_defs_Uuml },
+ { 0x7D, char_defs_uuml },
+ { 0x7C, char_defs_ouml },
+ { 0x5C, char_defs_Ouml },
+ { 0x7B, char_defs_auml },
+ { 0x7E, char_defs_szlig },
+ { 0x5B, char_defs_Auml } /* 945423-9701 rev. B p. 1-10 says 0x5D, but it must be a mistake */
+};
+
+/* 6 norway/denmark-specific characters */
+static const char_override_t norwegian_overrides[6] =
+{
+ { 0x5D, char_defs_Aring },
+ { 0x7B, char_defs_aelig },
+ { 0x5B, char_defs_AElig },
+ { 0x7D, char_defs_aring },
+ { 0x7C, char_defs_oslash},
+ { 0x5C, char_defs_Oslash}
+};
+
+/* 9 french-specific characters (word-processing model only: the data-processing model uses
+the US character set, although the keyboard mapping is different from the US model) */
+/* WARNING: I have created the character matrices from scratch, as I have no printout of
+the original matrices. */
+static const char_override_t frenchWP_overrides[9] =
+{
+ { 0x23, char_defs_pound },
+ { 0x40, char_defs_agrave},
+ { 0x5B, char_defs_deg },
+ { 0x5C, char_defs_ccedil},
+ { 0x5D, char_defs_sect },
+ { 0x7B, char_defs_eacute}, /* 945423-9701 rev. B says char_defs_egrave, but it must be a mistake */
+ { 0x7C, char_defs_ugrave},
+ { 0x7D, char_defs_egrave}, /* 945423-9701 rev. B says char_defs_eacute, but it must be a mistake */
+ { 0x7E, char_defs_uml }
+};
+
+/*
+ char_defs array: character matrices for each character
+*/
+static const UINT8 char_defs[char_defs_count][10] =
+{
+
+/* US character set: 128 7*10 character matrix */
+ { /* 0x00 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c
+ },
+ { /* 0x01 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x02 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x03 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x04 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x05 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x06 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x07 */
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x08 */
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x09 */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x0A */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1f,
+ 0x1f,
+ 0x1f,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x0B */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x7c,
+ 0x7c,
+ 0x7c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x0C */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x0D */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1f,
+ 0x1f,
+ 0x1f,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x0E */
+ 0x01,
+ 0x03,
+ 0x06,
+ 0x04,
+ 0x08,
+ 0x08,
+ 0x10,
+ 0x30,
+ 0x60,
+ 0x40
+ },
+ { /* 0x0F */
+ 0x00,
+ 0x00,
+ 0x7f,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7f,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x10 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x40,
+ 0x40,
+ 0x40,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x11 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x60,
+ 0x60,
+ 0x60,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x12 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x70,
+ 0x70,
+ 0x70,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x13 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x14*/
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7c,
+ 0x7c,
+ 0x7c,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x15 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7e,
+ 0x7e,
+ 0x7e,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x16 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x17*/
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x18 */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x19 */
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f
+ },
+ { /* 0x1A */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7c,
+ 0x7c,
+ 0x7c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x1B */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1f,
+ 0x1f,
+ 0x1f,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x1C */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x1D */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x7c,
+ 0x7c,
+ 0x7c,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x1E */
+ 0x40,
+ 0x60,
+ 0x30,
+ 0x10,
+ 0x08,
+ 0x08,
+ 0x04,
+ 0x06,
+ 0x03,
+ 0x01
+ },
+ { /* 0x1F */
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22
+ },
+ { /* 0x20 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x21 */
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x18,
+ 0x00,
+ 0x00
+ },
+ { /* 0x22 */
+ 0x00,
+ 0x14,
+ 0x14,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x23 */
+ 0x00,
+ 0x00,
+ 0x14,
+ 0x36,
+ 0x00,
+ 0x36,
+ 0x14,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x24 */
+ 0x00,
+ 0x1c,
+ 0x2a,
+ 0x28,
+ 0x1c,
+ 0x0a,
+ 0x2a,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x25 */
+ 0x00,
+ 0x30,
+ 0x32,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x26,
+ 0x06,
+ 0x00,
+ 0x00
+ },
+ { /* 0x26 */
+ 0x00,
+ 0x10,
+ 0x28,
+ 0x28,
+ 0x10,
+ 0x2a,
+ 0x24,
+ 0x1a,
+ 0x00,
+ 0x00
+ },
+ { /* 0x27 */
+ 0x00,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x28 */
+ 0x00,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x04,
+ 0x02,
+ 0x00,
+ 0x00
+ },
+ { /* 0x29 */
+ 0x00,
+ 0x20,
+ 0x10,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0x2A */
+ 0x00,
+ 0x00,
+ 0x08,
+ 0x1c,
+ 0x3e,
+ 0x1c,
+ 0x08,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x2B */
+ 0x00,
+ 0x00,
+ 0x08,
+ 0x08,
+ 0x3e,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x2C */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0x2D */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x2E */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x00
+ },
+ { /* 0x2F */
+ 0x00,
+ 0x00,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x30 */
+ 0x00,
+ 0x0c,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x0c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x31 */
+ 0x00,
+ 0x08,
+ 0x18,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x32 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x02,
+ 0x1c,
+ 0x20,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x33 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x02,
+ 0x0c,
+ 0x02,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x34 */
+ 0x00,
+ 0x04,
+ 0x0c,
+ 0x14,
+ 0x24,
+ 0x3e,
+ 0x04,
+ 0x04,
+ 0x00,
+ 0x00
+ },
+ { /* 0x35 */
+ 0x00,
+ 0x3e,
+ 0x20,
+ 0x3c,
+ 0x02,
+ 0x02,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x36 */
+ 0x00,
+ 0x0c,
+ 0x10,
+ 0x20,
+ 0x3c,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x37 */
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0x38 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x39 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x22,
+ 0x1e,
+ 0x02,
+ 0x04,
+ 0x18,
+ 0x00,
+ 0x00
+ },
+ { /* 0x3A */
+ 0x00,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x3B */
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0x3C */
+ 0x00,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x08,
+ 0x04,
+ 0x02,
+ 0x00,
+ 0x00
+ },
+ { /* 0x3D */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x00,
+ 0x3e,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x3E */
+ 0x00,
+ 0x20,
+ 0x10,
+ 0x08,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0x3F */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x04,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0x40 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x2e,
+ 0x2a,
+ 0x2e,
+ 0x20,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x41 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x22,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x42 */
+ 0x00,
+ 0x3c,
+ 0x12,
+ 0x12,
+ 0x1c,
+ 0x12,
+ 0x12,
+ 0x3c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x43 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x44 */
+ 0x00,
+ 0x3c,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x3c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x45 */
+ 0x00,
+ 0x3e,
+ 0x20,
+ 0x20,
+ 0x3c,
+ 0x20,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x46 */
+ 0x00,
+ 0x3e,
+ 0x20,
+ 0x20,
+ 0x3c,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0x47 */
+ 0x00,
+ 0x1e,
+ 0x20,
+ 0x20,
+ 0x2e,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x48 */
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x49 */
+ 0x00,
+ 0x1c,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x4A */
+ 0x00,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x4B */
+ 0x00,
+ 0x22,
+ 0x24,
+ 0x28,
+ 0x30,
+ 0x28,
+ 0x24,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x4C */
+ 0x00,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x4D */
+ 0x00,
+ 0x22,
+ 0x36,
+ 0x2a,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x4E */
+ 0x00,
+ 0x22,
+ 0x32,
+ 0x2a,
+ 0x26,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x4F */
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x50 */
+ 0x00,
+ 0x3c,
+ 0x22,
+ 0x22,
+ 0x3c,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0x51 */
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x2a,
+ 0x24,
+ 0x3a,
+ 0x00,
+ 0x00
+ },
+ { /* 0x52 */
+ 0x00,
+ 0x3c,
+ 0x22,
+ 0x22,
+ 0x3c,
+ 0x28,
+ 0x24,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x53 */
+ 0x00,
+ 0x1c,
+ 0x20,
+ 0x10,
+ 0x08,
+ 0x04,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x54 */
+ 0x00,
+ 0x3e,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0x55 */
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x56 */
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x14,
+ 0x14,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0x57 */
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x2a,
+ 0x2a,
+ 0x2a,
+ 0x14,
+ 0x00,
+ 0x00
+ },
+ { /* 0x58 */
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x14,
+ 0x08,
+ 0x14,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x59 */
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x14,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0x5A */
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x5B */
+ 0x00,
+ 0x0e,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x0e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x5C */
+ 0x00,
+ 0x00,
+ 0x20,
+ 0x10,
+ 0x08,
+ 0x04,
+ 0x02,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x5D */
+ 0x00,
+ 0x38,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x38,
+ 0x00,
+ 0x00
+ },
+ { /* 0x5E */
+ 0x00,
+ 0x08,
+ 0x14,
+ 0x22,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x5F */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x60 */
+ 0x00,
+ 0x10,
+ 0x08,
+ 0x04,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x61 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x62 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3c,
+ 0x12,
+ 0x1c,
+ 0x12,
+ 0x3c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x63 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1e,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x1e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x64 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3c,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x3c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x65 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x20,
+ 0x3c,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x66 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x20,
+ 0x3c,
+ 0x20,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0x67 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1e,
+ 0x20,
+ 0x2e,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x68 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x69 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x6A */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x0e,
+ 0x04,
+ 0x04,
+ 0x24,
+ 0x3c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x6B */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x24,
+ 0x38,
+ 0x24,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x6C */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x6D */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x36,
+ 0x2a,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x6E */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x32,
+ 0x2a,
+ 0x26,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x6F */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x70 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3c,
+ 0x22,
+ 0x3c,
+ 0x20,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0x71 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x2a,
+ 0x24,
+ 0x3a,
+ 0x00,
+ 0x00
+ },
+ { /* 0x72 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x3e,
+ 0x24,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x73 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1e,
+ 0x20,
+ 0x1c,
+ 0x02,
+ 0x3c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x74 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0x75 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0x76 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x24,
+ 0x28,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0x77 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x2a,
+ 0x36,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x78 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x14,
+ 0x08,
+ 0x14,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0x79 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x14,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0x7A */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0x7B */
+ 0x00,
+ 0x06,
+ 0x08,
+ 0x08,
+ 0x10,
+ 0x08,
+ 0x08,
+ 0x06,
+ 0x00,
+ 0x00
+ },
+ { /* 0x7C */
+ 0x00,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0x7D */
+ 0x00,
+ 0x30,
+ 0x08,
+ 0x08,
+ 0x04,
+ 0x08,
+ 0x08,
+ 0x30,
+ 0x00,
+ 0x00
+ },
+ { /* 0x7E */
+ 0x00,
+ 0x10,
+ 0x2a,
+ 0x04,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x7F */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+
+
+/* 128 additional characters for japanese terminals */
+ { /* 0x80 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c
+ },
+ { /* 0x81 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x82 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x83 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x84 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x85 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x86 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x87 */
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x88 */
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x89 */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x8A */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1f,
+ 0x1f,
+ 0x1f,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x8B */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x7c,
+ 0x7c,
+ 0x7c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x8C */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x8D */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1f,
+ 0x1f,
+ 0x1f,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x8E */
+ 0x01,
+ 0x03,
+ 0x06,
+ 0x04,
+ 0x08,
+ 0x08,
+ 0x10,
+ 0x30,
+ 0x30,
+ 0x20
+ },
+ { /* 0x8F */
+ 0x00,
+ 0x00,
+ 0x7f,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7f,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x90 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x40,
+ 0x40,
+ 0x40,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x91 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x60,
+ 0x60,
+ 0x60,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x92 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x70,
+ 0x70,
+ 0x70,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x93 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x78,
+ 0x78,
+ 0x78,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x94*/
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7c,
+ 0x7c,
+ 0x7c,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x95 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7e,
+ 0x7e,
+ 0x7e,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x96 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x97*/
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x98 */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x99 */
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x7f
+ },
+ { /* 0x9A */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7c,
+ 0x7c,
+ 0x7c,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x9B */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1f,
+ 0x1f,
+ 0x1f,
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x1c
+ },
+ { /* 0x9C */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x7f,
+ 0x7f,
+ 0x7f,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x9D */
+ 0x1c,
+ 0x1c,
+ 0x1c,
+ 0x7c,
+ 0x7c,
+ 0x7c,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0x9E */
+ 0x40,
+ 0x60,
+ 0x30,
+ 0x10,
+ 0x08,
+ 0x08,
+ 0x04,
+ 0x06,
+ 0x06,
+ 0x02
+ },
+ { /* 0x9F */
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22
+ },
+ { /* 0xA0 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xA1 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x38,
+ 0x28,
+ 0x38,
+ 0x00,
+ 0x00
+ },
+ { /* 0xA2 */
+ 0x00,
+ 0x0e,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xA3 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x38,
+ 0x00,
+ 0x00
+ },
+ { /* 0xA4 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x10,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xA5 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x10,
+ 0x10,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xA6 */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x1e,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xA7 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x0c,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xA8 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x04,
+ 0x08,
+ 0x18,
+ 0x28,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xA9 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x08,
+ 0x3e,
+ 0x22,
+ 0x02,
+ 0x0c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xAA */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x08,
+ 0x08,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xAB */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x04,
+ 0x3e,
+ 0x0c,
+ 0x14,
+ 0x24,
+ 0x00,
+ 0x00
+ },
+ { /* 0xAC */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x10,
+ 0x3e,
+ 0x12,
+ 0x14,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xAD */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x04,
+ 0x04,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xAE */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3c,
+ 0x04,
+ 0x3c,
+ 0x04,
+ 0x3c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xAF */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x2a,
+ 0x2a,
+ 0x02,
+ 0x0c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB0 */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB1 */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x0c,
+ 0x08,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB2 */
+ 0x00,
+ 0x04,
+ 0x08,
+ 0x18,
+ 0x28,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB3 */
+ 0x00,
+ 0x08,
+ 0x3e,
+ 0x22,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB4 */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB5 */
+ 0x00,
+ 0x04,
+ 0x3e,
+ 0x04,
+ 0x0c,
+ 0x14,
+ 0x24,
+ 0x04,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB6 */
+ 0x00,
+ 0x08,
+ 0x08,
+ 0x3e,
+ 0x0a,
+ 0x0a,
+ 0x12,
+ 0x24,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB7 */
+ 0x00,
+ 0x08,
+ 0x3e,
+ 0x08,
+ 0x3e,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB8 */
+ 0x00,
+ 0x00,
+ 0x1e,
+ 0x12,
+ 0x22,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xB9 */
+ 0x00,
+ 0x10,
+ 0x10,
+ 0x1e,
+ 0x24,
+ 0x04,
+ 0x04,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xBA */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xBB */
+ 0x00,
+ 0x14,
+ 0x3e,
+ 0x14,
+ 0x14,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xBC */
+ 0x00,
+ 0x00,
+ 0x30,
+ 0x00,
+ 0x32,
+ 0x02,
+ 0x04,
+ 0x38,
+ 0x00,
+ 0x00
+ },
+ { /* 0xBD */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x14,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0xBE */
+ 0x00,
+ 0x10,
+ 0x3e,
+ 0x12,
+ 0x14,
+ 0x10,
+ 0x10,
+ 0x1e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xBF */
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x12,
+ 0x02,
+ 0x04,
+ 0x18,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC0 */
+ 0x00,
+ 0x00,
+ 0x1e,
+ 0x12,
+ 0x2a,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC1 */
+ 0x00,
+ 0x04,
+ 0x38,
+ 0x08,
+ 0x3e,
+ 0x08,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC2 */
+ 0x00,
+ 0x00,
+ 0x2a,
+ 0x2a,
+ 0x2a,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC3 */
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x00,
+ 0x3e,
+ 0x08,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC4 */
+ 0x00,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x18,
+ 0x14,
+ 0x10,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC5 */
+ 0x00,
+ 0x08,
+ 0x08,
+ 0x3e,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC6 */
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC7 */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x14,
+ 0x08,
+ 0x14,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC8 */
+ 0x00,
+ 0x08,
+ 0x3e,
+ 0x04,
+ 0x08,
+ 0x1c,
+ 0x2a,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xC9 */
+ 0x00,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xCA */
+ 0x00,
+ 0x00,
+ 0x04,
+ 0x02,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* 0xCB */
+ 0x00,
+ 0x00,
+ 0x20,
+ 0x20,
+ 0x3e,
+ 0x20,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xCC */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xCD */
+ 0x00,
+ 0x00,
+ 0x10,
+ 0x28,
+ 0x04,
+ 0x02,
+ 0x02,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xCE */
+ 0x00,
+ 0x08,
+ 0x3e,
+ 0x08,
+ 0x2a,
+ 0x2a,
+ 0x2a,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xCF */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x02,
+ 0x14,
+ 0x08,
+ 0x04,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD0 */
+ 0x00,
+ 0x10,
+ 0x0e,
+ 0x00,
+ 0x0e,
+ 0x00,
+ 0x10,
+ 0x0e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD1 */
+ 0x00,
+ 0x00,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x22,
+ 0x3e,
+ 0x02,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD2 */
+ 0x00,
+ 0x00,
+ 0x02,
+ 0x02,
+ 0x14,
+ 0x08,
+ 0x14,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD3 */
+ 0x00,
+ 0x00,
+ 0x3c,
+ 0x10,
+ 0x3e,
+ 0x10,
+ 0x10,
+ 0x1e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD4 */
+ 0x00,
+ 0x10,
+ 0x10,
+ 0x3e,
+ 0x12,
+ 0x14,
+ 0x10,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD5 */
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD6 */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x3e,
+ 0x02,
+ 0x02,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD7 */
+ 0x00,
+ 0x00,
+ 0x1c,
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x02,
+ 0x0c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD8 */
+ 0x00,
+ 0x00,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xD9 */
+ 0x00,
+ 0x00,
+ 0x28,
+ 0x28,
+ 0x28,
+ 0x2a,
+ 0x2a,
+ 0x2c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xDA */
+ 0x00,
+ 0x00,
+ 0x20,
+ 0x20,
+ 0x22,
+ 0x24,
+ 0x28,
+ 0x30,
+ 0x00,
+ 0x00
+ },
+ { /* 0xDB */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xDC */
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xDD */
+ 0x00,
+ 0x00,
+ 0x30,
+ 0x00,
+ 0x02,
+ 0x02,
+ 0x04,
+ 0x38,
+ 0x00,
+ 0x00
+ },
+ { /* 0xDE */
+ 0x00,
+ 0x28,
+ 0x28,
+ 0x28,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xDF */
+ 0x00,
+ 0x38,
+ 0x28,
+ 0x38,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE0 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x04,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE1 */
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE2 */
+ 0x00,
+ 0x14,
+ 0x14,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE3 */
+ 0x00,
+ 0x00,
+ 0x14,
+ 0x36,
+ 0x00,
+ 0x36,
+ 0x14,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE4 */
+ 0x00,
+ 0x1c,
+ 0x2a,
+ 0x28,
+ 0x1c,
+ 0x0a,
+ 0x2a,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE5 */
+ 0x00,
+ 0x30,
+ 0x32,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x26,
+ 0x06,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE6 */
+ 0x00,
+ 0x10,
+ 0x28,
+ 0x28,
+ 0x10,
+ 0x2a,
+ 0x24,
+ 0x1a,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE7 */
+ 0x00,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE8 */
+ 0x00,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x04,
+ 0x02,
+ 0x00,
+ 0x00
+ },
+ { /* 0xE9 */
+ 0x00,
+ 0x20,
+ 0x10,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0xEA */
+ 0x00,
+ 0x00,
+ 0x08,
+ 0x1c,
+ 0x3e,
+ 0x1c,
+ 0x08,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xEB */
+ 0x00,
+ 0x00,
+ 0x08,
+ 0x08,
+ 0x3e,
+ 0x08,
+ 0x08,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xEC */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xED */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xEE */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x00
+ },
+ { /* 0xEF */
+ 0x00,
+ 0x00,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF0 */
+ 0x00,
+ 0x0c,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x12,
+ 0x0c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF1 */
+ 0x00,
+ 0x08,
+ 0x18,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x08,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF2 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x02,
+ 0x1c,
+ 0x20,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF3 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x02,
+ 0x0c,
+ 0x02,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF4 */
+ 0x00,
+ 0x04,
+ 0x0c,
+ 0x14,
+ 0x24,
+ 0x3e,
+ 0x04,
+ 0x04,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF5 */
+ 0x00,
+ 0x3e,
+ 0x20,
+ 0x3c,
+ 0x02,
+ 0x02,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF6 */
+ 0x00,
+ 0x0c,
+ 0x10,
+ 0x20,
+ 0x3c,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF7 */
+ 0x00,
+ 0x3e,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF8 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* 0xF9 */
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x22,
+ 0x1e,
+ 0x02,
+ 0x04,
+ 0x18,
+ 0x00,
+ 0x00
+ },
+ { /* 0xFA */
+ 0x00,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xFB */
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x18,
+ 0x18,
+ 0x08,
+ 0x10,
+ 0x00,
+ 0x00
+ },
+ { /* 0xFC */
+ 0x00,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x08,
+ 0x04,
+ 0x02,
+ 0x00,
+ 0x00
+ },
+ { /* 0xFD */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x00,
+ 0x3e,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* 0xFE */
+ 0x00,
+ 0x20,
+ 0x10,
+ 0x08,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x00,
+ 0x00
+ },
+ { /* 0xFF */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+
+
+/* extra symbols for various national terminals, which use slightly modified
+variants of the US character set */
+ { /* pound */
+ 0x00,
+ 0x0c,
+ 0x12,
+ 0x10,
+ 0x38,
+ 0x10,
+ 0x3a,
+ 0x34,
+ 0x00,
+ 0x00
+ },
+ { /* yen */
+ 0x00,
+ 0x22,
+ 0x14,
+ 0x08,
+ 0x3e,
+ 0x08,
+ 0x3e,
+ 0x08,
+ 0x00,
+ 0x00
+ },
+ { /* auml */
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x3e,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* Auml */
+ 0x00,
+ 0x22,
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* Aring */
+ 0x00,
+ 0x08,
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* uuml */
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* aring */
+ 0x00,
+ 0x00,
+ 0x08,
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x3e,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+
+ { /* Uuml */
+ 0x00,
+ 0x22,
+ 0x00,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+
+ { /* ouml */
+ 0x00,
+ 0x00,
+ 0x22,
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* Ouml */
+ 0x00,
+ 0x22,
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* szlig */
+ 0x00,
+ 0x18,
+ 0x24,
+ 0x24,
+ 0x2c,
+ 0x22,
+ 0x22,
+ 0x2c,
+ 0x00,
+ 0x00
+ },
+ { /* aelig */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x28,
+ 0x3e,
+ 0x28,
+ 0x2e,
+ 0x00,
+ 0x00
+ },
+ { /* AElig */
+ 0x00,
+ 0x3e,
+ 0x28,
+ 0x28,
+ 0x3e,
+ 0x28,
+ 0x28,
+ 0x2e,
+ 0x00,
+ 0x00
+ },
+ { /* Oslash */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3e,
+ 0x26,
+ 0x2a,
+ 0x32,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* oslash */
+ 0x00,
+ 0x3e,
+ 0x22,
+ 0x26,
+ 0x2a,
+ 0x32,
+ 0x22,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+/* WARNING: I have created the next 8 French character matrices from scratch,
+as I have no printout of the original matrices. */
+ { /* agrave */
+ 0x00,
+ 0x10,
+ 0x08,
+ 0x00,
+ 0x1c,
+ 0x22,
+ 0x3e,
+ 0x22,
+ 0x00,
+ 0x00
+ },
+ { /* deg */
+ 0x00,
+ 0x38,
+ 0x28,
+ 0x38,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ },
+ { /* ccedil */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x1e,
+ 0x20,
+ 0x20,
+ 0x20,
+ 0x1e,
+ 0x08,
+ 0x04
+ },
+ { /* sect */
+ 0x00,
+ 0x1c,
+ 0x20,
+ 0x1c,
+ 0x22,
+ 0x1c,
+ 0x02,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* egrave */
+ 0x00,
+ 0x10,
+ 0x08,
+ 0x3e,
+ 0x20,
+ 0x3c,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* ugrave */
+ 0x00,
+ 0x10,
+ 0x08,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x22,
+ 0x1c,
+ 0x00,
+ 0x00
+ },
+ { /* eacute */
+ 0x00,
+ 0x04,
+ 0x08,
+ 0x3e,
+ 0x20,
+ 0x3c,
+ 0x20,
+ 0x3e,
+ 0x00,
+ 0x00
+ },
+ { /* uml */
+ 0x00,
+ 0x22,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+};
+
diff --git a/src/mess/video/911_key.h b/src/mess/video/911_key.h
new file mode 100644
index 00000000000..58f95e2c45c
--- /dev/null
+++ b/src/mess/video/911_key.h
@@ -0,0 +1,4026 @@
+/*
+ key translation table for both US and UK terminals
+
+ The only difference is that the US # character is a Pound character in UK.
+*/
+static const unsigned char US_key_translate[4][91] =
+{
+ { /* lower case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x5F,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x71,
+ 0x77,
+ 0x65,
+ 0x72,
+ 0x74,
+ 0x79,
+ 0x75,
+ 0x69,
+ 0x6F,
+ 0x70,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x61,
+ 0x73,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x6A,
+ 0x6B,
+ 0x6C,
+ 0x3B,
+ 0x27,
+ 0,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x7A,
+ 0x78,
+ 0x63,
+ 0x76,
+ 0x62,
+ 0x6E,
+ 0x6D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* upper case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x5F,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x3B,
+ 0x27,
+ 0,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* shifted */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x21,
+ 0x40,
+ 0x23,
+ 0x24,
+ 0x25,
+ 0x5E,
+ 0x26,
+ 0x2A,
+ 0x28,
+ 0x29,
+ 0x5B,
+ 0x5D,
+ 0x3D,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x8A,
+ 0x8C,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x3A,
+ 0x22,
+ 0,
+ 0x83,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x3C,
+ 0x3E,
+ 0x3F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* control */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x90,
+ 0x91,
+ 0x00,
+ 0xA1,
+ 0x8D,
+ 0x8E,
+ 0x8F,
+ 0x7C,
+ 0x60,
+ 0x7E,
+ 0x1D,
+ 0x7F,
+ 0x5C,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x11,
+ 0x17,
+ 0x05,
+ 0x12,
+ 0x14,
+ 0x19,
+ 0x15,
+ 0x09,
+ 0x0F,
+ 0x10,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x01,
+ 0x13,
+ 0x04,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ 0x7B,
+ 0x7D,
+ 0,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x1A,
+ 0x18,
+ 0x03,
+ 0x16,
+ 0x02,
+ 0x0E,
+ 0x0D,
+ 0x1C,
+ 0x1E,
+ 0x1F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ }
+};
+
+
+/*
+ key translation table for French terminals
+*/
+static const unsigned char French_key_translate[4][91] =
+{
+ { /* lower case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x5F,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x61,
+ 0x7A,
+ 0x65,
+ 0x72,
+ 0x74,
+ 0x79,
+ 0x75,
+ 0x69,
+ 0x6F,
+ 0x70,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x71,
+ 0x73,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x6A,
+ 0x6B,
+ 0x6C,
+ 0x6D,
+ 0x27,
+ 0,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x77,
+ 0x78,
+ 0x63,
+ 0x76,
+ 0x62,
+ 0x6E,
+ 0x3B,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* upper case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x5F,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x41,
+ 0x5A,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x51,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x4D,
+ 0x27,
+ 0,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x57,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x3B,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* shifted */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x21,
+ 0x40,
+ 0x23,
+ 0x24,
+ 0x25,
+ 0x5E,
+ 0x26,
+ 0x2A,
+ 0x28,
+ 0x29,
+ 0x5B,
+ 0x5D,
+ 0x3D,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x41,
+ 0x5A,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x8A,
+ 0x8C,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x51,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x4D,
+ 0x22,
+ 0,
+ 0x83,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x57,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x3A,
+ 0x3C,
+ 0x3E,
+ 0x3F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* control */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x90,
+ 0x91,
+ 0x00,
+ 0xA1,
+ 0x8D,
+ 0x8E,
+ 0x8F,
+ 0x7C,
+ 0x60,
+ 0x7E,
+ 0x1D,
+ 0x7F,
+ 0x5C,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x01,
+ 0x1A,
+ 0x05,
+ 0x12,
+ 0x14,
+ 0x19,
+ 0x15,
+ 0x09,
+ 0x0F,
+ 0x10,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x11,
+ 0x13,
+ 0x04,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ 0x0D,
+ 0x7D,
+ 0,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x17,
+ 0x18,
+ 0x03,
+ 0x16,
+ 0x02,
+ 0x0E,
+ 0x7B,
+ 0x1C,
+ 0x1E,
+ 0x1F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0
+ }
+};
+
+
+/*
+ key translation table for German terminals
+*/
+static const unsigned char German_key_translate[4][91] =
+{
+ { /* lower case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x7E,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x71,
+ 0x77,
+ 0x65,
+ 0x72,
+ 0x74,
+ 0x7A,
+ 0x75,
+ 0x69,
+ 0x6F,
+ 0x70,
+ 0x7D,
+ 0x88,
+ 0x87,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x61,
+ 0x73,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x6A,
+ 0x6B,
+ 0x6C,
+ 0x7C,
+ 0x7B,
+ 0x3B,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x79,
+ 0x78,
+ 0x63,
+ 0x76,
+ 0x62,
+ 0x6E,
+ 0x6D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ },
+ { /* upper case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x27,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x5A,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x5D,
+ 0x88,
+ 0x87,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x5C,
+ 0x5B,
+ 0x3B,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x59,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ },
+ { /* shifted */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x21,
+ 0x40,
+ 0x23,
+ 0x24,
+ 0x25,
+ 0x5E,
+ 0x26,
+ 0x2A,
+ 0x28,
+ 0x29,
+ 0x5F,
+ 0x3D,
+ 0x22,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x5A,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x5D,
+ 0x8A,
+ 0x8C,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x5C,
+ 0x5B,
+ 0x3A,
+ 0x83, /* 945423-9701 rev. B says 0x85, but it must be a mistake */
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x59,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x3C,
+ 0x3E,
+ 0x3F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ },
+ { /* control */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x90,
+ 0x91,
+ 0x00,
+ 0xA1,
+ 0x8D,
+ 0x8E,
+ 0x8F,
+ 0x7C,
+ 0x60,
+ 0x00,
+ 0x1D,
+ 0x7F,
+ 0x00,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x11,
+ 0x17,
+ 0x05,
+ 0x12,
+ 0x14,
+ 0x1A,
+ 0x15,
+ 0x09,
+ 0x0F,
+ 0x10,
+ 0x00,
+ 0x88,
+ 0x87,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x01,
+ 0x13,
+ 0x04,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x19,
+ 0x18,
+ 0x03,
+ 0x16,
+ 0x02,
+ 0x0E,
+ 0x0D,
+ 0x1C,
+ 0x1E,
+ 0x1F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ }
+};
+
+
+/*
+ key translation table for Swedish/Finnish terminals
+*/
+static const unsigned char Swedish_key_translate[4][91] =
+{
+ { /* lower case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x7E,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x71,
+ 0x77,
+ 0x65,
+ 0x72,
+ 0x74,
+ 0x79,
+ 0x75,
+ 0x69,
+ 0x6F,
+ 0x70,
+ 0x7D,
+ 0x88,
+ 0x87,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x61,
+ 0x73,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x6A,
+ 0x6B,
+ 0x6C,
+ 0x7C,
+ 0x7B,
+ 0x3B,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x7A,
+ 0x78,
+ 0x63,
+ 0x76,
+ 0x62,
+ 0x6E,
+ 0x6D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ },
+ { /* upper case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x27,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x5D,
+ 0x88,
+ 0x87,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x5C,
+ 0x5B,
+ 0x3B,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ },
+ { /* shifted */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x21,
+ 0x40,
+ 0x23,
+ 0x24,
+ 0x25,
+ 0x5E,
+ 0x26,
+ 0x2A,
+ 0x28,
+ 0x29,
+ 0x5F,
+ 0x3D,
+ 0x22,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x5D,
+ 0x8A,
+ 0x8C,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x5C,
+ 0x5B,
+ 0x3A,
+ 0x83, /* 945423-9701 rev. B says 0x85, but it must be a mistake */
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x3C,
+ 0x3E,
+ 0x3F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ },
+ { /* control */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x90,
+ 0x91,
+ 0x00,
+ 0xA1,
+ 0x8D,
+ 0x8E,
+ 0x8F,
+ 0x00,
+ 0x60,
+ 0x00,
+ 0x1D,
+ 0x7F,
+ 0x00,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x11,
+ 0x17,
+ 0x05,
+ 0x12,
+ 0x14,
+ 0x19,
+ 0x15,
+ 0x09,
+ 0x0F,
+ 0x10,
+ 0x00,
+ 0x88,
+ 0x87,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x01,
+ 0x13,
+ 0x04,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x1A,
+ 0x18,
+ 0x03,
+ 0x16,
+ 0x02,
+ 0x0E,
+ 0x0D,
+ 0x1C,
+ 0x1E,
+ 0x1F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ }
+};
+
+
+/*
+ key translation table for Norwegian/Danish terminals
+*/
+static const unsigned char Norwegian_key_translate[4][91] =
+{
+ { /* lower case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x27,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x71,
+ 0x77,
+ 0x65,
+ 0x72,
+ 0x74,
+ 0x79,
+ 0x75,
+ 0x69,
+ 0x6F,
+ 0x70,
+ 0x7D,
+ 0x88,
+ 0x87,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x61,
+ 0x73,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x6A,
+ 0x6B,
+ 0x6C,
+ 0x7B,
+ 0x7C,
+ 0x3B,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x7A,
+ 0x78,
+ 0x63,
+ 0x76,
+ 0x62,
+ 0x6E,
+ 0x6D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ },
+ { /* upper case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x27,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x5D,
+ 0x88,
+ 0x87,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x5B,
+ 0x5C,
+ 0x3B,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ },
+ { /* shifted */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x21,
+ 0x40,
+ 0x23,
+ 0x24,
+ 0x25,
+ 0x5E,
+ 0x26,
+ 0x2A,
+ 0x28,
+ 0x29,
+ 0x5F,
+ 0x3D,
+ 0x22,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x5D,
+ 0x8A, /* 945423-9701 rev. B says 0x88, but it must be a mistake */
+ 0x8C, /* 945423-9701 rev. B says 0x87, but it must be a mistake */
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x5B,
+ 0x5C,
+ 0x3A,
+ 0x83,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x3C,
+ 0x3E,
+ 0x3F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ },
+ { /* control */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x90,
+ 0x91,
+ 0x00,
+ 0xA1,
+ 0x8D,
+ 0x8E,
+ 0x8F,
+ 0x00,
+ 0x60,
+ 0x00,
+ 0x1D,
+ 0x7F,
+ 0x00,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x11,
+ 0x17,
+ 0x05,
+ 0x12,
+ 0x14,
+ 0x19,
+ 0x15,
+ 0x09,
+ 0x0F,
+ 0x10,
+ 0x00,
+ 0x88, /* 945423-9701 rev. B says 0x8A, but it must be a mistake */
+ 0x87, /* 945423-9701 rev. B says 0x8C, but it must be a mistake */
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x01,
+ 0x13,
+ 0x04,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x1A,
+ 0x18,
+ 0x03,
+ 0x16,
+ 0x02,
+ 0x0E,
+ 0x0D,
+ 0x1C,
+ 0x1E,
+ 0x1F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0x0D
+ }
+};
+
+
+/*
+ key translation table for Japanese katakana terminals
+*/
+static const unsigned char Japanese_key_translate[6][91] =
+{
+ { /* lower case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x5F,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x71,
+ 0x77,
+ 0x65,
+ 0x72,
+ 0x74,
+ 0x79,
+ 0x75,
+ 0x69,
+ 0x6F,
+ 0x70,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x61,
+ 0x73,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x6A,
+ 0x6B,
+ 0x6C,
+ 0x3B,
+ 0x27,
+ 0x5C,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x7A,
+ 0x78,
+ 0x63,
+ 0x76,
+ 0x62,
+ 0x6E,
+ 0x6D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* upper case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x5F,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x3B,
+ 0x27,
+ 0x5C,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* shifted */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x21,
+ 0x40,
+ 0x23,
+ 0x24,
+ 0x25,
+ 0x5E,
+ 0x26,
+ 0x2A,
+ 0x28,
+ 0x29,
+ 0x5B,
+ 0x5D,
+ 0x3D,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x8A,
+ 0x8C,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x3A,
+ 0x22,
+ 0x00,
+ 0x83,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x3C,
+ 0x3E,
+ 0x3F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* control */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x90,
+ 0x91,
+ 0x00,
+ 0xA1,
+ 0x8D,
+ 0x8E,
+ 0x8F,
+ 0x7C,
+ 0x60,
+ 0x7E,
+ 0x1D,
+ 0x7F,
+ 0x5C, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays the back quote character, whereas it actually display the Yen symbol) */
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x11,
+ 0x17,
+ 0x05,
+ 0x12,
+ 0x14,
+ 0x19,
+ 0x15,
+ 0x09,
+ 0x0F,
+ 0x10,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x01,
+ 0x13,
+ 0x04,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ 0x7B,
+ 0x7D,
+ 0x00,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x1A,
+ 0x18,
+ 0x03,
+ 0x16,
+ 0x02,
+ 0x0E,
+ 0x0D,
+ 0x1C,
+ 0x1E,
+ 0x1F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* katakana */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0xC7,
+ 0xCC,
+ 0xB1,
+ 0xB3,
+ 0xB4,
+ 0xB5,
+ 0xD4,
+ 0xD5,
+ 0xD6,
+ 0xDC,
+ 0xCE,
+ 0xCD,
+ 0xDB,
+ 0x1B, /* 945423-9701 rev. B says 0x00, but it must be a mistake */
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0xC0,
+ 0xC3,
+ 0xB2,
+ 0xBD,
+ 0xB6,
+ 0xDD,
+ 0xC5,
+ 0xC6,
+ 0xD7,
+ 0xBE,
+ 0x88, /* 945423-9701 rev. B says 0x00, but it must be a mistake */
+ 0x87, /* 945423-9701 rev. B says 0x00, but it must be a mistake */
+ 0x0D, /* 945423-9701 rev. B says 0x00, but it must be a mistake */
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0xC1,
+ 0xC4,
+ 0xBC,
+ 0xCA,
+ 0xB7,
+ 0xB8,
+ 0xCF,
+ 0xC9,
+ 0xD8, /* 945423-9701 rev. B says 0xC8, but it must be a mistake */
+ 0xDA,
+ 0xB9,
+ 0xD1,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0xC2,
+ 0xBB,
+ 0xBF,
+ 0xCB,
+ 0xBA,
+ 0xD0,
+ 0xD3,
+ 0xC8,
+ 0xD9,
+ 0xD2,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* shifted katakana */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x00,
+ 0x00,
+ 0xA7,
+ 0xA9,
+ 0xAA,
+ 0xAB,
+ 0xAC,
+ 0xAD,
+ 0xAE,
+ 0xA6,
+ 0xDE,
+ 0xDF,
+ 0xB0,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x00,
+ 0x00,
+ 0xAB,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x8A,
+ 0x8C,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xA2,
+ 0xA3,
+ 0x83,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0xAF,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xA4,
+ 0xA1,
+ 0xA5,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ }
+};
+
+
+#if 0
+/*
+ key translation table for Arabic terminals
+*/
+static const unsigned char Arabic_key_translate[6][91] =
+{
+ { /* lower case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x5F,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x71,
+ 0x77,
+ 0x65,
+ 0x72,
+ 0x74,
+ 0x79,
+ 0x75,
+ 0x69,
+ 0x6F,
+ 0x70,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x61,
+ 0x73,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x6A,
+ 0x6B,
+ 0x6C,
+ 0x3B,
+ 0x27,
+ 0x5C,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x7A,
+ 0x78,
+ 0x63,
+ 0x76,
+ 0x62,
+ 0x6E,
+ 0x6D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* upper case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x2B,
+ 0x2D,
+ 0x5F,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x3B,
+ 0x27,
+ 0x5C,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x2C,
+ 0x2E,
+ 0x2F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* shifted */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x21,
+ 0x40,
+ 0x23,
+ 0x24,
+ 0x25,
+ 0x5E,
+ 0x26,
+ 0x2A,
+ 0x28,
+ 0x29,
+ 0x5B,
+ 0x5D,
+ 0x3D,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x51,
+ 0x57,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x8A,
+ 0x8C,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x41,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x3A,
+ 0x22,
+ 0x00,
+ 0x83,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x5A,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x4D,
+ 0x3C,
+ 0x3E,
+ 0x3F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* control */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x90,
+ 0x91,
+ 0x00,
+ 0xA1,
+ 0x8D,
+ 0x8E,
+ 0x8F,
+ 0x7C,
+ 0x60,
+ 0x7E,
+ 0x1D,
+ 0x7F,
+ 0x5C,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x11,
+ 0x17,
+ 0x05,
+ 0x12,
+ 0x14,
+ 0x19,
+ 0x15,
+ 0x09,
+ 0x0F,
+ 0x10,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x01,
+ 0x13,
+ 0x04,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ 0x7B,
+ 0x7D,
+ 0x00,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x1A,
+ 0x18,
+ 0x03,
+ 0x16,
+ 0x02,
+ 0x0E,
+ 0x0D,
+ 0x1C,
+ 0x1E,
+ 0x1F,
+ 0,
+
+ 0x30,
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* arabic */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0xC7,
+ 0xCC,
+ 0xB1,
+ 0xB3,
+ 0xB4,
+ 0xB5,
+ 0xD4,
+ 0xD5,
+ 0xD6,
+ 0xDC,
+ 0xCE,
+ 0xCD,
+ 0xDB,
+ 0x1B,
+
+ 0x37, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x38, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x39, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0xC0,
+ 0xC3,
+ 0xB2,
+ 0xBD,
+ 0xB6,
+ 0xDD,
+ 0xC5,
+ 0xC6,
+ 0xD7,
+ 0xBE,
+ 0x88,
+ 0x87,
+ 0x0D,
+
+ 0x34, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x35, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x36, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0xC1,
+ 0xC4,
+ 0xBC,
+ 0xCA,
+ 0xB7,
+ 0xB8,
+ 0xCF,
+ 0xC9,
+ 0xD8,
+ 0xDA,
+ 0xB9,
+ 0xD1,
+ 0x85,
+
+ 0x31, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x32, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x33, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0xC2,
+ 0xBB,
+ 0xBF,
+ 0xCB,
+ 0xBA,
+ 0xD0,
+ 0xD3,
+ 0xC8,
+ 0xD9,
+ 0xD2,
+ 0,
+
+ 0x30, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* shifted arabic */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x00,
+ 0x00,
+ 0xA7,
+ 0xA9,
+ 0xAA,
+ 0xAB,
+ 0xAC,
+ 0xAD,
+ 0xAE,
+ 0xA6,
+ 0xDE,
+ 0xDF,
+ 0xB0,
+ 0x1B,
+
+ 0x37, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x38, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x39, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x00,
+ 0x00,
+ 0xAB,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x8A,
+ 0x8C,
+ 0x0D,
+
+ 0x34, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x35, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x36, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xA2,
+ 0xA3,
+ 0x83,
+
+ 0x31, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x32, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x33, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0xAF,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xA4,
+ 0xA1,
+ 0xA5,
+ 0,
+
+ 0x30, /* 945423-9701 rev. B says so, but it might be a mistake (it claims it displays arabic-style digits, whereas it actually displays western-style digits) */
+ 0x2E,
+
+ 0,
+ 0x20,
+ 0
+ }
+};
+#endif
+
+
+/*
+ key translation table for French word-processing terminals
+*/
+static const unsigned char FrenchWP_key_translate[4][91] =
+{
+ { /* lower case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x26,
+ 0x7B,
+ 0x22,
+ 0x27,
+ 0x28,
+ 0x5D,
+ 0x7D,
+ 0x21,
+ 0x5C,
+ 0x40,
+ 0x29,
+ 0x2D,
+ 0x24,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x61,
+ 0x7A,
+ 0x65,
+ 0x72,
+ 0x74,
+ 0x79,
+ 0x75,
+ 0x69,
+ 0x6F,
+ 0x70,
+ 0x5E,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x71,
+ 0x73,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x6A,
+ 0x6B,
+ 0x6C,
+ 0x6D,
+ 0x7C,
+ 0x2A,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x77,
+ 0x78,
+ 0x63,
+ 0x76,
+ 0x62,
+ 0x6E,
+ 0x2C,
+ 0x3B,
+ 0x3A,
+ 0x3D,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* upper case */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x5B,
+ 0x5F,
+ 0x23,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x41,
+ 0x5A,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x7E,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x51,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x4D,
+ 0x25,
+ 0x60,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x57,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x3F,
+ 0x2E,
+ 0x2F,
+ 0x2B,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* shifted */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x31,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x35,
+ 0x36,
+ 0x37,
+ 0x38,
+ 0x39,
+ 0x30,
+ 0x5B,
+ 0x5F,
+ 0x23,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x41,
+ 0x5A,
+ 0x45,
+ 0x52,
+ 0x54,
+ 0x59,
+ 0x55,
+ 0x49,
+ 0x4F,
+ 0x50,
+ 0x7E,
+ 0x8C,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x51,
+ 0x53,
+ 0x44,
+ 0x46,
+ 0x47,
+ 0x48,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x4D,
+ 0x25,
+ 0x60,
+ 0x83,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x57,
+ 0x58,
+ 0x43,
+ 0x56,
+ 0x42,
+ 0x4E,
+ 0x3F,
+ 0x2E,
+ 0x2F,
+ 0x2B,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0
+ },
+ { /* control */
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x96,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9B,
+ 0x9C,
+
+
+ 0x80,
+ 0x81,
+ 0x9F,
+
+ 0,
+ 0x90,
+ 0x91,
+ 0x00,
+ 0xA1,
+ 0x8D,
+ 0x8E,
+ 0x8F,
+ 0x3C,
+ 0x3E,
+ 0x00,
+ 0x1D,
+ 0x7F,
+ 0x00,
+ 0x1B,
+
+ 0x37,
+ 0x38,
+ 0x39,
+
+
+ 0x9A,
+ 0x89,
+ 0,
+
+ 0xA0,
+ 0x01,
+ 0x1A,
+ 0x05,
+ 0x12,
+ 0x14,
+ 0x19,
+ 0x15,
+ 0x09,
+ 0x0F,
+ 0x10,
+ 0x00,
+ 0x87,
+ 0x0D,
+
+ 0x34,
+ 0x35,
+ 0x36,
+
+
+ 0x88,
+ 0x82,
+ 0x8A,
+
+ 0,
+ 0x11,
+ 0x13,
+ 0x04,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ 0x0D,
+ 0x00,
+ 0x00,
+ 0x85,
+
+ 0x31,
+ 0x32,
+ 0x33,
+
+
+ 0x86,
+ 0x8B,
+ 0x84,
+
+ 0,
+ 0x17,
+ 0x18,
+ 0x03,
+ 0x16,
+ 0x02,
+ 0x0E,
+ 0x00,
+ 0x1C,
+ 0x1E,
+ 0x1F,
+ 0,
+
+ 0x30,
+ 0x2C,
+
+ 0,
+ 0x20,
+ 0
+ }
+};
diff --git a/src/mess/video/911_vdt.c b/src/mess/video/911_vdt.c
new file mode 100644
index 00000000000..409f785424d
--- /dev/null
+++ b/src/mess/video/911_vdt.c
@@ -0,0 +1,701 @@
+/*
+ TI 911 VDT core. To be operated with the TI 990 line of computers (can be connected to
+ any model, as communication uses the CRU bus).
+
+ Raphael Nabet 2002
+
+TODO:
+ * add more flexibility, so that we can create multiple-terminal configurations.
+ * support test mode???
+*/
+
+
+#include "emu.h"
+#include "911_vdt.h"
+#include "911_chr.h"
+#include "911_key.h"
+#include "sound/beep.h"
+
+
+
+#define MAX_VDT 1
+
+static const gfx_layout fontlayout_7bit =
+{
+ 7, 10, /* 7*10 characters */
+ 128, /* 128 characters */
+ 1, /* 1 bit per pixel */
+ { 0 },
+ { 1, 2, 3, 4, 5, 6, 7 }, /* straightforward layout */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8 },
+ 10*8 /* every char takes 10 consecutive bytes */
+};
+
+static const gfx_layout fontlayout_8bit =
+{
+ 7, 10, /* 7*10 characters */
+ 128, /* 128 characters */
+ 1, /* 1 bit per pixel */
+ { 0 },
+ { 1, 2, 3, 4, 5, 6, 7 }, /* straightforward layout */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8 },
+ 10*8 /* every char takes 10 consecutive bytes */
+};
+
+GFXDECODE_START( vdt911 )
+ /* array must use same order as vdt911_model_t!!! */
+ /* US */
+ GFXDECODE_ENTRY( vdt911_chr_region, vdt911_US_chr_offset, fontlayout_7bit, 0, 4 )
+ /* UK */
+ GFXDECODE_ENTRY( vdt911_chr_region, vdt911_UK_chr_offset, fontlayout_7bit, 0, 4 )
+ /* French */
+ GFXDECODE_ENTRY( vdt911_chr_region, vdt911_US_chr_offset, fontlayout_7bit, 0, 4 )
+ /* German */
+ GFXDECODE_ENTRY( vdt911_chr_region, vdt911_german_chr_offset, fontlayout_7bit, 0, 4 )
+ /* Swedish */
+ GFXDECODE_ENTRY( vdt911_chr_region, vdt911_swedish_chr_offset, fontlayout_7bit, 0, 4 )
+ /* Norwegian */
+ GFXDECODE_ENTRY( vdt911_chr_region, vdt911_norwegian_chr_offset, fontlayout_7bit, 0, 4 )
+ /* Japanese */
+ GFXDECODE_ENTRY( vdt911_chr_region, vdt911_japanese_chr_offset, fontlayout_8bit, 0, 4 )
+ /* Arabic */
+ /* GFXDECODE_ENTRY( vdt911_chr_region, vdt911_arabic_chr_offset, fontlayout_8bit, 0, 4 ) */
+ /* FrenchWP */
+ GFXDECODE_ENTRY( vdt911_chr_region, vdt911_frenchWP_chr_offset, fontlayout_7bit, 0, 4 )
+GFXDECODE_END
+
+static const unsigned char vdt911_colors[] =
+{
+ 0x00,0x00,0x00, /* black */
+ 0xC0,0xC0,0xC0, /* low intensity */
+ 0xFF,0xFF,0xFF /* high intensity */
+};
+
+static const unsigned short vdt911_palette[] =
+{
+ 0, 2, /* high intensity */
+ 0, 1, /* low intensity */
+ 2, 0, /* high intensity, reverse */
+ 2, 1 /* low intensity, reverse */
+};
+
+typedef struct vdt_t
+{
+ vdt911_screen_size_t screen_size; /* char_960 for 960-char, 12-line model; char_1920 for 1920-char, 24-line model */
+ vdt911_model_t model; /* country code */
+ void (*int_callback)(running_machine &machine, int state); /* interrupt callback, called when the state of irq changes */
+
+ UINT8 data_reg; /* vdt911 write buffer */
+ UINT8 display_RAM[2048]; /* vdt911 char buffer (1kbyte for 960-char model, 2kbytes for 1920-char model) */
+
+ unsigned int cursor_address; /* current cursor address (controlled by the computer, affects both display and I/O protocol) */
+ unsigned int cursor_address_mask; /* 1023 for 960-char model, 2047 for 1920-char model */
+
+ emu_timer *beep_timer; /* beep clock (beeps ends when timer times out) */
+ /*void *blink_clock;*/ /* cursor blink clock */
+
+ UINT8 keyboard_data; /* last code pressed on keyboard */
+ unsigned int keyboard_data_ready : 1; /* true if there is a new code in keyboard_data */
+ unsigned int keyboard_interrupt_enable : 1; /* true when keybord interrupts are enabled */
+
+ unsigned int display_enable : 1; /* screen is black when false */
+ unsigned int dual_intensity_enable : 1; /* if true, MSBit of ASCII codes controls character highlight */
+ unsigned int display_cursor : 1; /* if true, the current cursor location is displayed on screen */
+ unsigned int blinking_cursor_enable : 1;/* if true, the cursor will blink when displayed */
+ unsigned int blink_state : 1; /* current cursor blink state */
+
+ unsigned int word_select : 1; /* CRU interface mode */
+ unsigned int previous_word_select : 1; /* value of word_select is saved here */
+
+ UINT8 last_key_pressed;
+ int last_modifier_state;
+ char foreign_mode;
+} vdt_t;
+
+/*
+ Macros for model features
+*/
+/* TRUE for japanese and arabic terminals, which use 8-bit charcodes and keyboard shift modes */
+#define USES_8BIT_CHARCODES(vdt) ((vdt->model == vdt911_model_Japanese) /*|| (vdt->model == vdt911_model_Arabic)*/)
+/* TRUE for keyboards which have this extra key (on the left of TAB/SKIP)
+ (Most localized keyboards have it) */
+#define HAS_EXTRA_KEY_67(vdt) (! ((vdt->model == vdt911_model_US) || (vdt->model == vdt911_model_UK) || (vdt->model == vdt911_model_French)))
+/* TRUE for keyboards which have this extra key (on the right of space),
+ AND do not use it as a modifier */
+#define HAS_EXTRA_KEY_91(vdt) ((vdt->model == vdt911_model_German) || (vdt->model == vdt911_model_Swedish) || (vdt->model == vdt911_model_Norwegian))
+
+static TIMER_CALLBACK(blink_callback);
+static TIMER_CALLBACK(beep_callback);
+
+/*
+ Initialize vdt911 palette
+*/
+PALETTE_INIT( vdt911 )
+{
+ UINT8 i, r, g, b;
+
+ machine.colortable = colortable_alloc(machine, 3);
+
+ for ( i = 0; i < 3; i++ )
+ {
+ r = vdt911_colors[i*3]; g = vdt911_colors[i*3+1]; b = vdt911_colors[i*3+2];
+ colortable_palette_set_color(machine.colortable, i, MAKE_RGB(r, g, b));
+ }
+
+ for(i=0;i<8;i++)
+ colortable_entry_set_value(machine.colortable, i, vdt911_palette[i]);
+}
+
+/*
+ Copy a character bitmap array to another location in memory
+*/
+static void copy_character_matrix_array(const UINT8 char_array[128][10], UINT8 *dest)
+{
+ int i, j;
+
+ for (i=0; i<128; i++)
+ for (j=0; j<10; j++)
+ *(dest++) = char_array[i][j];
+}
+
+/*
+ Patch a character bitmap array according to an array of char_override_t
+*/
+static void apply_char_overrides(int nb_char_overrides, const char_override_t char_overrides[], UINT8 *dest)
+{
+ int i, j;
+
+ for (i=0; i<nb_char_overrides; i++)
+ {
+ for (j=0; j<10; j++)
+ dest[char_overrides[i].char_index*10+j] = char_defs[char_overrides[i].symbol_index][j];
+ }
+}
+
+/*
+ Initialize the 911 vdt core
+*/
+void vdt911_init(running_machine &machine)
+{
+ UINT8 *base;
+ UINT8 *chr = machine.root_device().memregion(vdt911_chr_region)->base();
+
+ /* set up US character definitions */
+ base = chr+vdt911_US_chr_offset;
+ copy_character_matrix_array(char_defs+char_defs_US_base, base);
+
+ /* set up UK character definitions */
+ base = chr+vdt911_UK_chr_offset;
+ copy_character_matrix_array(char_defs+char_defs_US_base, base);
+ apply_char_overrides(sizeof(UK_overrides)/sizeof(char_override_t), UK_overrides, base);
+
+ /* French character set is identical to US character set */
+
+ /* set up German character definitions */
+ base = chr+vdt911_german_chr_offset;
+ copy_character_matrix_array(char_defs+char_defs_US_base, base);
+ apply_char_overrides(sizeof(german_overrides)/sizeof(char_override_t), german_overrides, base);
+
+ /* set up Swedish/Finnish character definitions */
+ base = chr+vdt911_swedish_chr_offset;
+ copy_character_matrix_array(char_defs+char_defs_US_base, base);
+ apply_char_overrides(sizeof(swedish_overrides)/sizeof(char_override_t), swedish_overrides, base);
+
+ /* set up Norwegian/Danish character definitions */
+ base = chr+vdt911_norwegian_chr_offset;
+ copy_character_matrix_array(char_defs+char_defs_US_base, base);
+ apply_char_overrides(sizeof(norwegian_overrides)/sizeof(char_override_t), norwegian_overrides, base);
+
+ /* set up Katakana Japanese character definitions */
+ base = chr+vdt911_japanese_chr_offset;
+ copy_character_matrix_array(char_defs+char_defs_US_base, base);
+ apply_char_overrides(sizeof(japanese_overrides)/sizeof(char_override_t), japanese_overrides, base);
+ base = chr+vdt911_japanese_chr_offset+128*vdt911_single_char_len;
+ copy_character_matrix_array(char_defs+char_defs_katakana_base, base);
+
+#if 0
+ /* set up Arabic character definitions */
+ base = chr+vdt911_arabic_chr_offset;
+ copy_character_matrix_array(char_defs+char_defs_US_base, base);
+ apply_char_overrides(sizeof(arabic_overrides)/sizeof(char_override_t), arabic_overrides, base);
+ base = chr+vdt911_arabic_chr_offset+128*vdt911_single_char_len;
+ copy_character_matrix_array(char_defs+char_defs_arabic_base, base);
+#endif
+
+ /* set up French word processing character definitions */
+ base = chr+vdt911_frenchWP_chr_offset;
+ copy_character_matrix_array(char_defs+char_defs_US_base, base);
+ apply_char_overrides(sizeof(frenchWP_overrides)/sizeof(char_override_t), frenchWP_overrides, base);
+}
+
+static TIMER_CALLBACK(setup_beep)
+{
+ beep_set_frequency(machine.device(BEEPER_TAG), 2000);
+}
+
+
+INLINE vdt_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == VDT911);
+
+ return (vdt_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+/*
+ Initialize one 911 vdt controller/terminal
+*/
+static DEVICE_START( vdt911 )
+{
+ vdt_t *vdt = get_safe_token(device);
+ const vdt911_init_params_t *params = (const vdt911_init_params_t *)device->static_config();
+ vdt->last_key_pressed = 0x80;
+ vdt->screen_size = params->screen_size;
+ vdt->model = params->model;
+ vdt->int_callback = params->int_callback;
+
+ if (vdt->screen_size == char_960)
+ vdt->cursor_address_mask = 0x3ff; /* 1kb of RAM */
+ else
+ vdt->cursor_address_mask = 0x7ff; /* 2 kb of RAM */
+
+ device->machine().scheduler().timer_set(attotime::zero, FUNC(setup_beep), 0, vdt);
+
+ /* set up cursor blink clock. 2Hz frequency -> .25s half-period. */
+ /*vdt->blink_clock =*/ device->machine().scheduler().timer_pulse(attotime::from_msec(250), FUNC(blink_callback), 0, vdt);
+
+ /* alloc beep timer */
+ vdt->beep_timer = device->machine().scheduler().timer_alloc(FUNC(beep_callback));
+}
+
+DEVICE_GET_INFO( vdt911 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(vdt_t); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(vdt911); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "911 VDT"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "911 VDT Video"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(VDT911, vdt911);
+
+/*
+ timer callback to toggle blink state
+*/
+static TIMER_CALLBACK(blink_callback)
+{
+ vdt_t *vdt = (vdt_t *)ptr;
+ vdt->blink_state = !vdt->blink_state;
+}
+
+/*
+ timer callback to stop beep generator
+*/
+static TIMER_CALLBACK(beep_callback)
+{
+ beep_set_state(machine.device(BEEPER_TAG), 0);
+}
+
+/*
+ CRU interface read
+*/
+READ8_DEVICE_HANDLER( vdt911_cru_r )
+{
+ vdt_t *vdt = get_safe_token(device);
+ int reply=0;
+
+ offset &= 0x1;
+
+ if (! vdt->word_select)
+ { /* select word 0 */
+ switch (offset)
+ {
+ case 0:
+ reply = vdt->display_RAM[vdt->cursor_address];
+ break;
+
+ case 1:
+ reply = vdt->keyboard_data & 0x7f;
+ if (vdt->keyboard_data_ready)
+ reply |= 0x80;
+ break;
+ }
+ }
+ else
+ { /* select word 1 */
+ switch (offset)
+ {
+ case 0:
+ reply = vdt->cursor_address & 0xff;
+ break;
+
+ case 1:
+ reply = (vdt->cursor_address >> 8) & 0x07;
+ if (vdt->keyboard_data & 0x80)
+ reply |= 0x08;
+ /*if (! vdt->terminal_ready)
+ reply |= 0x10;*/
+ if (vdt->previous_word_select)
+ reply |= 0x20;
+ /*if (vdt->keyboard_parity_error)
+ reply |= 0x40;*/
+ if (vdt->keyboard_data_ready)
+ reply |= 0x80;
+ break;
+ }
+ }
+
+ return reply;
+}
+
+/*
+ CRU interface write
+*/
+WRITE8_DEVICE_HANDLER( vdt911_cru_w )
+{
+ vdt_t *vdt = get_safe_token(device);
+ offset &= 0xf;
+
+ if (! vdt->word_select)
+ { /* select word 0 */
+ switch (offset)
+ {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ /* display memory write data */
+ if (data)
+ vdt->data_reg |= (1 << offset);
+ else
+ vdt->data_reg &= ~ (1 << offset);
+ break;
+
+ case 0x8:
+ /* write data strobe */
+ vdt->display_RAM[vdt->cursor_address] = vdt->data_reg;
+ break;
+
+ case 0x9:
+ /* test mode */
+ /* ... */
+ break;
+
+ case 0xa:
+ /* cursor move */
+ if (data)
+ vdt->cursor_address--;
+ else
+ vdt->cursor_address++;
+ vdt->cursor_address &= vdt->cursor_address_mask;
+ break;
+
+ case 0xb:
+ /* blinking cursor enable */
+ vdt->blinking_cursor_enable = data;
+ break;
+
+ case 0xc:
+ /* keyboard interrupt enable */
+ vdt->keyboard_interrupt_enable = data;
+ (*vdt->int_callback)(device->machine(), vdt->keyboard_interrupt_enable && vdt->keyboard_data_ready);
+ break;
+
+ case 0xd:
+ /* dual intensity enable */
+ vdt->dual_intensity_enable = data;
+ break;
+
+ case 0xe:
+ /* display enable */
+ vdt->display_enable = data;
+ break;
+
+ case 0xf:
+ /* select word */
+ vdt->previous_word_select = vdt->word_select;
+ vdt->word_select = data;
+ break;
+ }
+ }
+ else
+ { /* select word 1 */
+ switch (offset)
+ {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ case 0x8:
+ case 0x9:
+ case 0xa:
+ /* cursor address */
+ if (data)
+ vdt->cursor_address |= (1 << offset);
+ else
+ vdt->cursor_address &= ~ (1 << offset);
+ vdt->cursor_address &= vdt->cursor_address_mask;
+ break;
+
+ case 0xb:
+ /* not used */
+ break;
+
+ case 0xc:
+ /* display cursor */
+ vdt->display_cursor = data;
+ break;
+
+ case 0xd:
+ /* keyboard acknowledge */
+ if (vdt->keyboard_data_ready)
+ {
+ vdt->keyboard_data_ready = 0;
+ if (vdt->keyboard_interrupt_enable)
+ (*vdt->int_callback)(device->machine(), 0);
+ }
+ /*vdt->keyboard_parity_error = 0;*/
+ break;
+
+ case 0xe:
+ /* beep enable strobe - not tested */
+ beep_set_state(device->machine().device(BEEPER_TAG), 1);
+
+ vdt->beep_timer->adjust(attotime::from_usec(300));
+ break;
+
+ case 0xf:
+ /* select word */
+ vdt->previous_word_select = vdt->word_select;
+ vdt->word_select = data;
+ break;
+ }
+ }
+}
+
+/*
+ Video refresh
+*/
+void vdt911_refresh(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y)
+{
+ vdt_t *vdt = get_safe_token(device);
+ const gfx_element *gfx = device->machine().gfx[vdt->model];
+ int height = (vdt->screen_size == char_960) ? 12 : /*25*/24;
+ int use_8bit_charcodes = USES_8BIT_CHARCODES(vdt);
+ int address = 0;
+ int i, j;
+ int cur_char;
+ int color;
+
+ /*if (use_8bit_charcodes)
+ color = vdt->dual_intensity_enable ? 1 : 0;*/
+
+ if (! vdt->display_enable)
+ {
+ rectangle my_rect(x, x + 80*7 - 1, y, y + height*10 - 1);
+
+ bitmap.fill(0, my_rect);
+ }
+ else
+ for (i=0; i<height; i++)
+ {
+ for (j=0; j<80; j++)
+ {
+ cur_char = vdt->display_RAM[address];
+ /* does dual intensity work with 8-bit character set? */
+ color = (vdt->dual_intensity_enable && (cur_char & 0x80)) ? 1 : 0;
+ if (! use_8bit_charcodes)
+ cur_char &= 0x7f;
+
+ /* display cursor in reverse video */
+ if ((address == vdt->cursor_address) && vdt->display_cursor
+ && ((! vdt->blinking_cursor_enable) || vdt->blink_state))
+ color += 2;
+
+ address++;
+
+ drawgfx_opaque(bitmap, cliprect, gfx, cur_char, color, 0, 0,
+ x+j*7, y+i*10);
+ }
+ }
+}
+
+static const unsigned char (*const key_translate[])[91] =
+{ /* array must use same order as vdt911_model_t!!! */
+ /* US */
+ US_key_translate,
+ /* UK */
+ US_key_translate,
+ /* French */
+ French_key_translate,
+ /* German */
+ German_key_translate,
+ /* Swedish */
+ Swedish_key_translate,
+ /* Norwegian */
+ Norwegian_key_translate,
+ /* Japanese */
+ Japanese_key_translate,
+ /* Arabic */
+ /*Arabic_key_translate,*/
+ /* FrenchWP */
+ FrenchWP_key_translate
+};
+
+/*
+ keyboard handler: should be called regularly by machine code, for instance
+ every Video Blank Interrupt.
+*/
+void vdt911_keyboard(device_t *device)
+{
+ vdt_t *vdt = get_safe_token(device);
+
+ typedef enum
+ {
+ /* states for western keyboards and katakana/arabic keyboards in romaji/latin mode */
+ lower_case = 0, upper_case, shift, control,
+ /* states for katakana/arabic keyboards in katakana/arabic mode */
+ foreign, foreign_shift,
+ /* special value to stop repeat if the modifier state changes */
+ special_debounce = -1
+ } modifier_state_t;
+
+ static unsigned char repeat_timer;
+ enum { repeat_delay = 5 /* approx. 1/10s */ };
+
+ UINT16 key_buf[6];
+ int i, j;
+ modifier_state_t modifier_state;
+ int repeat_mode;
+
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5" };
+
+ /* read current key state */
+ for (i = 0; i < 6; i++)
+ {
+ key_buf[i] = device->machine().root_device().ioport(keynames[i])->read();
+ }
+
+ /* parse modifier keys */
+ if ((USES_8BIT_CHARCODES(vdt))
+ && ((key_buf[5] & 0x0400) || ((!(key_buf[5] & 0x0100)) && vdt->foreign_mode)))
+ { /* we are in katakana/arabic mode */
+ vdt->foreign_mode = TRUE;
+
+ if ((key_buf[4] & 0x0400) || (key_buf[5] & 0x0020))
+ modifier_state = foreign_shift;
+ else
+ modifier_state = foreign;
+ }
+ else
+ { /* we are using a western keyboard, or a katakana/arabic keyboard in
+ romaji/latin mode */
+ vdt->foreign_mode = FALSE;
+
+ if (key_buf[3] & 0x0040)
+ modifier_state = control;
+ else if ((key_buf[4] & 0x0400) || (key_buf[5] & 0x0020))
+ modifier_state = shift;
+ else if ((key_buf[0] & 0x2000))
+ modifier_state = upper_case;
+ else
+ modifier_state = lower_case;
+ }
+
+
+ /* test repeat key */
+ repeat_mode = key_buf[2] & 0x0002;
+
+
+ /* remove modifier keys */
+ key_buf[0] &= ~0x2000;
+ key_buf[2] &= ~0x0002;
+ key_buf[3] &= ~0x0040;
+ key_buf[4] &= ~0x0400;
+ key_buf[5] &= ~0x0120;
+
+ /* remove unused keys */
+ if (! HAS_EXTRA_KEY_91(vdt))
+ key_buf[5] &= ~0x0400;
+
+ if (! HAS_EXTRA_KEY_67(vdt))
+ key_buf[4] &= ~0x0004;
+
+
+ if (! repeat_mode)
+ /* reset REPEAT timer if the REPEAT key is not pressed */
+ repeat_timer = 0;
+
+ if (! (vdt->last_key_pressed & 0x80) && (key_buf[vdt->last_key_pressed >> 4] & (1 << (vdt->last_key_pressed & 0xf))))
+ {
+ /* last key has not been released */
+ if (modifier_state == vdt->last_modifier_state)
+ {
+ /* handle REPEAT mode if applicable */
+ if ((repeat_mode) && (++repeat_timer == repeat_delay))
+ {
+ if (vdt->keyboard_data_ready)
+ { /* keyboard buffer full */
+ repeat_timer--;
+ }
+ else
+ { /* repeat current key */
+ vdt->keyboard_data_ready = 1;
+ repeat_timer = 0;
+ }
+ }
+ }
+ else
+ {
+ repeat_timer = 0;
+ vdt->last_modifier_state = special_debounce;
+ }
+ }
+ else
+ {
+ vdt->last_key_pressed = 0x80;
+
+ if (vdt->keyboard_data_ready)
+ { /* keyboard buffer full */
+ /* do nothing */
+ }
+ else
+ {
+ for (i=0; i<6; i++)
+ {
+ for (j=0; j<16; j++)
+ {
+ if (key_buf[i] & (1 << j))
+ {
+ vdt->last_key_pressed = (i << 4) | j;
+ vdt->last_modifier_state = modifier_state;
+
+ vdt->keyboard_data = (int)key_translate[vdt->model][modifier_state][vdt->last_key_pressed];
+ vdt->keyboard_data_ready = 1;
+ if (vdt->keyboard_interrupt_enable)
+ (*vdt->int_callback)(device->machine(), 1);
+ return;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/mess/video/911_vdt.h b/src/mess/video/911_vdt.h
new file mode 100644
index 00000000000..781565fad0e
--- /dev/null
+++ b/src/mess/video/911_vdt.h
@@ -0,0 +1,163 @@
+
+#define vdt911_chr_region "gfx1"
+
+enum
+{
+ /* 10 bytes per character definition */
+ vdt911_single_char_len = 10,
+
+ vdt911_US_chr_offset = 0,
+ vdt911_UK_chr_offset = vdt911_US_chr_offset+128*vdt911_single_char_len,
+ vdt911_german_chr_offset = vdt911_UK_chr_offset+128*vdt911_single_char_len,
+ vdt911_swedish_chr_offset = vdt911_german_chr_offset+128*vdt911_single_char_len,
+ vdt911_norwegian_chr_offset = vdt911_swedish_chr_offset+128*vdt911_single_char_len,
+ vdt911_frenchWP_chr_offset = vdt911_norwegian_chr_offset+128*vdt911_single_char_len,
+ vdt911_japanese_chr_offset = vdt911_frenchWP_chr_offset+128*vdt911_single_char_len,
+
+ vdt911_chr_region_len = vdt911_japanese_chr_offset+256*vdt911_single_char_len
+};
+
+GFXDECODE_EXTERN( vdt911 );
+
+typedef enum { char_960, char_1920 } vdt911_screen_size_t;
+typedef enum
+{
+ vdt911_model_US,
+ vdt911_model_UK,
+ vdt911_model_French,
+ vdt911_model_German,
+ vdt911_model_Swedish, /* Swedish/Finnish */
+ vdt911_model_Norwegian, /* Norwegian/Danish */
+ vdt911_model_Japanese, /* Katakana Japanese */
+ /*vdt911_model_Arabic,*//* Arabic */
+ vdt911_model_FrenchWP /* French word processing */
+} vdt911_model_t;
+
+typedef struct vdt911_init_params_t
+{
+ vdt911_screen_size_t screen_size;
+ vdt911_model_t model;
+ void (*int_callback)(running_machine &machine, int state);
+} vdt911_init_params_t;
+
+PALETTE_INIT( vdt911 );
+
+void vdt911_init(running_machine &machine);
+DECLARE_LEGACY_DEVICE(VDT911, vdt911);
+
+#define MCFG_VDT911_VIDEO_ADD(_tag, _intf) \
+ MCFG_DEVICE_ADD(_tag, VDT911, 0) \
+ MCFG_DEVICE_CONFIG(_intf)
+
+
+ READ8_DEVICE_HANDLER(vdt911_cru_r);
+WRITE8_DEVICE_HANDLER(vdt911_cru_w);
+
+void vdt911_refresh(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y);
+
+void vdt911_keyboard(device_t *device);
+
+#define VDT911_KEY_PORTS \
+ PORT_START("KEY0") /* keys 1-16 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) \
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) \
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) \
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) \
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) \
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) \
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CMD") PORT_CODE(KEYCODE_F9) \
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(red)") PORT_CODE(KEYCODE_F10) \
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ERASE FIELD") PORT_CODE(KEYCODE_END) \
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ERASE INPUT") PORT_CODE(KEYCODE_PGDN) \
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(grey)") PORT_CODE(KEYCODE_F11) \
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("UPPER CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE\
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) \
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 @") PORT_CODE(KEYCODE_2) \
+ \
+ PORT_START("KEY1") /* keys 17-32 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) \
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 ^") PORT_CODE(KEYCODE_6) \
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7) \
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8) \
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9) \
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0) \
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("+ [") PORT_CODE(KEYCODE_MINUS) \
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- ]") PORT_CODE(KEYCODE_EQUALS) \
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("_ =") PORT_CODE(KEYCODE_BACKSPACE) \
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) \
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 (numpad)") PORT_CODE(KEYCODE_7_PAD) \
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 (numpad)") PORT_CODE(KEYCODE_8_PAD) \
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (numpad)") PORT_CODE(KEYCODE_9_PAD) \
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("PRINT") PORT_CODE(KEYCODE_PRTSCR) \
+ \
+ PORT_START("KEY2") /* keys 33-48 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(up)") PORT_CODE(KEYCODE_UP) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("REPEAT") PORT_CODE(KEYCODE_LALT) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER_PAD) \
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) \
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) \
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) \
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) \
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) \
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) \
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) \
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) \
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) \
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) \
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CHAR (left/right)") PORT_CODE(KEYCODE_OPENBRACE) \
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("FIELD (left/right)") PORT_CODE(KEYCODE_CLOSEBRACE) \
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) \
+ \
+ PORT_START("KEY3") /* keys 49-64 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 (numpad)") PORT_CODE(KEYCODE_4_PAD) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 (numpad)") PORT_CODE(KEYCODE_5_PAD) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 (numpad)") PORT_CODE(KEYCODE_6_PAD) \
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(left)") PORT_CODE(KEYCODE_LEFT) \
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("HOME") PORT_CODE(KEYCODE_HOME) \
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(right)") PORT_CODE(KEYCODE_RIGHT) \
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL) \
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) \
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) \
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) \
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) \
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) \
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) \
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) \
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) \
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) \
+ \
+ PORT_START("KEY4") /* keys 65-80 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(not on US keyboard)") PORT_CODE(KEYCODE_BACKSLASH) \
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SKIP TAB") PORT_CODE(KEYCODE_TAB) \
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 (numpad)") PORT_CODE(KEYCODE_1_PAD) \
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 (numpad)") PORT_CODE(KEYCODE_2_PAD) \
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 (numpad)") PORT_CODE(KEYCODE_3_PAD) \
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("INS CHAR") PORT_CODE(KEYCODE_INSERT) \
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(down)") PORT_CODE(KEYCODE_DOWN) \
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DEL CHAR") PORT_CODE(KEYCODE_DEL) \
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) \
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) \
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) \
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) \
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) \
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) \
+ \
+ PORT_START("KEY5") /* keys 81-91 */ \
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) \
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) \
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) \
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) \
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) \
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_RSHIFT) \
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 (numpad)") PORT_CODE(KEYCODE_0_PAD) \
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". (numpad)") PORT_CODE(KEYCODE_DEL_PAD) \
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(not on US keyboard)") PORT_CODE(KEYCODE_MINUS_PAD) \
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) \
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(not on US keyboard)") PORT_CODE(KEYCODE_PLUS_PAD)
+
diff --git a/src/mess/video/a7800.c b/src/mess/video/a7800.c
new file mode 100644
index 00000000000..2936f532eb1
--- /dev/null
+++ b/src/mess/video/a7800.c
@@ -0,0 +1,584 @@
+/***************************************************************************
+
+ video/a7800.c
+
+ Routines to control the Atari 7800 video hardware
+
+ TODO:
+ precise DMA cycle stealing
+
+ 2003-06-23 ericball Kangaroo mode & 320 mode & other stuff
+
+ 2002-05-14 kubecj vblank dma stop fix
+
+ 2002-05-13 kubecj fixed 320C mode (displayed 2 pixels instead of one!)
+ noticed that Jinks uses 0x02-320D mode
+ implemented the mode - completely unsure if good!
+ implemented some Maria CTRL variables
+
+ 2002-05-12 kubecj added cases for 0x01-160A, 0x05-160B as stated by docs
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+
+#include "includes/a7800.h"
+
+
+#define TRIGGER_HSYNC 64717
+
+#define READ_MEM(x) space->read_byte(x)
+
+/********** Maria ***********/
+
+#define DPPH 0x2c
+#define DPPL 0x30
+#define CTRL 0x3c
+
+
+
+
+// 20030621 ericball define using logical operations
+#define inc_hpos() { hpos = (hpos + 1) & 0x1FF; }
+#define inc_hpos_by_2() { hpos = (hpos + 2) & 0x1FF; }
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( a7800 )
+{
+ a7800_state *state = machine.driver_data<a7800_state>();
+ int i;
+
+ for(i=0; i<8; i++)
+ {
+ state->m_maria_palette[i][0]=0;
+ state->m_maria_palette[i][1]=0;
+ state->m_maria_palette[i][2]=0;
+ state->m_maria_palette[i][3]=0;
+ }
+
+ state->m_maria_write_mode=0;
+ state->m_maria_scanline=0;
+ state->m_maria_dmaon=0;
+ state->m_maria_vblank=0x80;
+ state->m_maria_dll=0;
+ state->m_maria_dodma=0;
+ state->m_maria_wsync=0;
+
+ state->m_maria_color_kill = 0;
+ state->m_maria_cwidth = 0;
+ state->m_maria_bcntl = 0;
+ state->m_maria_kangaroo = 0;
+ state->m_maria_rm = 0;
+
+ machine.primary_screen->register_screen_bitmap(state->m_bitmap);
+}
+
+/***************************************************************************
+
+ Stop the video hardware emulation.
+
+***************************************************************************/
+
+static void maria_draw_scanline(running_machine &machine)
+{
+ a7800_state *state = machine.driver_data<a7800_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ unsigned int graph_adr,data_addr;
+ int width,hpos,pal,mode,ind;
+ unsigned int dl;
+ int x, d, c, i;
+ int ind_bytes;
+ UINT16 *scanline;
+
+ /* set up scanline */
+ scanline = &state->m_bitmap.pix16(state->m_maria_scanline);
+ for (i = 0; i < 320; i++)
+ scanline[i] = state->m_maria_backcolor;
+
+ /* Process this DLL entry */
+ dl = state->m_maria_dl;
+
+ /* Step through DL's */
+ while ((READ_MEM(dl + 1) & 0x5F) != 0)
+ {
+
+ /* Extended header */
+ if (!(READ_MEM(dl+1) & 0x1F))
+ {
+ graph_adr = (READ_MEM(dl+2) << 8) | READ_MEM(dl);
+ width = ((READ_MEM(dl+3) ^ 0xff) & 0x1F) + 1;
+ hpos = READ_MEM(dl+4)*2;
+ pal = READ_MEM(dl+3) >> 5;
+ state->m_maria_write_mode = (READ_MEM(dl+1) & 0x80) >> 5;
+ ind = READ_MEM(dl+1) & 0x20;
+ dl+=5;
+ }
+ /* Normal header */
+ else
+ {
+ graph_adr = (READ_MEM(dl+2) << 8) | READ_MEM(dl);
+ width = ((READ_MEM(dl+1) ^ 0xff) & 0x1F) + 1;
+ hpos = READ_MEM(dl+3)*2;
+ pal = READ_MEM(dl+1) >> 5;
+ ind = 0x00;
+ dl+=4;
+ }
+
+ mode = state->m_maria_rm | state->m_maria_write_mode;
+
+ /*logerror("%x DL: ADR=%x width=%x hpos=%x pal=%x mode=%x ind=%x\n",state->m_maria_scanline,graph_adr,width,hpos,pal,mode,ind );*/
+
+ for (x=0; x<width; x++) // 20030621 ericball get graphic data first, then switch (mode)
+ {
+ ind_bytes = 1;
+
+ /* Do indirect mode */
+ if (ind)
+ {
+ c = READ_MEM(graph_adr + x) & 0xFF;
+ data_addr= (state->m_maria_charbase | c) + (state->m_maria_offset << 8);
+ if( state->m_maria_cwidth )
+ ind_bytes = 2;
+ }
+ else
+ {
+ data_addr = graph_adr + x + (state->m_maria_offset << 8);
+ }
+
+ if ( (state->m_maria_holey & 0x02) && ((data_addr & 0x9000) == 0x9000))
+ continue;
+ if ( (state->m_maria_holey & 0x01) && ((data_addr & 0x8800) == 0x8800))
+ continue;
+
+ while (ind_bytes > 0)
+ {
+ ind_bytes--;
+ d = READ_MEM(data_addr++);
+
+ switch (mode)
+ {
+ case 0x00: /* 160A (160x2) */
+ case 0x01: /* 160A (160x2) */
+ c = (d & 0xC0) >> 6;
+ if (c || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][c];
+ scanline[hpos + 1] = state->m_maria_palette[pal][c];
+ }
+ inc_hpos_by_2();
+
+ c = (d & 0x30) >> 4;
+ if (c || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][c];
+ scanline[hpos + 1] = state->m_maria_palette[pal][c];
+ }
+ inc_hpos_by_2();
+
+ c = (d & 0x0C) >> 2;
+ if (c || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][c];
+ scanline[hpos + 1] = state->m_maria_palette[pal][c];
+ }
+ inc_hpos_by_2();
+
+ c = (d & 0x03);
+ if (c || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][c];
+ scanline[hpos + 1] = state->m_maria_palette[pal][c];
+ }
+ inc_hpos_by_2();
+ break;
+
+ case 0x02: /* 320D used by Jinks! */
+ c = pal & 0x04;
+ if ( d & 0xC0 || pal & 0x03 || state->m_maria_kangaroo )
+ {
+ scanline[hpos + 0] = state->m_maria_palette[c][((d & 0x80) >> 6) | ((pal & 2) >> 1)];
+ scanline[hpos + 1] = state->m_maria_palette[c][((d & 0x40) >> 5) | ((pal & 1) >> 0)];
+ }
+ inc_hpos_by_2();
+
+ if ( d & 0x30 || pal & 0x03 || state->m_maria_kangaroo )
+ {
+ scanline[hpos + 0] = state->m_maria_palette[c][((d & 0x20) >> 4) | ((pal & 2) >> 1)];
+ scanline[hpos + 1] = state->m_maria_palette[c][((d & 0x10) >> 3) | ((pal & 1) >> 0)];
+ }
+ inc_hpos_by_2();
+
+ if ( d & 0x0C || pal & 0x03 || state->m_maria_kangaroo )
+ {
+ scanline[hpos + 0] = state->m_maria_palette[c][((d & 0x08) >> 2) | ((pal & 2) >> 1)];
+ scanline[hpos + 1] = state->m_maria_palette[c][((d & 0x04) >> 1) | ((pal & 1) >> 0)];
+ }
+ inc_hpos_by_2();
+
+ if ( d & 0x03 || pal & 0x03 || state->m_maria_kangaroo )
+ {
+ scanline[hpos + 0] = state->m_maria_palette[c][((d & 0x02) << 0) | ((pal & 2) >> 1)];
+ scanline[hpos + 1] = state->m_maria_palette[c][((d & 0x01) << 1) | ((pal & 1) >> 0)];
+ }
+ inc_hpos_by_2();
+
+ break;
+
+ case 0x03: /* MODE 320A */
+ if (d & 0xC0 || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][(d & 0x80) >> 6];
+ scanline[hpos + 1] = state->m_maria_palette[pal][(d & 0x40) >> 5];
+ }
+ inc_hpos_by_2();
+
+ if ( d & 0x30 || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][(d & 0x20) >> 4];
+ scanline[hpos + 1] = state->m_maria_palette[pal][(d & 0x10) >> 3];
+ }
+ inc_hpos_by_2();
+
+ if (d & 0x0C || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][(d & 0x08) >> 2];
+ scanline[hpos + 1] = state->m_maria_palette[pal][(d & 0x04) >> 1];
+ }
+ inc_hpos_by_2();
+
+ if (d & 0x03 || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][(d & 0x02)];
+ scanline[hpos + 1] = state->m_maria_palette[pal][(d & 0x01) << 1];
+ }
+ inc_hpos_by_2();
+ break;
+
+ case 0x04: /* 160B (160x4) */
+ case 0x05: /* 160B (160x4) */
+ c = (d & 0xC0) >> 6;
+ if (c || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[(pal & 0x04) | ((d & 0x0C) >> 2)][c];
+ scanline[hpos + 1] = state->m_maria_palette[(pal & 0x04) | ((d & 0x0C) >> 2)][c];
+ }
+ inc_hpos_by_2();
+
+ c = (d & 0x30) >> 4;
+ if (c || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[(pal & 0x04) | (d & 0x03)][c];
+ scanline[hpos + 1] = state->m_maria_palette[(pal & 0x04) | (d & 0x03)][c];
+ }
+ inc_hpos_by_2();
+ break;
+
+ case 0x06: /* MODE 320B */
+ if (d & 0xCC || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][((d & 0x80) >> 6) | ((d & 0x08) >> 3)];
+ scanline[hpos + 1] = state->m_maria_palette[pal][((d & 0x40) >> 5) | ((d & 0x04) >> 2)];
+ }
+ inc_hpos_by_2();
+
+ if ( d & 0x33 || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[pal][((d & 0x20) >> 4) | ((d & 0x02) >> 1)];
+ scanline[hpos + 1] = state->m_maria_palette[pal][((d & 0x10) >> 3) | (d & 0x01)];
+ }
+ inc_hpos_by_2();
+ break;
+
+ case 0x07: /* (320C mode) */
+ if (d & 0xC0 || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[(pal & 0x04) | ((d & 0x0C) >> 2)][(d & 0x80) >> 6];
+ scanline[hpos + 1] = state->m_maria_palette[(pal & 0x04) | ((d & 0x0C) >> 2)][(d & 0x40) >> 5];
+ }
+ inc_hpos_by_2();
+
+ if ( d & 0x30 || state->m_maria_kangaroo)
+ {
+ scanline[hpos + 0] = state->m_maria_palette[(pal & 0x04) | (d & 0x03)][(d & 0x20) >> 4];
+ scanline[hpos + 1] = state->m_maria_palette[(pal & 0x04) | (d & 0x03)][(d & 0x10) >> 3];
+ }
+ inc_hpos_by_2();
+ break;
+
+ } /* endswitch (mode) */
+ } /* endwhile (ind_bytes > 0)*/
+ } /* endfor (x=0; x<width; x++) */
+ } /* endwhile (READ_MEM(dl + 1) != 0) */
+}
+
+
+TIMER_DEVICE_CALLBACK( a7800_interrupt )
+{
+ a7800_state *state = timer.machine().driver_data<a7800_state>();
+ int frame_scanline;
+ UINT8 *ROM = timer.machine().root_device().memregion("maincpu")->base();
+ address_space* space = timer.machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ state->m_maria_scanline++;
+
+ /* why + 1? */
+ frame_scanline = state->m_maria_scanline % ( state->m_lines + 1 );
+
+ if( frame_scanline == 1 )
+ {
+ /*logerror( "frame beg\n" );*/
+ }
+
+ if( state->m_maria_wsync )
+ {
+ timer.machine().scheduler().trigger( TRIGGER_HSYNC );
+ state->m_maria_wsync = 0;
+ }
+
+ if( frame_scanline == 16 )
+ {
+ /* end of vblank */
+
+ state->m_maria_vblank=0;
+ if( state->m_maria_dmaon || state->m_maria_dodma )
+ {
+ state->m_maria_dodma = 1; /* if dma allowed, start it */
+
+ state->m_maria_dll = (ROM[DPPH] << 8) | ROM[DPPL];
+ state->m_maria_dl = (READ_MEM(state->m_maria_dll+1) << 8) | READ_MEM(state->m_maria_dll+2);
+ state->m_maria_offset = READ_MEM(state->m_maria_dll) & 0x0f;
+ state->m_maria_holey = (READ_MEM(state->m_maria_dll) & 0x60) >> 5;
+ state->m_maria_dli = READ_MEM(state->m_maria_dll) & 0x80;
+ /* logerror("DLL=%x\n",state->m_maria_dll); */
+ /* logerror("DLL: DL = %x dllctrl = %x\n",state->m_maria_dl,ROM[state->m_maria_dll]); */
+ }
+
+ /*logerror( "vblank end on line %d\n", frame_scanline );*/
+ }
+
+ /* moved start of vblank up (to prevent dma/dli happen on line -4)
+ this fix made PR Baseball happy
+ Kung-Fu Master looks worse
+ don't know about others yet */
+ if( frame_scanline == ( state->m_lines - 4 ) )
+ {
+ /* vblank starts 4 scanlines before end of screen */
+
+ state->m_maria_vblank = 0x80;
+
+ /* fixed 2002/05/14 kubecj
+ when going vblank, dma must be stopped
+ otherwise system tries to read past end of dll
+ causing false dlis to occur, mainly causing wild
+ screen flickering
+
+ games fixed:
+ Ace of Aces
+ Mean 18
+ Ninja Golf (end of levels)
+ Choplifter
+ Impossible Mission
+ Jinks
+ */
+
+ state->m_maria_dodma = 0;
+ /*logerror( "vblank on line %d\n\n", frame_scanline );*/
+ }
+
+
+ if( ( frame_scanline > 15 ) && state->m_maria_dodma )
+ {
+ if (state->m_maria_scanline < ( state->m_lines - 4 ) )
+ maria_draw_scanline(timer.machine());
+
+ if( state->m_maria_offset == 0 )
+ {
+ state->m_maria_dll+=3;
+ state->m_maria_dl = (READ_MEM(state->m_maria_dll+1) << 8) | READ_MEM(state->m_maria_dll+2);
+ state->m_maria_offset = READ_MEM(state->m_maria_dll) & 0x0f;
+ state->m_maria_holey = (READ_MEM(state->m_maria_dll) & 0x60) >> 5;
+ state->m_maria_dli = READ_MEM(state->m_maria_dll) & 0x80;
+ }
+ else
+ {
+ state->m_maria_offset--;
+ }
+ }
+
+ if( state->m_maria_dli )
+ {
+ /*logerror( "dli on line %d [%02X] [%02X] [%02X]\n", frame_scanline, ROM[0x7E], ROM[0x7C], ROM[0x7D] );*/
+ }
+
+ if( state->m_maria_dli )
+ {
+ state->m_maria_dli = 0;
+ device_set_input_line(state->m_maincpu, INPUT_LINE_NMI, PULSE_LINE);
+ }
+
+}
+
+/***************************************************************************
+
+ Refresh the video screen
+
+***************************************************************************/
+/* This routine is called at the start of vblank to refresh the screen */
+SCREEN_UPDATE_IND16( a7800 )
+{
+ a7800_state *state = screen.machine().driver_data<a7800_state>();
+ state->m_maria_scanline = 0;
+ copybitmap(bitmap, state->m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+
+/****** MARIA ***************************************/
+
+READ8_MEMBER(a7800_state::a7800_MARIA_r)
+{
+ UINT8 *ROM = memregion("maincpu")->base();
+ switch (offset)
+ {
+ case 0x08:
+ return m_maria_vblank;
+
+ default:
+ logerror("undefined MARIA read %x\n",offset);
+ return ROM[0x20 + offset];
+ }
+}
+
+WRITE8_MEMBER(a7800_state::a7800_MARIA_w)
+{
+ UINT8 *ROM = memregion("maincpu")->base();
+ switch (offset)
+ {
+ case 0x00:
+ m_maria_backcolor = data;
+ // 20030621 ericball added m_maria_palette[pal][0] to make kanagroo mode easier
+ m_maria_palette[0][0]=m_maria_backcolor;
+ m_maria_palette[1][0]=m_maria_backcolor;
+ m_maria_palette[2][0]=m_maria_backcolor;
+ m_maria_palette[3][0]=m_maria_backcolor;
+ m_maria_palette[4][0]=m_maria_backcolor;
+ m_maria_palette[5][0]=m_maria_backcolor;
+ m_maria_palette[6][0]=m_maria_backcolor;
+ m_maria_palette[7][0]=m_maria_backcolor;
+ break;
+ case 0x01:
+ m_maria_palette[0][1] = data;
+ break;
+ case 0x02:
+ m_maria_palette[0][2] = data;
+ break;
+ case 0x03:
+ m_maria_palette[0][3] = data;
+ break;
+ case 0x04:
+ device_spin_until_trigger(machine().device("maincpu"), TRIGGER_HSYNC);
+ m_maria_wsync=1;
+ break;
+
+ case 0x05:
+ m_maria_palette[1][1] = data;
+ break;
+ case 0x06:
+ m_maria_palette[1][2] = data;
+ break;
+ case 0x07:
+ m_maria_palette[1][3] = data;
+ break;
+
+ case 0x09:
+ m_maria_palette[2][1] = data;
+ break;
+ case 0x0A:
+ m_maria_palette[2][2] = data;
+ break;
+ case 0x0B:
+ m_maria_palette[2][3] = data;
+ break;
+
+ case 0x0D:
+ m_maria_palette[3][1] = data;
+ break;
+ case 0x0E:
+ m_maria_palette[3][2] = data;
+ break;
+ case 0x0F:
+ m_maria_palette[3][3] = data;
+ break;
+
+ case 0x11:
+ m_maria_palette[4][1] = data;
+ break;
+ case 0x12:
+ m_maria_palette[4][2] = data;
+ break;
+ case 0x13:
+ m_maria_palette[4][3] = data;
+ break;
+ case 0x14:
+ m_maria_charbase = (data << 8);
+ break;
+ case 0x15:
+ m_maria_palette[5][1] = data;
+ break;
+ case 0x16:
+ m_maria_palette[5][2] = data;
+ break;
+ case 0x17:
+ m_maria_palette[5][3] = data;
+ break;
+
+ case 0x19:
+ m_maria_palette[6][1] = data;
+ break;
+ case 0x1A:
+ m_maria_palette[6][2] = data;
+ break;
+ case 0x1B:
+ m_maria_palette[6][3] = data;
+ break;
+
+ case 0x1C:
+ /*logerror("MARIA CTRL=%x\n",data);*/
+ m_maria_color_kill = data & 0x80;
+ if ((data & 0x60) == 0x40)
+ m_maria_dmaon = 1;
+ else
+ m_maria_dmaon = m_maria_dodma = 0;
+
+ m_maria_cwidth = data & 0x10;
+ m_maria_bcntl = data & 0x08;
+ m_maria_kangaroo = data & 0x04;
+ m_maria_rm = data & 0x03;
+
+ /*logerror( "MARIA CTRL: CK:%d DMA:%d CW:%d BC:%d KM:%d RM:%d\n",
+ m_maria_color_kill ? 1 : 0,
+ ( data & 0x60 ) >> 5,
+ m_maria_cwidth ? 1 : 0,
+ m_maria_bcntl ? 1 : 0,
+ m_maria_kangaroo ? 1 : 0,
+ m_maria_rm );*/
+
+ break;
+ case 0x1D:
+ m_maria_palette[7][1] = data;
+ break;
+ case 0x1E:
+ m_maria_palette[7][2] = data;
+ break;
+ case 0x1F:
+ m_maria_palette[7][3] = data;
+ break;
+ }
+ ROM[ 0x20 + offset ] = data;
+}
+
diff --git a/src/mess/video/abc1600.c b/src/mess/video/abc1600.c
new file mode 100644
index 00000000000..bdfc54b5d74
--- /dev/null
+++ b/src/mess/video/abc1600.c
@@ -0,0 +1,1130 @@
+#include "includes/abc1600.h"
+#include "abc1600.lh"
+
+
+
+//**************************************************************************
+// CONSTANTS / MACROS
+//**************************************************************************
+
+#define LOG 0
+
+
+// video RAM
+#define VIDEORAM_SIZE 0x40000
+#define VIDEORAM16_MASK 0x3ffff
+#define VIDEORAM8_MASK 0x7fffe
+
+
+// flag register
+#define L_P BIT(m_flag, 0)
+#define BLANK BIT(m_flag, 1)
+#define PIX_POL BIT(m_flag, 2)
+#define FRAME_POL BIT(m_flag, 3)
+#define HOLD_FY BIT(m_flag, 4)
+#define HOLD_FX BIT(m_flag, 5)
+#define COMP_MOVE BIT(m_flag, 6)
+#define REPLACE BIT(m_flag, 7)
+
+
+// image position
+#define HFP 96
+#define VFP 23
+
+
+// IOWR0 registers
+enum
+{
+ LDSX_HB = 0,
+ LDSX_LB,
+ LDSY_HB,
+ LDSY_LB,
+ LDTX_HB,
+ LDTX_LB,
+ LDTY_HB,
+ LDTY_LB
+};
+
+
+// IOWR1 registers
+enum
+{
+ LDFX_HB = 0,
+ LDFX_LB,
+ LDFY_HB,
+ LDFY_LB,
+ WRML = 5,
+ WRDL = 7
+};
+
+
+// IOWR2 registers
+enum
+{
+ WRMASK_STROBE_HB = 0,
+ WRMASK_STROBE_LB,
+ ENABLE_CLOCKS,
+ FLAG_STROBE,
+ ENDISP
+};
+
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+//-------------------------------------------------
+// read_videoram -
+//-------------------------------------------------
+
+inline UINT16 abc1600_state::read_videoram(UINT32 offset)
+{
+ return m_video_ram[offset & VIDEORAM16_MASK];
+}
+
+
+//-------------------------------------------------
+// write_videoram -
+//-------------------------------------------------
+
+inline void abc1600_state::write_videoram(UINT32 offset, UINT16 data, UINT16 mask)
+{
+ UINT16 old_data = m_video_ram[offset & VIDEORAM16_MASK];
+
+ m_video_ram[offset & VIDEORAM16_MASK] = (data & mask) | (old_data & (mask ^ 0xffff));
+}
+
+
+//-------------------------------------------------
+// video_ram_r -
+//-------------------------------------------------
+
+READ8_MEMBER( abc1600_state::video_ram_r )
+{
+ UINT32 addr = (offset & VIDEORAM8_MASK) >> 1;
+ UINT8 data = 0;
+
+ if (offset & 0x01)
+ {
+ data = m_video_ram[addr] & 0xff;
+ }
+ else
+ {
+ data = m_video_ram[addr] >> 8;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// video_ram_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc1600_state::video_ram_w )
+{
+ UINT32 addr = (offset & VIDEORAM8_MASK) >> 1;
+
+ if (offset & 0x01)
+ {
+ if (REPLACE)
+ {
+ // WRPORT_LB
+ m_wrm = (m_wrm & 0xff00) | data;
+ if (LOG) logerror("WRM LB %02x -> %04x\n", data, m_wrm);
+ }
+ else
+ {
+ // DATAPORT_LB
+ m_gmdi = (m_gmdi & 0xff00) | data;
+ if (LOG) logerror("GMDI LB %02x -> %04x\n", data, m_gmdi);
+ }
+
+ write_videoram(addr, m_gmdi, m_wrm & 0x00ff);
+
+ if (LOG) logerror("Video RAM write LB to %05x : %04x\n", addr, m_video_ram[addr]);
+ }
+ else
+ {
+ if (REPLACE)
+ {
+ // WRPORT_HB
+ m_wrm = (data << 8) | (m_wrm & 0xff);
+ if (LOG) logerror("WRM HB %02x -> %04x\n", data, m_wrm);
+ }
+ else
+ {
+ // DATAPORT_HB
+ m_gmdi = (data << 8) | (m_gmdi & 0xff);
+ if (LOG) logerror("GMDI HB %02x -> %04x\n", data, m_gmdi);
+ }
+
+ write_videoram(addr, m_gmdi, m_wrm & 0xff00);
+
+ if (LOG) logerror("Video RAM write HB to %05x : %04x\n", addr, m_video_ram[addr]);
+ }
+}
+
+
+//-------------------------------------------------
+// iord0_r -
+//-------------------------------------------------
+
+READ8_MEMBER( abc1600_state::iord0_r )
+{
+ /*
+
+ bit description
+
+ 0 0
+ 1 SCREENPOS
+ 2
+ 3
+ 4
+ 5
+ 6 VSYNC
+ 7 BUSY
+
+ */
+
+ UINT8 data = 0;
+
+ // monitor orientation (portrait/landscape)
+ data |= machine().render().first_target()->view() << 1;
+
+ // vertical sync
+ data |= m_crtc->vsync_r() << 6;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// iowr0_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc1600_state::iowr0_w )
+{
+ switch (offset & 0x07)
+ {
+ case LDSX_HB:
+ /*
+
+ bit description
+
+ 0 XSIZE8
+ 1 XSIZE9
+ 2 U/D* Y
+ 3 U/D* X
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("%s LDSX HB: %02x\n", machine().describe_context(), data);
+
+ m_xsize = ((data & 0x03) << 8) | (m_xsize & 0xff);
+ m_udy = BIT(data, 2);
+ m_udx = BIT(data, 3);
+ break;
+
+ case LDSX_LB:
+ /*
+
+ bit description
+
+ 0 XSIZE0
+ 1 XSIZE1
+ 2 XSIZE2
+ 3 XSIZE3
+ 4 XSIZE4
+ 5 XSIZE5
+ 6 XSIZE6
+ 7 XSIZE7
+
+ */
+
+ if (LOG) logerror("%s LDSX LB: %02x\n", machine().describe_context(), data);
+
+ m_xsize = (m_xsize & 0x300) | data;
+ break;
+
+ case LDSY_HB:
+ /*
+
+ bit description
+
+ 0 YSIZE8
+ 1 YSIZE9
+ 2 YSIZE10
+ 3 YSIZE11
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("%s LDSY HB: %02x\n", machine().describe_context(), data);
+
+ m_ysize = ((data & 0x0f) << 8) | (m_ysize & 0xff);
+ break;
+
+ case LDSY_LB:
+ /*
+
+ bit description
+
+ 0 YSIZE0
+ 1 YSIZE1
+ 2 YSIZE2
+ 3 YSIZE3
+ 4 YSIZE4
+ 5 YSIZE5
+ 6 YSIZE6
+ 7 YSIZE7
+
+ */
+
+ if (LOG) logerror("%s LDSX LB: %02x\n", machine().describe_context(), data);
+
+ m_ysize = (m_ysize & 0xf00) | data;
+ break;
+
+ case LDTX_HB:
+ /*
+
+ bit description
+
+ 0 XTO8, MTA4
+ 1 XTO9, MTA5
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("%s LDTX HB: %02x\n", machine().describe_context(), data);
+
+ m_xto = ((data & 0x03) << 8) | (m_xto & 0xff);
+ m_mta = (m_mta & 0x3ffcf) | ((data & 0x03) << 4);
+ break;
+
+ case LDTX_LB:
+ /*
+
+ bit description
+
+ 0 XTO0
+ 1 XTO1
+ 2 XTO2
+ 3 XTO3
+ 4 XTO4, MTA0
+ 5 XTO5, MTA1
+ 6 XTO6, MTA2
+ 7 XTO7, MTA3
+
+ */
+
+ if (LOG) logerror("%s LDTX LB: %02x\n", machine().describe_context(), data);
+
+ m_xto = (m_xto & 0x300) | data;
+ m_mta = (m_mta & 0x3fff0) | (data >> 4);
+ break;
+
+ case LDTY_HB:
+ /*
+
+ bit description
+
+ 0 YTO8, MTA14
+ 1 YTO9, MTA15
+ 2 YTO10, MTA16
+ 3 YTO11, MTA17
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("%s LDTY HB: %02x\n", machine().describe_context(), data);
+
+ m_ty = ((data & 0x0f) << 8) | (m_yto & 0xff);
+ m_yto = ((data & 0x0f) << 8) | (m_yto & 0xff);
+ m_mta = ((data & 0x0f) << 14) | (m_mta & 0x3fff);
+ break;
+
+ case LDTY_LB:
+ /*
+
+ bit description
+
+ 0 YTO0, MTA6
+ 1 YTO1, MTA7
+ 2 YTO2, MTA8
+ 3 YTO3, MTA9
+ 4 YTO4, MTA10
+ 5 YTO5, MTA11
+ 6 YTO6, MTA12
+ 7 YTO7, MTA13
+
+ */
+
+ if (LOG) logerror("%s LDTY LB: %02x\n", machine().describe_context(), data);
+
+ m_ty = (m_ty & 0xf00) | data;
+ m_yto = (m_yto & 0xf00) | data;
+ m_mta = (m_mta & 0x3c03f) | (data << 6);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// iowr1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc1600_state::iowr1_w )
+{
+ switch (offset & 0x07)
+ {
+ case LDFX_HB:
+ /*
+
+ bit description
+
+ 0 XFROM8, MFA4
+ 1 XFROM9, MFA5
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("%s LDFX HB: %02x\n", machine().describe_context(), data);
+
+ m_xfrom = ((data & 0x03) << 8) | (m_xfrom & 0xff);
+ m_mfa = (m_mfa & 0x3ffcf) | ((data & 0x03) << 4);
+ break;
+
+ case LDFX_LB:
+ /*
+
+ bit description
+
+ 0 XFROM0
+ 1 XFROM1
+ 2 XFROM2
+ 3 XFROM3
+ 4 XFROM4, MFA0
+ 5 XFROM5, MFA1
+ 6 XFROM6, MFA2
+ 7 XFROM7, MFA3
+
+ */
+
+ if (LOG) logerror("%s LDFX LB: %02x\n", machine().describe_context(), data);
+
+ m_xfrom = (m_xfrom & 0x300) | data;
+ m_mfa = (m_mfa & 0x3fff0) | (data >> 4);
+ break;
+
+ case LDFY_HB:
+ /*
+
+ bit description
+
+ 0 MFA14
+ 1 MFA15
+ 2 MFA16
+ 3 MFA17
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("%s LDFY HB: %02x\n", machine().describe_context(), data);
+
+ m_mfa = ((data & 0x0f) << 14) | (m_mfa & 0x3fff);
+ break;
+
+ case LDFY_LB:
+ /*
+
+ bit description
+
+ 0 MFA6
+ 1 MFA7
+ 2 MFA8
+ 3 MFA9
+ 4 MFA10
+ 5 MFA11
+ 6 MFA12
+ 7 MFA13
+
+ */
+
+ if (LOG) logerror("%s LDFY LB: %02x\n", machine().describe_context(), data);
+
+ m_mfa = (m_mfa & 0x3c03f) | (data << 6);
+
+ mover();
+ break;
+
+ case WRML:
+ /*
+
+ bit description
+
+ 0 MOVE CYK CLK
+ 1 DISP CYC SEL / DISP CYK PRE FETCH (+1 PIXCLK)
+ 2 DATA CLK
+ 3 _DISP MEM WE
+ 4 _CAS HB
+ 5 DTACK CLK / BLANK TEST (+2 PIXCLK)
+ 6 DISPREC CLK
+ 7 _RAS HB
+
+ */
+
+ if (LOG) logerror("MS %u : %02x\n", (offset >> 4) & 0x0f, data);
+
+ if (m_clocks_disabled)
+ {
+ m_ms[(offset >> 4) & 0x0f] = data;
+ }
+ break;
+
+ case WRDL:
+ /*
+
+ bit description
+
+ 0 MOVE CYK CLK
+ 1 DISP CYC SEL / DISP CYK PRE FETCH (+1 PIXCLK)
+ 2 DATA CLK
+ 3 _DISP MEM WE
+ 4 _CAS HB
+ 5 DTACK CLK / BLANK TEST (+2 PIXCLK)
+ 6 DISPREC CLK
+ 7 _RAS HB
+
+ */
+
+ if (LOG) logerror("WS %u : %02x\n", (offset >> 4) & 0x0f, data);
+
+ if (m_clocks_disabled)
+ {
+ m_ds[(offset >> 4) & 0x0f] = data;
+ }
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// iowr2_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc1600_state::iowr2_w )
+{
+ switch (offset & 0x07)
+ {
+ case WRMASK_STROBE_HB:
+ if (REPLACE)
+ {
+ // DATAPORT_HB
+ m_gmdi = (data << 8) | (m_gmdi & 0xff);
+ if (LOG) logerror("GMDI HB %04x\n", m_gmdi);
+ }
+ else
+ {
+ // WRPORT_HB
+ m_wrm = (data << 8) | (m_wrm & 0xff);
+ if (LOG) logerror("WRM HB %04x\n", m_gmdi);
+ }
+ break;
+
+ case WRMASK_STROBE_LB:
+ if (REPLACE)
+ {
+ // DATAPORT_LB
+ m_gmdi = (m_gmdi & 0xff00) | data;
+ if (LOG) logerror("GMDI LB %04x\n", m_gmdi);
+ }
+ else
+ {
+ // WRPORT_LB
+ m_wrm = (m_wrm & 0xff00) | data;
+ if (LOG) logerror("WRM LB %04x\n", m_gmdi);
+ }
+ break;
+
+ case ENABLE_CLOCKS:
+ if (LOG) logerror("ENABLE CLOCKS\n");
+ m_clocks_disabled = 0;
+ break;
+
+ case FLAG_STROBE:
+ /*
+
+ bit description
+
+ 0 L/_P FLAG
+ 1 BLANK FLAG
+ 2 PIX POL
+ 3 FRAME POL
+ 4 HOLD FY
+ 5 HOLD FX
+ 6 COMP MOVE FLAG
+ 7 REPLACE/SET & RESET
+
+ */
+
+ m_flag = data;
+ if (LOG) logerror("FLAG %02x\n", m_flag);
+ break;
+
+ case ENDISP:
+ if (LOG) logerror("ENDISP\n");
+ m_endisp = 1;
+ break;
+ }
+}
+
+
+
+//**************************************************************************
+// MOVER
+//**************************************************************************
+
+//-------------------------------------------------
+// clock_mfa_x -
+//-------------------------------------------------
+
+inline void abc1600_state::clock_mfa_x()
+{
+ UINT16 mfa_y = m_mfa >> 6;
+ UINT8 mfa_x = m_mfa & 0x3f;
+
+ if (!HOLD_FX)
+ {
+ mfa_x += m_udx ? 1 : -1;
+ mfa_x &= 0x3f;
+ }
+
+ m_mfa = (mfa_y << 6) | mfa_x;
+}
+
+
+//-------------------------------------------------
+// clock_mfa_y -
+//-------------------------------------------------
+
+inline void abc1600_state::clock_mfa_y()
+{
+ UINT16 mfa_y = m_mfa >> 6;
+ UINT8 mfa_x = m_mfa & 0x3f;
+
+ if (!HOLD_FY)
+ {
+ mfa_y += m_udy ? 1 : -1;
+ mfa_y &= 0xfff;
+ }
+
+ m_mfa = (mfa_y << 6) | mfa_x;
+}
+
+
+//-------------------------------------------------
+// clock_mta_x -
+//-------------------------------------------------
+
+inline void abc1600_state::clock_mta_x()
+{
+ UINT16 mta_y = m_mta >> 6;
+ UINT8 mta_x = m_mta & 0x3f;
+
+ mta_x += m_udx ? 1 : -1;
+ mta_x &= 0x3f;
+
+ m_mta = (mta_y << 6) | mta_x;
+}
+
+
+//-------------------------------------------------
+// clock_mta_y -
+//-------------------------------------------------
+
+inline void abc1600_state::clock_mta_y()
+{
+ UINT16 mta_y = m_mta >> 6;
+ UINT8 mta_x = m_mta & 0x3f;
+
+ mta_y += m_udy ? 1 : -1;
+ mta_y &= 0xfff;
+
+ m_mta = (mta_y << 6) | mta_x;
+}
+
+
+//-------------------------------------------------
+// load_mfa_x -
+//-------------------------------------------------
+
+inline void abc1600_state::load_mfa_x()
+{
+ UINT16 mfa_y = m_mfa >> 6;
+ UINT8 mfa_x = m_xfrom >> 4;
+
+ m_mfa = (mfa_y << 6) | mfa_x;
+}
+
+
+//-------------------------------------------------
+// load_mta_x -
+//-------------------------------------------------
+
+inline void abc1600_state::load_mta_x()
+{
+ UINT16 mta_y = m_mta >> 6;
+ UINT8 mta_x = m_xto >> 4;
+
+ m_mta = (mta_y << 6) | mta_x;
+}
+
+
+//-------------------------------------------------
+// load_xy_reg -
+//-------------------------------------------------
+
+inline void abc1600_state::load_xy_reg()
+{
+ if (L_P) return;
+
+ UINT16 sum = m_xto + m_xsize;
+
+ m_xto = sum & 0x3ff;
+ m_yto = m_ty & 0xfff;
+ m_mta = (m_ty << 6) | (sum >> 4);
+}
+
+
+//-------------------------------------------------
+// compare_mta_x -
+//-------------------------------------------------
+
+inline void abc1600_state::compare_mta_x()
+{
+ UINT8 mta_x_end = ((m_xto + m_xsize) >> 4) & 0x3f;
+ UINT8 mta_x = m_mta & 0x3f;
+
+ if (mta_x == mta_x_end)
+ {
+ m_cmc = 0;
+ }
+
+ m_wrms1 = m_cmc & m_amm;
+}
+
+
+//-------------------------------------------------
+// compare_mta_y -
+//-------------------------------------------------
+
+inline void abc1600_state::compare_mta_y()
+{
+ int mta_y_end = (m_yto + m_ysize) & 0xfff;
+ UINT16 mta_y = m_mta >> 6;
+
+ if (mta_y == mta_y_end)
+ {
+ m_rmc = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// get_shinf -
+//-------------------------------------------------
+
+inline void abc1600_state::get_shinf()
+{
+ /*
+
+ bit description
+
+ A0 XFROM0
+ A1 XFROM1
+ A2 XFROM2
+ A3 XFROM3
+ A4 XTO0
+ A5 XTO1
+ A6 XTO2
+ A7 XTO3
+ A8 U/D* X
+
+ */
+
+ UINT16 shinf_addr = (m_udx << 8) | ((m_xto & 0x0f) << 4) | (m_xfrom & 0x0f);
+ UINT8 shinf = m_shinf_rom[shinf_addr];
+
+ m_sh = shinf & 0x0f;
+ m_hold_1w_cyk = BIT(shinf, 5);
+}
+
+
+//-------------------------------------------------
+// get_drmsk -
+//-------------------------------------------------
+
+inline UINT16 abc1600_state::get_drmsk()
+{
+ /*
+
+ bit description
+
+ A0 SH0
+ A1 SH1
+ A2 SH2
+ A3 SH3
+ A4 U/D* X
+
+ */
+
+ UINT16 drmsk_addr = (m_udx << 4) | (m_sh & 0x0f);
+ UINT8 drmskl = m_drmsk_rom[drmsk_addr];
+ UINT8 drmskh = m_drmsk_rom[drmsk_addr + 0x20];
+ UINT16 drmsk = (drmskh << 8) | drmskl;
+
+ return drmsk;
+}
+
+
+//-------------------------------------------------
+// get_wrmsk - get mover write mask
+//-------------------------------------------------
+
+inline UINT16 abc1600_state::get_wrmsk()
+{
+ /*
+
+ bit description
+
+ A0 XTO0
+ A1 XTO1
+ A2 XTO2
+ A3 XTO3
+ A4 XSIZE0
+ A5 XSIZE1
+ A6 XSIZE2
+ A7 XSIZE3
+ A8 U/D* X
+ A9 ANDED MASKS
+ A10 WRMS0
+ A11 WRMS1
+
+ */
+
+ UINT16 wrmsk_addr = (m_wrms1 << 11) | (m_wrms0 << 10) | ((!m_wrms1 && !m_wrms0) << 9) | (m_udx << 8) | ((m_xsize & 0x0f) << 4) | (m_xto & 0x0f);
+ UINT8 wrmskl = m_wrmsk_rom[wrmsk_addr];
+ UINT8 wrmskh = m_wrmsk_rom[wrmsk_addr + 0x1000];
+ UINT16 wrmsk = (wrmskh << 8) | wrmskl;
+
+ return wrmsk ^ 0xffff;
+}
+
+
+//-------------------------------------------------
+// barrel_shift -
+//-------------------------------------------------
+
+inline UINT16 abc1600_state::barrel_shift(UINT16 gmdr)
+{
+ UINT16 rot = gmdr;
+
+ for (int sh = 0; sh < m_sh; sh++)
+ {
+ int msb = BIT(rot, 15);
+ rot <<= 1;
+ rot |= msb;
+ }
+
+ return rot;
+}
+
+
+//-------------------------------------------------
+// word_mixer -
+//-------------------------------------------------
+
+inline UINT16 abc1600_state::word_mixer(UINT16 rot)
+{
+ UINT16 drmsk = get_drmsk();
+ UINT16 gmdi = (rot & drmsk) | (m_mdor & (drmsk ^ 0xffff));
+
+ if (COMP_MOVE)
+ {
+ gmdi ^= 0xffff;
+ }
+
+ m_mdor = rot;
+
+ return gmdi;
+}
+
+
+//-------------------------------------------------
+// mover -
+//-------------------------------------------------
+
+void abc1600_state::mover()
+{
+ if (LOG) logerror("XFROM %u XSIZE %u YSIZE %u XTO %u YTO %u MFA %05x MTA %05x U/D*X %u U/D*Y %u\n", m_xfrom, m_xsize, m_ysize, m_xto, m_yto, m_mfa, m_mta, m_udx, m_udy);
+
+ m_amm = 1;
+
+ m_rmc = 1;
+ get_shinf();
+
+ do
+ {
+ compare_mta_y();
+
+ load_mfa_x();
+ load_mta_x();
+ m_cmc = 1;
+ m_wrms0 = 0;
+
+ if (m_hold_1w_cyk)
+ {
+ // read one word in advance
+ UINT16 gmdr = read_videoram(m_mfa);
+ UINT16 rot = barrel_shift(gmdr);
+ word_mixer(rot);
+
+ clock_mfa_x();
+ }
+
+ do
+ {
+ compare_mta_x();
+
+ UINT16 gmdr = read_videoram(m_mfa);
+ UINT16 rot = barrel_shift(gmdr);
+ UINT16 gmdi = word_mixer(rot);
+ UINT16 mask = get_wrmsk();
+
+ write_videoram(m_mta, gmdi, mask);
+
+ clock_mfa_x();
+ clock_mta_x();
+
+ m_wrms0 = 1;
+ }
+ while (m_cmc);
+
+ clock_mfa_y();
+ clock_mta_y();
+ }
+ while (m_rmc);
+
+ load_xy_reg();
+
+ m_amm = 0;
+}
+
+
+
+//**************************************************************************
+// CRT CONTROLLER
+//**************************************************************************
+
+//-------------------------------------------------
+// mc6845_interface crtc_intf
+//-------------------------------------------------
+
+inline UINT16 abc1600_state::get_crtca(UINT16 ma, UINT8 ra, UINT8 column)
+{
+ /*
+
+ bit description
+
+ CRTCA0 0
+ CRTCA1 0
+ CRTCA2 CC1/MA1
+ CRTCA3 CC2/MA2
+ CRTCA4 CC3/MA3
+ CRTCA5 CC4/MA4
+ CRTCA6 RA0
+ CRTCA7 RA1
+ CRTCA8 RA2
+ CRTCA9 RA3
+ CRTCA10 CR0/MA8
+ CRTCA11 CR1/MA9
+ CRTCA12 CR2/MA10
+ CRTCA13 CR3/MA11
+ CRTCA14 CR4/MA12
+ CRTCA15 CR5/MA13
+
+ */
+
+ UINT8 cc = (ma & 0xff) + column;
+ UINT8 cr = ma >> 8;
+
+ return (cr << 10) | ((ra & 0x0f) << 6) | ((cc << 1) & 0x3c);
+}
+
+void abc1600_state::crtc_update_row(device_t *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+{
+ if (y > 0x3ff) return;
+
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int x = HFP;
+
+ for (int column = 0; column < x_count; column += 2)
+ {
+ UINT16 dma = get_crtca(ma, ra, column);
+
+ // data is read out of video RAM in nibble mode by strobing CAS 4 times
+ for (int cas = 0; cas < 4; cas++)
+ {
+ UINT16 data = m_video_ram[dma + cas];
+
+ for (int bit = 0; bit < 16; bit++)
+ {
+ int color = (BIT(data, 15) ^ PIX_POL) & !BLANK;
+
+ bitmap.pix32(y + VFP, x++) = palette[color];
+
+ data <<= 1;
+ }
+ }
+ }
+}
+
+static MC6845_UPDATE_ROW( abc1600_update_row )
+{
+ abc1600_state *state = device->machine().driver_data<abc1600_state>();
+ state->crtc_update_row(device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param);
+}
+
+static MC6845_ON_UPDATE_ADDR_CHANGED( crtc_update )
+{
+}
+
+static const mc6845_interface crtc_intf =
+{
+ SCREEN_TAG,
+ 32,
+ NULL,
+ abc1600_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ crtc_update
+};
+
+
+
+//**************************************************************************
+// VIDEO
+//**************************************************************************
+
+//-------------------------------------------------
+// VIDEO_START( abc1600 )
+//-------------------------------------------------
+
+void abc1600_state::video_start()
+{
+ // allocate video RAM
+ m_video_ram = auto_alloc_array(machine(), UINT16, VIDEORAM_SIZE);
+
+ // find memory regions
+ m_wrmsk_rom = memregion("wrmsk")->base();
+ m_shinf_rom = memregion("shinf")->base();
+ m_drmsk_rom = memregion("drmsk")->base();
+
+ // state saving
+ save_pointer(NAME(m_video_ram), VIDEORAM_SIZE);
+ save_item(NAME(m_endisp));
+ save_item(NAME(m_clocks_disabled));
+ save_item(NAME(m_gmdi));
+ save_item(NAME(m_wrm));
+ save_item(NAME(m_ms));
+ save_item(NAME(m_ds));
+ save_item(NAME(m_flag));
+ save_item(NAME(m_xsize));
+ save_item(NAME(m_ysize));
+ save_item(NAME(m_udx));
+ save_item(NAME(m_udy));
+ save_item(NAME(m_xfrom));
+ save_item(NAME(m_xto));
+ save_item(NAME(m_yto));
+ save_item(NAME(m_ty));
+ save_item(NAME(m_mfa));
+ save_item(NAME(m_mta));
+ save_item(NAME(m_sh));
+ save_item(NAME(m_mdor));
+ save_item(NAME(m_hold_1w_cyk));
+ save_item(NAME(m_wrms0));
+ save_item(NAME(m_wrms1));
+ save_item(NAME(m_rmc));
+ save_item(NAME(m_cmc));
+}
+
+
+//-------------------------------------------------
+// SCREEN_UPDATE_IND16( abc1600 )
+//-------------------------------------------------
+
+UINT32 abc1600_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ // HACK expand visible area to workaround MC6845
+ screen.set_visible_area(0, 958-1, 0, 1067-1);
+
+ if (m_endisp)
+ {
+ bitmap.fill(FRAME_POL, cliprect);
+ m_crtc->screen_update(screen, bitmap, cliprect);
+ }
+ else
+ {
+ bitmap.fill(get_black_pen(machine()), cliprect);
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( abc1600_video )
+//-------------------------------------------------
+
+MACHINE_CONFIG_FRAGMENT( abc1600_video )
+ MCFG_DEFAULT_LAYOUT(layout_abc1600)
+
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) // not accurate
+ MCFG_SCREEN_UPDATE_DRIVER(abc1600_state, screen_update)
+ MCFG_SCREEN_SIZE(958, 1067)
+ MCFG_SCREEN_VISIBLE_AREA(0, 958-1, 0, 1067-1)
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(monochrome_green)
+ MCFG_MC6845_ADD(SY6845E_TAG, SY6845E, XTAL_64MHz/32, crtc_intf)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/abc80.c b/src/mess/video/abc80.c
new file mode 100644
index 00000000000..817e646a4c8
--- /dev/null
+++ b/src/mess/video/abc80.c
@@ -0,0 +1,224 @@
+/*****************************************************************************
+ *
+ * video/abc80.c
+ *
+ ****************************************************************************/
+
+#include "emu.h"
+#include "includes/abc80.h"
+
+
+
+//-------------------------------------------------
+// gfx_layout charlayout
+//-------------------------------------------------
+
+static const gfx_layout charlayout =
+{
+ 6, 10,
+ 128,
+ 1,
+ { 0 },
+ { 0, 1, 2, 3, 4, 5 },
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8 },
+ 10*8
+};
+
+
+//-------------------------------------------------
+// GFXDECODE( abc80 )
+//-------------------------------------------------
+
+static GFXDECODE_START( abc80 )
+ GFXDECODE_ENTRY( "chargen", 0, charlayout, 0, 2 ) // normal characters
+ GFXDECODE_ENTRY( "chargen", 0x500, charlayout, 0, 2 ) // graphics characters
+GFXDECODE_END
+
+
+//-------------------------------------------------
+// update_screen -
+//-------------------------------------------------
+
+void abc80_state::update_screen(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ int c = 0;
+ int r = 0;
+ int mode = 0;
+
+ for (int y = 0; y < 312; y++)
+ {
+ UINT8 vsync_data = m_vsync_prom[y];
+ UINT8 l = m_line_prom[y];
+ int dv = (vsync_data & ABC80_K2_DV) ? 1 : 0;
+
+ if (!(vsync_data & ABC80_K2_FRAME_RESET))
+ {
+ // reset F2
+ r = 0;
+ }
+
+ for (int sx = 0; sx < 64; sx++)
+ {
+ UINT8 hsync_data = m_hsync_prom[sx];
+ int dh = (hsync_data & ABC80_K5_DH) ? 1 : 0;
+ UINT8 data = 0;
+
+ if (hsync_data & ABC80_K5_LINE_END)
+ {
+ // reset F4
+ c = 0;
+
+ // reset J5
+ mode = 0;
+ }
+
+ /*
+
+ Video RAM Addressing Scheme
+
+ A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
+ R2 R1 R0 xx xx xx xx C2 C1 C0
+
+ A6 A5 A4 A3 = 00 C5 C4 C3 + R4 R3 R4 R3
+
+ */
+
+ int a = (c >> 3) & 0x07;
+ int b = ((r >> 1) & 0x0c) | ((r >> 3) & 0x03);
+ int s = (a + b) & 0x0f;
+ UINT16 videoram_addr = ((r & 0x07) << 7) | (s << 3) | (c & 0x07);
+ UINT8 videoram_data = m_latch;
+ UINT8 attr_addr = ((dh & dv) << 7) | (videoram_data & 0x7f);
+ UINT8 attr_data = m_attr_prom[attr_addr];
+
+ int blank = (attr_data & ABC80_J3_BLANK) ? 1 : 0;
+ int j = (attr_data & ABC80_J3_TEXT) ? 1 : 0;
+ int k = (attr_data & ABC80_J3_GRAPHICS) ? 1 : 0;
+ int versal = (attr_data & ABC80_J3_VERSAL) ? 1 : 0;
+ int cursor = (videoram_data & ABC80_CHAR_CURSOR) ? 1 : 0;
+
+ if (!j && k) mode = 0;
+ if (j && !k) mode = 1;
+ if (j && k) mode = !mode;
+
+ if (mode & versal)
+ {
+ // graphics mode
+ int r0 = 1, r1 = 1, r2 = 1;
+
+ if (l < 3) r0 = 0; else if (l < 7) r1 = 0; else r2 = 0;
+
+ int c0 = BIT(videoram_data, 0) | r0;
+ int c1 = BIT(videoram_data, 1) | r0;
+ int c2 = BIT(videoram_data, 2) | r1;
+ int c3 = BIT(videoram_data, 3) | r1;
+ int c4 = BIT(videoram_data, 4) | r2;
+ int c5 = BIT(videoram_data, 6) | r2;
+
+ if (!(c0 & c2 & c4)) data |= 0xe0;
+ if (!(c1 & c3 & c5)) data |= 0x1c;
+ }
+ else
+ {
+ // text mode
+ UINT16 chargen_addr = ((videoram_data & 0x7f) * 10) + l;
+
+ data = m_char_rom[chargen_addr];
+ }
+
+ // shift out pixels
+ for (int bit = 0; bit < 6; bit++)
+ {
+ int color = BIT(data, 7);
+ int x = (sx * 6) + bit;
+
+ color ^= (cursor & m_blink);
+ color &= blank;
+
+ bitmap.pix16(y, x) = color;
+
+ data <<= 1;
+ }
+
+ m_latch = m_video_ram[videoram_addr];
+
+ if (hsync_data & ABC80_K5_ROW_START)
+ {
+ // clock F4
+ c++;
+ }
+ }
+
+ if (vsync_data & ABC80_K2_FRAME_END)
+ {
+ // clock F2
+ r++;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// VIDEO_START( abc80 )
+//-------------------------------------------------
+
+void abc80_state::video_start()
+{
+ screen_device *screen = machine().device<screen_device>(SCREEN_TAG);
+
+ // start timers
+ m_pio_timer = timer_alloc(TIMER_ID_PIO);
+ m_pio_timer->adjust(screen->time_until_pos(0, 0), 0, screen->scan_period());
+
+ m_blink_timer = timer_alloc(TIMER_ID_BLINK);
+ m_blink_timer->adjust(attotime::from_hz(XTAL_11_9808MHz/2/6/64/312/16), 0, attotime::from_hz(XTAL_11_9808MHz/2/6/64/312/16));
+
+ m_vsync_on_timer = timer_alloc(TIMER_ID_VSYNC_ON);
+ m_vsync_on_timer->adjust(screen->time_until_pos(0, 0), 0, screen->frame_period());
+
+ m_vsync_off_timer = timer_alloc(TIMER_ID_VSYNC_OFF);
+ m_vsync_on_timer->adjust(screen->time_until_pos(16, 0), 0, screen->frame_period());
+
+ // allocate memory
+ m_video_ram = auto_alloc_array(machine(), UINT8, 0x400);
+
+ // find memory regions
+ m_char_rom = memregion("chargen")->base();
+ m_hsync_prom = memregion("hsync")->base();
+ m_vsync_prom = memregion("vsync")->base();
+ m_line_prom = memregion("line")->base();
+ m_attr_prom = memregion("attr")->base();
+
+ // register for state saving
+ save_item(NAME(m_blink));
+ save_item(NAME(m_latch));
+}
+
+
+//-------------------------------------------------
+// SCREEN_UPDATE_IND16( abc80 )
+//-------------------------------------------------
+
+UINT32 abc80_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ update_screen(bitmap, cliprect);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( abc80_video )
+//-------------------------------------------------
+
+MACHINE_CONFIG_FRAGMENT( abc80_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(abc80_state, screen_update)
+
+ MCFG_GFXDECODE(abc80)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(black_and_white)
+
+ MCFG_SCREEN_RAW_PARAMS(XTAL_11_9808MHz/2, ABC80_HTOTAL, ABC80_HBEND, ABC80_HBSTART, ABC80_VTOTAL, ABC80_VBEND, ABC80_VBSTART)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/abc800.c b/src/mess/video/abc800.c
new file mode 100644
index 00000000000..1377620aee0
--- /dev/null
+++ b/src/mess/video/abc800.c
@@ -0,0 +1,380 @@
+/*****************************************************************************
+ *
+ * video/abc800.c
+ *
+ ****************************************************************************/
+
+#include "includes/abc80x.h"
+
+
+
+// these are needed because the MC6845 emulation does
+// not position the active display area correctly
+#define HORIZONTAL_PORCH_HACK 115
+#define VERTICAL_PORCH_HACK 29
+
+
+
+//**************************************************************************
+// HIGH RESOLUTION GRAPHICS
+//**************************************************************************
+
+//-------------------------------------------------
+// hrs_w - high resolution scanline write
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc800_state::hrs_w )
+{
+ m_hrs = data;
+}
+
+
+//-------------------------------------------------
+// hrc_w - high resolution color write
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc800_state::hrc_w )
+{
+ m_fgctl = data;
+}
+
+
+
+//**************************************************************************
+// ABC 800 COLOR
+//**************************************************************************
+
+//-------------------------------------------------
+// translate_trom_offset -
+//-------------------------------------------------
+
+offs_t abc800c_state::translate_trom_offset(offs_t offset)
+{
+ int row = offset >> 7;
+ int col = offset & 0x7f;
+
+ if (col >= 80) row += 16;
+ else if (col >= 40) row += 8;
+
+ return (row * 40) + (col % 40);
+}
+
+
+//-------------------------------------------------
+// char_ram_r - character RAM read
+//-------------------------------------------------
+
+READ8_MEMBER( abc800c_state::char_ram_r )
+{
+ return saa5050_videoram_r(m_trom, translate_trom_offset(offset));
+}
+
+
+//-------------------------------------------------
+// char_ram_w - character RAM write
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc800c_state::char_ram_w )
+{
+ saa5050_videoram_w(m_trom, translate_trom_offset(offset), data);
+}
+
+
+//-------------------------------------------------
+// hr_update - high resolution screen update
+//-------------------------------------------------
+
+void abc800c_state::hr_update(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT16 addr = 0;
+
+ for (int y = m_hrs; y < MIN(cliprect.max_y + 1, m_hrs + 480); y += 2)
+ {
+ int x = 0;
+
+ for (int sx = 0; sx < 64; sx++)
+ {
+ UINT8 data = m_video_ram[addr++];
+
+ for (int dot = 0; dot < 4; dot++)
+ {
+ UINT16 fgctl_addr = ((m_fgctl & 0x7f) << 2) | ((data >> 6) & 0x03);
+ UINT8 fgctl = m_fgctl_prom[fgctl_addr];
+ int color = fgctl & 0x07;
+
+ if (color)
+ {
+ rgb_t rgb = palette_entry_get_color(machine().palette, bitmap.pix16(y, x));
+ bool black = !RGB_RED(rgb) && !RGB_GREEN(rgb) && !RGB_BLUE(rgb);
+ bool opaque = !BIT(fgctl, 3);
+
+ if (black || opaque)
+ {
+ color += 128;
+
+ bitmap.pix16(y, x) = color;
+ bitmap.pix16(y, x + 1) = color;
+
+ bitmap.pix16(y + 1, x) = color;
+ bitmap.pix16(y + 1, x + 1) = color;
+ }
+ }
+
+ data <<= 2;
+ x += 2;
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// VIDEO_START( abc800 )
+//-------------------------------------------------
+
+void abc800_state::video_start()
+{
+ // find memory regions
+ m_char_rom = memregion(MC6845_TAG)->base();
+ m_fgctl_prom = memregion("hru2")->base();
+
+ // register for state saving
+ save_item(NAME(m_hrs));
+ save_item(NAME(m_fgctl));
+}
+
+
+//-------------------------------------------------
+// VIDEO_START( abc800c )
+//-------------------------------------------------
+
+void abc800c_state::video_start()
+{
+ abc800_state::video_start();
+
+ // initialize palette
+ palette_set_color_rgb(machine(), 128+0, 0x00, 0x00, 0x00); // black
+ palette_set_color_rgb(machine(), 128+1, 0xff, 0x00, 0x00); // red
+ palette_set_color_rgb(machine(), 128+2, 0x00, 0xff, 0x00); // green
+ palette_set_color_rgb(machine(), 128+3, 0xff, 0xff, 0x00); // yellow
+ palette_set_color_rgb(machine(), 128+4, 0x00, 0x00, 0xff); // blue
+ palette_set_color_rgb(machine(), 128+5, 0xff, 0x00, 0xff); // magenta
+ palette_set_color_rgb(machine(), 128+6, 0x00, 0xff, 0xff); // cyan
+ palette_set_color_rgb(machine(), 128+7, 0xff, 0xff, 0xff); // white
+}
+
+
+//-------------------------------------------------
+// SCREEN_UPDATE( abc800c )
+//-------------------------------------------------
+
+UINT32 abc800c_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ // clear screen
+ bitmap.fill(get_black_pen(machine()), cliprect);
+
+ // draw text
+ if (!BIT(m_fgctl, 7))
+ {
+ saa5050_update(m_trom, bitmap, cliprect);
+ }
+
+ saa5050_frame_advance(m_trom);
+
+ // draw HR graphics
+ hr_update(bitmap, cliprect);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// saa5050_interface trom_intf
+//-------------------------------------------------
+
+static const saa5050_interface trom_intf =
+{
+ SCREEN_TAG,
+ 0, // starting gfxnum
+ 40, 24, 40, // x, y, size
+ 0 // rev y order
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( abc800c_video )
+//-------------------------------------------------
+
+MACHINE_CONFIG_FRAGMENT( abc800c_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(abc800c_state, screen_update)
+
+ MCFG_SCREEN_REFRESH_RATE(50)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_SIZE(480, 480)
+ MCFG_SCREEN_VISIBLE_AREA(0, 480-1, 0, 480-1)
+
+ MCFG_PALETTE_LENGTH(128+8)
+ MCFG_PALETTE_INIT(saa5050)
+
+ MCFG_GFXDECODE(saa5050)
+
+ MCFG_SAA5050_ADD(SAA5052_TAG, trom_intf)
+MACHINE_CONFIG_END
+
+
+
+//**************************************************************************
+// ABC 800 MONOCHROME
+//**************************************************************************
+
+//-------------------------------------------------
+// PALETTE_INIT( abc800m )
+//-------------------------------------------------
+
+static PALETTE_INIT( abc800m )
+{
+ palette_set_color_rgb(machine, 0, 0x00, 0x00, 0x00); // black
+ palette_set_color_rgb(machine, 1, 0xff, 0xff, 0x00); // yellow
+}
+
+
+//-------------------------------------------------
+// hr_update - high resolution screen update
+//-------------------------------------------------
+
+void abc800m_state::hr_update(bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT16 addr = 0;
+
+ for (int y = m_hrs + VERTICAL_PORCH_HACK; y < MIN(cliprect.max_y + 1, m_hrs + VERTICAL_PORCH_HACK + 240); y++)
+ {
+ int x = HORIZONTAL_PORCH_HACK;
+
+ for (int sx = 0; sx < 64; sx++)
+ {
+ UINT8 data = m_video_ram[addr++];
+
+ for (int dot = 0; dot < 4; dot++)
+ {
+ UINT16 fgctl_addr = ((m_fgctl & 0x7f) << 2) | ((data >> 6) & 0x03);
+ int color = (m_fgctl_prom[fgctl_addr] & 0x07) ? 1 : 0;
+
+ bitmap.pix32(y, x++) = palette[color];
+ bitmap.pix32(y, x++) = palette[color];
+
+ data <<= 2;
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// MC6845_UPDATE_ROW( abc800m_update_row )
+//-------------------------------------------------
+
+static MC6845_UPDATE_ROW( abc800m_update_row )
+{
+ abc800m_state *state = device->machine().driver_data<abc800m_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ int column;
+
+ // prevent wraparound
+ if (y >= 240) return;
+
+ y += VERTICAL_PORCH_HACK;
+
+ for (column = 0; column < x_count; column++)
+ {
+ int bit;
+
+ UINT16 address = (state->m_char_ram[(ma + column) & 0x7ff] << 4) | (ra & 0x0f);
+ UINT8 data = (state->m_char_rom[address & 0x7ff] & 0x3f);
+
+ if (column == cursor_x)
+ {
+ data = 0x3f;
+ }
+
+ data <<= 2;
+
+ for (bit = 0; bit < ABC800_CHAR_WIDTH; bit++)
+ {
+ int x = HORIZONTAL_PORCH_HACK + (column * ABC800_CHAR_WIDTH) + bit;
+
+ if (BIT(data, 7))
+ {
+ bitmap.pix32(y, x) = palette[1];
+ }
+
+ data <<= 1;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// mc6845_interface crtc_intf
+//-------------------------------------------------
+
+static const mc6845_interface crtc_intf =
+{
+ SCREEN_TAG,
+ ABC800_CHAR_WIDTH,
+ NULL,
+ abc800m_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(Z80DART_TAG, z80dart_rib_w),
+ NULL
+};
+
+
+//-------------------------------------------------
+// SCREEN_UPDATE( abc800m )
+//-------------------------------------------------
+
+UINT32 abc800m_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ // HACK expand visible area to workaround MC6845
+ screen.set_visible_area(0, 767, 0, 311);
+
+ // clear screen
+ bitmap.fill(get_black_pen(machine()), cliprect);
+
+ // draw HR graphics
+ hr_update(bitmap, cliprect);
+
+ // draw text
+ if (!BIT(m_fgctl, 7))
+ {
+ m_crtc->screen_update(screen, bitmap, cliprect);
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( abc800m_video )
+//-------------------------------------------------
+
+MACHINE_CONFIG_FRAGMENT( abc800m_video )
+ MCFG_MC6845_ADD(MC6845_TAG, MC6845, ABC800_CCLK, crtc_intf)
+
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(abc800m_state, screen_update)
+
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_SIZE(768, 312)
+ MCFG_SCREEN_VISIBLE_AREA(0,768-1, 0, 312-1)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(abc800m)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/abc802.c b/src/mess/video/abc802.c
new file mode 100644
index 00000000000..6e15fe92ee6
--- /dev/null
+++ b/src/mess/video/abc802.c
@@ -0,0 +1,255 @@
+/*****************************************************************************
+ *
+ * video/abc802.c
+ *
+ ****************************************************************************/
+
+#include "includes/abc80x.h"
+
+
+
+// these are needed because the MC6845 emulation does
+// not position the active display area correctly
+#define HORIZONTAL_PORCH_HACK 121
+#define VERTICAL_PORCH_HACK 29
+
+
+
+//-------------------------------------------------
+// MC6845_UPDATE_ROW( abc802_update_row )
+//-------------------------------------------------
+
+static MC6845_UPDATE_ROW( abc802_update_row )
+{
+ /*
+
+ PAL16R4 equation:
+
+ IF (VCC) *OS = FC + RF / RC
+ *RG: = HS / *RG + *ATE / *RG + ATD / *RG + LL /
+ *RG + AT1 / *RG + AT0 / ATE + *ATD + *LL +
+ *AT1 + *AT0
+ *RI: = *RI + *INV / *RI + LL / *INV + *LL
+ *RF: = HS / *RF + *ATE / *RF + ATD / *RF + LL /
+ *RF + AT1 / *RF + AT0 / ATE + *ATD + *LL +
+ *AT1 + AT0
+ *RC: = HS / *RC + *ATE / *RC + *ATD / *RC + LL /
+ *RC + *ATI / *RC + AT0 / ATE + *LL + *AT1 +
+ *AT0
+ IF (VCC) *O0 = *CUR + *AT0 / *CUR + ATE
+ *O1 = *CUR + *AT1 / *CUR + ATE
+
+
+ + = AND
+ / = OR
+ * = Inverted
+
+ ATD Attribute data
+ ATE Attribute enable
+ AT0,AT1 Attribute address
+ CUR Cursor
+ FC FLSH clock
+ HS Horizontal sync
+ INV Inverted signal input
+ LL Load when Low
+ OEL Output Enable when Low
+ RC Row clear
+ RF Row flash
+ RG Row graphic
+ RI Row inverted
+
+ */
+
+ abc802_state *state = device->machine().driver_data<abc802_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ int rf = 0, rc = 0, rg = 0;
+
+ // prevent wraparound
+ if (y >= 240) return;
+
+ y += VERTICAL_PORCH_HACK;
+
+ for (int column = 0; column < x_count; column++)
+ {
+ UINT8 code = state->m_char_ram[(ma + column) & 0x7ff];
+ UINT16 address = code << 4;
+ UINT8 ra_latch = ra;
+ UINT8 data;
+
+ int ri = (code & ABC802_INV) ? 1 : 0;
+
+ if (column == cursor_x)
+ {
+ ra_latch = 0x0f;
+ }
+
+ if ((state->m_flshclk && rf) || rc)
+ {
+ ra_latch = 0x0e;
+ }
+
+ if (rg)
+ {
+ address |= 0x800;
+ }
+
+ data = state->m_char_rom[(address + ra_latch) & 0xfff];
+
+ if (data & ABC802_ATE)
+ {
+ int attr = data & 0x03;
+ int value = (data & ABC802_ATD) ? 1 : 0;
+
+ switch (attr)
+ {
+ case 0x00:
+ // Row Graphic
+ rg = value;
+ break;
+
+ case 0x01:
+ // Row Flash
+ rf = value;
+ break;
+
+ case 0x02:
+ // Row Clear
+ rc = value;
+ break;
+
+ case 0x03:
+ // undefined
+ break;
+ }
+ }
+ else
+ {
+ data <<= 2;
+
+ if (state->m_80_40_mux)
+ {
+ for (int bit = 0; bit < ABC800_CHAR_WIDTH; bit++)
+ {
+ int x = HORIZONTAL_PORCH_HACK + ((column + 3) * ABC800_CHAR_WIDTH) + bit;
+ int color = BIT(data, 7) ^ ri;
+
+ bitmap.pix32(y, x) = palette[color];
+
+ data <<= 1;
+ }
+ }
+ else
+ {
+ for (int bit = 0; bit < ABC800_CHAR_WIDTH; bit++)
+ {
+ int x = HORIZONTAL_PORCH_HACK + ((column + 3) * ABC800_CHAR_WIDTH) + (bit << 1);
+ int color = BIT(data, 7) ^ ri;
+
+ bitmap.pix32(y, x) = palette[color];
+ bitmap.pix32(y, x + 1) = palette[color];
+
+ data <<= 1;
+ }
+
+ column++;
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// vs_w - vertical sync write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc802_state::vs_w )
+{
+ if (!state)
+ {
+ // flash clock
+ if (m_flshclk_ctr & 0x20)
+ {
+ m_flshclk = !m_flshclk;
+ m_flshclk_ctr = 0;
+ }
+ else
+ {
+ m_flshclk_ctr++;
+ }
+ }
+
+ // signal _DEW to DART
+ m_dart->ri_w(1, !state);
+}
+
+
+//-------------------------------------------------
+// mc6845_interface crtc_intf
+//-------------------------------------------------
+
+static const mc6845_interface crtc_intf =
+{
+ SCREEN_TAG,
+ ABC800_CHAR_WIDTH,
+ NULL,
+ abc802_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(abc802_state, vs_w),
+ NULL
+};
+
+
+//-------------------------------------------------
+// VIDEO_START( abc802 )
+//-------------------------------------------------
+
+void abc802_state::video_start()
+{
+ // find memory regions
+ m_char_rom = memregion(MC6845_TAG)->base();
+
+ // register for state saving
+ save_item(NAME(m_flshclk_ctr));
+ save_item(NAME(m_flshclk));
+ save_item(NAME(m_80_40_mux));
+}
+
+
+//-------------------------------------------------
+// SCREEN_UPDATE( abc802 )
+//-------------------------------------------------
+
+UINT32 abc802_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ // HACK expand visible area to workaround MC6845
+ screen.set_visible_area(0, 767, 0, 311);
+
+ // draw text
+ m_crtc->screen_update(screen, bitmap, cliprect);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( abc802_video )
+//-------------------------------------------------
+
+MACHINE_CONFIG_FRAGMENT( abc802_video )
+ MCFG_MC6845_ADD(MC6845_TAG, MC6845, ABC800_CCLK, crtc_intf)
+
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(abc802_state, screen_update)
+
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_SIZE(768, 312)
+ MCFG_SCREEN_VISIBLE_AREA(0,768-1, 0, 312-1)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(monochrome_amber)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/abc806.c b/src/mess/video/abc806.c
new file mode 100644
index 00000000000..0c354474be1
--- /dev/null
+++ b/src/mess/video/abc806.c
@@ -0,0 +1,554 @@
+/*****************************************************************************
+ *
+ * video/abc806.c
+ *
+ ****************************************************************************/
+
+/*
+
+ TODO:
+
+ - flashing
+ - double height
+ - underline
+
+*/
+
+#include "includes/abc80x.h"
+
+
+
+// these are needed because the MC6845 emulation does
+// not position the active display area correctly
+#define HORIZONTAL_PORCH_HACK 109
+#define VERTICAL_PORCH_HACK 27
+
+
+
+//-------------------------------------------------
+// PALETTE_INIT( abc806 )
+//-------------------------------------------------
+
+static PALETTE_INIT( abc806 )
+{
+ palette_set_color_rgb(machine, 0, 0x00, 0x00, 0x00); // black
+ palette_set_color_rgb(machine, 1, 0xff, 0x00, 0x00); // red
+ palette_set_color_rgb(machine, 2, 0x00, 0xff, 0x00); // green
+ palette_set_color_rgb(machine, 3, 0xff, 0xff, 0x00); // yellow
+ palette_set_color_rgb(machine, 4, 0x00, 0x00, 0xff); // blue
+ palette_set_color_rgb(machine, 5, 0xff, 0x00, 0xff); // magenta
+ palette_set_color_rgb(machine, 6, 0x00, 0xff, 0xff); // cyan
+ palette_set_color_rgb(machine, 7, 0xff, 0xff, 0xff); // white
+}
+
+
+//-------------------------------------------------
+// hrs_w - high resolution memory banking
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc806_state::hrs_w )
+{
+ /*
+
+ bit signal description
+
+ 0 VM14 visible screen memory area bit 0
+ 1 VM15 visible screen memory area bit 1
+ 2 VM16 visible screen memory area bit 2
+ 3 VM17 visible screen memory area bit 3
+ 4 F14 cpu accessible screen memory area bit 0
+ 5 F15 cpu accessible screen memory area bit 1
+ 6 F16 cpu accessible screen memory area bit 2
+ 7 F17 cpu accessible screen memory area bit 3
+
+ */
+
+ m_hrs = data;
+}
+
+
+//-------------------------------------------------
+// hrc_w - high resolution color write
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc806_state::hrc_w )
+{
+ int reg = (offset >> 8) & 0x0f;
+
+ m_hrc[reg] = data;
+}
+
+
+//-------------------------------------------------
+// charram_r - character RAM read
+//-------------------------------------------------
+
+READ8_MEMBER( abc806_state::charram_r )
+{
+ m_attr_data = m_color_ram[offset];
+
+ return m_char_ram[offset];
+}
+
+
+//-------------------------------------------------
+// charram_w - character RAM write
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc806_state::charram_w )
+{
+ m_color_ram[offset] = m_attr_data;
+
+ m_char_ram[offset] = data;
+}
+
+
+//-------------------------------------------------
+// ami_r - attribute memory read
+//-------------------------------------------------
+
+READ8_MEMBER( abc806_state::ami_r )
+{
+ return m_attr_data;
+}
+
+
+//-------------------------------------------------
+// amo_w - attribute memory write
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc806_state::amo_w )
+{
+ m_attr_data = data;
+}
+
+
+//-------------------------------------------------
+// cli_r - palette PROM read
+//-------------------------------------------------
+
+READ8_MEMBER( abc806_state::cli_r )
+{
+ /*
+
+ bit description
+
+ 0 HRU II data bit 0
+ 1 HRU II data bit 1
+ 2 HRU II data bit 2
+ 3 HRU II data bit 3
+ 4
+ 5
+ 6
+ 7 RTC data output
+
+ */
+
+ UINT16 hru2_addr = (m_hru2_a8 << 8) | (offset >> 8);
+ UINT8 data = m_hru2_prom[hru2_addr] & 0x0f;
+
+ logerror("HRU II %03x : %01x\n", hru2_addr, data);
+
+ data |= m_rtc->dio_r() << 7;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// sti_r - protection device read
+//-------------------------------------------------
+
+READ8_MEMBER( abc806_state::sti_r )
+{
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7 PROT DOUT
+
+ */
+
+ return 0x7f;
+}
+
+
+//-------------------------------------------------
+// sto_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc806_state::sto_w )
+{
+ int level = BIT(data, 7);
+
+ switch (data & 0x07)
+ {
+ case 0:
+ // external memory enable
+ m_eme = level;
+ break;
+ case 1:
+ // 40/80 column display
+ m_40 = level;
+ break;
+ case 2:
+ // HRU II address line 8, PROT A0
+ m_hru2_a8 = level;
+ break;
+ case 3:
+ // PROT INI
+ break;
+ case 4:
+ // text display enable
+ m_txoff = level;
+ break;
+ case 5:
+ // RTC chip select
+ m_rtc->cs_w(!level);
+ break;
+ case 6:
+ // RTC clock
+ m_rtc->clk_w(level);
+ break;
+ case 7:
+ // RTC data in, PROT DIN
+ m_rtc->dio_w(level);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// sso_w - sync offset write
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc806_state::sso_w )
+{
+ m_sync = data & 0x3f;
+}
+
+
+//-------------------------------------------------
+// MC6845_UPDATE_ROW( abc806_update_row )
+//-------------------------------------------------
+
+static MC6845_UPDATE_ROW( abc806_update_row )
+{
+ abc806_state *state = device->machine().driver_data<abc806_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+// UINT8 old_data = 0xff;
+ int fg_color = 7;
+ int bg_color = 0;
+ int underline = 0;
+ int flash = 0;
+ int e5 = state->m_40;
+ int e6 = state->m_40;
+ int th = 0;
+
+ // prevent wraparound
+ if (y >= 240) return;
+
+ y += state->m_sync + VERTICAL_PORCH_HACK;
+
+ for (int column = 0; column < x_count; column++)
+ {
+ UINT8 data = state->m_char_ram[(ma + column) & 0x7ff];
+ UINT8 attr = state->m_color_ram[(ma + column) & 0x7ff];
+ UINT16 rad_addr;
+ UINT8 rad_data;
+
+ if ((attr & 0x07) == ((attr >> 3) & 0x07))
+ {
+ // special case
+
+ switch (attr >> 6)
+ {
+ case 0:
+ // use previously selected attributes
+ break;
+ case 1:
+ // reserved for future use
+ break;
+ case 2:
+ // blank
+ fg_color = 0;
+ bg_color = 0;
+ underline = 0;
+ flash = 0;
+ break;
+ case 3:
+ // double width
+ e5 = BIT(attr, 0);
+ e6 = BIT(attr, 1);
+
+ // read attributes from next byte
+ attr = state->m_color_ram[(ma + column + 1) & 0x7ff];
+
+ if (attr != 0x00)
+ {
+ fg_color = attr & 0x07;
+ bg_color = (attr >> 3) & 0x07;
+ underline = BIT(attr, 6);
+ flash = BIT(attr, 7);
+ }
+ break;
+ }
+ }
+ else
+ {
+ // normal case
+ fg_color = attr & 0x07;
+ bg_color = (attr >> 3) & 0x07;
+ underline = BIT(attr, 6);
+ flash = BIT(attr, 7);
+ e5 = state->m_40;
+ e6 = state->m_40;
+ }
+
+ if (column == cursor_x)
+ {
+ rad_data = 0x0f;
+ }
+ else
+ {
+ rad_addr = (e6 << 8) | (e5 << 7) | (flash << 6) | (underline << 5) | (state->m_flshclk << 4) | ra;
+ rad_data = state->m_rad_prom[rad_addr] & 0x0f;
+
+ rad_data = ra; // HACK because the RAD prom is not dumped yet
+ }
+
+ UINT16 chargen_addr = (th << 12) | (data << 4) | rad_data;
+ UINT8 chargen_data = state->m_char_rom[chargen_addr & 0xfff] << 2;
+ int x = HORIZONTAL_PORCH_HACK + (column + 4) * ABC800_CHAR_WIDTH;
+
+ for (int bit = 0; bit < ABC800_CHAR_WIDTH; bit++)
+ {
+ int color = BIT(chargen_data, 7) ? fg_color : bg_color;
+
+ bitmap.pix32(y, x++) = palette[color];
+
+ if (e5 || e6)
+ {
+ bitmap.pix32(y, x++) = palette[color];
+ }
+
+ chargen_data <<= 1;
+ }
+
+ if (e5 || e6)
+ {
+ column++;
+ }
+
+// old_data = data;
+ }
+}
+
+
+//-------------------------------------------------
+// hs_w - horizontal sync write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc806_state::hs_w )
+{
+ int vsync;
+
+ if (!state)
+ {
+ m_v50_addr++;
+
+ // clock current vsync value into the shift register
+ m_vsync_shift <<= 1;
+ m_vsync_shift |= m_vsync;
+
+ vsync = BIT(m_vsync_shift, m_sync);
+
+ if (!m_d_vsync && vsync)
+ {
+ // clear V50 address
+ m_v50_addr = 0;
+ }
+ else if (m_d_vsync && !vsync)
+ {
+ // flash clock
+ if (m_flshclk_ctr & 0x20)
+ {
+ m_flshclk = !m_flshclk;
+ m_flshclk_ctr = 0;
+ }
+ else
+ {
+ m_flshclk_ctr++;
+ }
+ }
+
+ if (m_d_vsync != vsync)
+ {
+ // signal _DEW to DART
+ m_dart->ri_w(1, !vsync);
+ }
+
+ m_d_vsync = vsync;
+ }
+}
+
+
+//-------------------------------------------------
+// vs_w - vertical sync write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc806_state::vs_w )
+{
+ m_vsync = state;
+}
+
+
+//-------------------------------------------------
+// mc6845_interface crtc_intf
+//-------------------------------------------------
+
+static const mc6845_interface crtc_intf =
+{
+ SCREEN_TAG,
+ ABC800_CHAR_WIDTH,
+ NULL,
+ abc806_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(abc806_state, hs_w),
+ DEVCB_DRIVER_LINE_MEMBER(abc806_state, vs_w),
+ NULL
+};
+
+
+//-------------------------------------------------
+// hr_update - high resolution screen update
+//-------------------------------------------------
+
+void abc806_state::hr_update(bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 addr = (m_hrs & 0x0f) << 15;
+
+ for (int y = m_sync + VERTICAL_PORCH_HACK; y < MIN(cliprect.max_y + 1, m_sync + VERTICAL_PORCH_HACK + 240); y++)
+ {
+ for (int sx = 0; sx < 128; sx++)
+ {
+ UINT8 data = m_video_ram[addr++];
+ UINT16 dot = (m_hrc[data >> 4] << 8) | m_hrc[data & 0x0f];
+
+ for (int pixel = 0; pixel < 4; pixel++)
+ {
+ int x = HORIZONTAL_PORCH_HACK + (ABC800_CHAR_WIDTH * 4) - 16 + (sx * 4) + pixel;
+
+ if (BIT(dot, 15) || bitmap.pix32(y, x) == palette[0])
+ {
+ bitmap.pix32(y, x) = palette[(dot >> 12) & 0x07];
+ }
+
+ dot <<= 4;
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// VIDEO_START( abc806 )
+//-------------------------------------------------
+
+void abc806_state::video_start()
+{
+ // initialize variables
+ for (int i = 0; i < 16; i++)
+ {
+ m_hrc[i] = 0;
+ }
+
+ m_sync = 10;
+ m_d_vsync = 1;
+ m_vsync = 1;
+ m_40 = 1;
+
+ // find memory regions
+ m_char_rom = memregion(MC6845_TAG)->base();
+ m_rad_prom = memregion("rad")->base();
+ m_hru2_prom = memregion("hru2")->base();
+
+ // allocate memory
+ m_char_ram.allocate(ABC806_CHAR_RAM_SIZE);
+ m_color_ram = auto_alloc_array(machine(), UINT8, ABC806_ATTR_RAM_SIZE);
+
+ // register for state saving
+ save_pointer(NAME(m_char_ram.target()), ABC806_CHAR_RAM_SIZE);
+ save_pointer(NAME(m_color_ram), ABC806_ATTR_RAM_SIZE);
+ save_pointer(NAME(m_video_ram.target()), ABC806_VIDEO_RAM_SIZE);
+ save_item(NAME(m_txoff));
+ save_item(NAME(m_40));
+ save_item(NAME(m_flshclk_ctr));
+ save_item(NAME(m_flshclk));
+ save_item(NAME(m_attr_data));
+ save_item(NAME(m_hrs));
+ save_item(NAME(m_hrc));
+ save_item(NAME(m_sync));
+ save_item(NAME(m_v50_addr));
+ save_item(NAME(m_hru2_a8));
+ save_item(NAME(m_vsync_shift));
+ save_item(NAME(m_vsync));
+ save_item(NAME(m_d_vsync));
+}
+
+
+//-------------------------------------------------
+// SCREEN_UPDATE( abc806 )
+//-------------------------------------------------
+
+UINT32 abc806_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ // HACK expand visible area to workaround MC6845
+ screen.set_visible_area(0, 767, 0, 311);
+
+ // clear screen
+ bitmap.fill(get_black_pen(machine()), cliprect);
+
+ if (!m_txoff)
+ {
+ // draw text
+ m_crtc->screen_update(screen, bitmap, cliprect);
+ }
+
+ // draw HR graphics
+ hr_update(bitmap, cliprect);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( abc806_video )
+//-------------------------------------------------
+
+MACHINE_CONFIG_FRAGMENT( abc806_video )
+ MCFG_MC6845_ADD(MC6845_TAG, MC6845, ABC800_CCLK, crtc_intf)
+
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(abc806_state, screen_update)
+
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_SIZE(768, 312)
+ MCFG_SCREEN_VISIBLE_AREA(0, 768-1, 0, 312-1)
+
+ MCFG_PALETTE_LENGTH(8)
+
+ MCFG_PALETTE_INIT(abc806)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/ac1.c b/src/mess/video/ac1.c
new file mode 100644
index 00000000000..5dbda02b6b6
--- /dev/null
+++ b/src/mess/video/ac1.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+
+ AC1 video driver by Miodrag Milanovic
+
+ 15/01/2009 Preliminary driver.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "includes/ac1.h"
+
+#define AC1_VIDEO_MEMORY 0x1000
+
+const gfx_layout ac1_charlayout =
+{
+ 6, 8, /* 6x8 characters */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ {0}, /* no bitplanes; 1 bit per pixel */
+ {7, 6, 5, 4, 3, 2},
+ {0 * 8, 1 * 8, 2 * 8, 3 * 8, 4 * 8, 5 * 8, 6 * 8, 7 * 8},
+ 8*8 /* size of one char */
+};
+
+VIDEO_START( ac1 )
+{
+}
+
+SCREEN_UPDATE_IND16( ac1 )
+{
+ int x,y;
+ address_space *space = screen.machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ for(y = 0; y < 16; y++ )
+ {
+ for(x = 0; x < 64; x++ )
+ {
+ int code = space->read_byte(AC1_VIDEO_MEMORY + x + y*64);
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], code , 0, 0,0, 63*6-x*6,15*8-y*8);
+ }
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( ac1_32 )
+{
+ int x,y;
+ address_space *space = screen.machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ for(y = 0; y < 32; y++ )
+ {
+ for(x = 0; x < 64; x++ )
+ {
+ int code = space->read_byte(AC1_VIDEO_MEMORY + x + y*64);
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], code , 0, 0,0, 63*6-x*6,31*8-y*8);
+ }
+ }
+ return 0;
+}
+
+
diff --git a/src/mess/video/advision.c b/src/mess/video/advision.c
new file mode 100644
index 00000000000..597d30c55cd
--- /dev/null
+++ b/src/mess/video/advision.c
@@ -0,0 +1,115 @@
+/***************************************************************************
+
+ video/advision.c
+
+ Routines to control the Adventurevision video hardware
+
+ Video hardware is composed of a vertical array of 40 LEDs which is
+ reflected off a spinning mirror, to give a resolution of 150 x 40 at 15 FPS.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/advision.h"
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+void advision_state::video_start()
+{
+ m_video_hpos = 0;
+ m_display = auto_alloc_array(machine(), UINT8, 8 * 8 * 256);
+ memset(m_display, 0, 8 * 8 * 256);
+}
+
+/***************************************************************************
+
+ Initialise the palette.
+
+***************************************************************************/
+
+PALETTE_INIT( advision )
+{
+ int i;
+
+ for( i = 0; i < 8; i++ )
+ {
+ /* 8 shades of RED */
+ palette_set_color_rgb(machine, i, i * 0x22, 0x00, 0x00);
+ }
+}
+
+/***************************************************************************
+
+ Update the display data.
+
+***************************************************************************/
+
+void advision_state::vh_write(int data)
+{
+ if (m_video_bank >= 1 && m_video_bank <=5)
+ {
+ m_led_latch[m_video_bank] = data;
+ }
+}
+
+void advision_state::vh_update(int x)
+{
+ UINT8 *dst = &m_display[x];
+ int y;
+
+ for( y = 0; y < 8; y++ )
+ {
+ UINT8 data = m_led_latch[7-y];
+
+ if( (data & 0x80) == 0 ) dst[0 * 256] = 8;
+ if( (data & 0x40) == 0 ) dst[1 * 256] = 8;
+ if( (data & 0x20) == 0 ) dst[2 * 256] = 8;
+ if( (data & 0x10) == 0 ) dst[3 * 256] = 8;
+ if( (data & 0x08) == 0 ) dst[4 * 256] = 8;
+ if( (data & 0x04) == 0 ) dst[5 * 256] = 8;
+ if( (data & 0x02) == 0 ) dst[6 * 256] = 8;
+ if( (data & 0x01) == 0 ) dst[7 * 256] = 8;
+
+ m_led_latch[7-y] = 0xff;
+
+ dst += 8 * 256;
+ }
+}
+
+
+/***************************************************************************
+
+ Refresh the video screen
+
+***************************************************************************/
+
+UINT32 advision_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ int x, y;
+
+ if( (m_frame_count++ % 4) == 0 )
+ {
+ m_frame_start = 1;
+ m_video_hpos = 0;
+ }
+
+ for (x = 0; x < 150; x++)
+ {
+ UINT8 *led = &m_display[x];
+
+ for( y = 0; y < 128; y+=2 )
+ {
+ if( *led > 0 )
+ bitmap.pix16(30 + y, 85 + x) = --(*led);
+ else
+ bitmap.pix16(30 + y, 85 + x) = 0;
+
+ led += 256;
+ }
+ }
+ return 0;
+}
diff --git a/src/mess/video/apollo.c b/src/mess/video/apollo.c
new file mode 100644
index 00000000000..4caecf3cab5
--- /dev/null
+++ b/src/mess/video/apollo.c
@@ -0,0 +1,882 @@
+/*
+ * video/apollo.c
+ *
+ * Created on: May 12, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ *
+ * see also:
+ * - Domain Series 3000/Series 4000 Hardware Architecture Handbook (Order No. 007861 Rev. 02)
+ * - http://www.bitsavers.org/pdf/apollo/002398-04_Domain_Engineering_Handbook_Rev4_Jan87.pdf (page 12-16 ...)
+ */
+
+#define VERBOSE 0
+
+#include "includes/apollo.h"
+
+#include "apollo.lh"
+#include "apollo_15i.lh"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+ ***************************************************************************/
+
+// monochrome 1280x1024
+#define SCREEN_DEVICE_ID_19I 0x09
+
+// monochrome 1024x800
+#define SCREEN_DEVICE_ID_15I 0x0b
+
+#define VIDEO_SCREEN_TAG "screen"
+
+// status register
+#define SR_BLANK 0x80
+#define SR_V_BLANK 0x40
+#define SR_H_SYNC 0x20
+#define SR_R_M_W 0x10
+#define SR_ALT 0x08
+#define SR_V_SYNC 0x04
+#define SR_H_CK 0x02
+#define SR_V_DATA 0x01
+
+// control register 0
+#define CR0_MODE(a) ((a) >> 5)
+#define CR0_MODE_0 0
+#define CR0_MODE_1 1
+#define CR0_MODE_VECTOR 2
+#define CR0_MODE_3 3
+#define CR0_MODE_BLT 4
+#define CR0_MODE_NORMAL 7
+#define CR0_SHIFT(a) ((a) & 0x1f)
+
+// control register 1
+#define CR1_INV 0x80
+#define CR1_DADDR_16 0x40
+#define CR1_DV_CK 0x40
+#define CR1_DH_CK 0x20
+#define CR1_ROP_EN 0x10
+#define CR1_RESET 0x08
+#define CR1_DP_CK 0x04
+#define CR1_SYNC_EN 0x02
+#define CR1_DISP_EN 0x01
+
+// control register 2
+#define CR2_S_DATA(a) ((a) >> 6)
+#define CR2_CONST_ACCESS 0x00
+#define CR2_PIXEL_ACCESS 0x01
+#define CR2_SHIFT_ACCESS 0x02
+#define CR2_PLANE_ACCESS 0x03
+
+typedef struct _screen_data screen_data_t;
+struct _screen_data {
+ UINT16 width;
+ UINT16 height;
+ UINT16 buffer_width;
+ UINT16 buffer_height;
+
+ UINT8 status_register;
+ UINT8 device_id;
+ UINT16 write_enable_register;
+ UINT16 rop_register_0;
+ UINT16 diag_mem_request;
+ UINT8 cr0;
+ UINT8 cr1;
+ UINT8 cr2;
+ UINT8 cr3a;
+
+ UINT8 update_flag;
+ UINT8 update_pending;
+
+ UINT8 blt_cycle_count;
+ UINT32 guard_latch;
+ offs_t image_offset;
+
+ int h_clock;
+ int v_clock;
+ int pixel_clock;
+ int data_clock;
+
+ UINT16 *image_memory;
+ int image_memory_size;
+
+ screen_device *screen;
+};
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+ *****************************************************************************/
+
+INLINE screen_data_t *get_safe_token(device_t *device) {
+ assert(device != NULL);
+ assert(device->type() == APOLLO_MONO15I || device->type() == APOLLO_MONO19I );
+ return (screen_data_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+/***************************************************************************
+ Monochrome Controller Registers at 0x5d800 - 0x5dc07
+ ***************************************************************************/
+
+static void log_cr1(const char * text, device_t *device, screen_data_t *screen_data) {
+
+ DLOG1(("%s: cr0=%02x cr1=%02x sr=%02x pixel_clock=%3d/%3d bl=%d vb=%d vs=%d hs=%d hc=%d vck=%d hck=%d pck=%d vd=%d",
+ text,
+ screen_data->cr0,
+ screen_data->cr1,
+ screen_data->status_register,
+ screen_data->pixel_clock,
+ screen_data->data_clock,
+ screen_data->status_register & SR_BLANK ? 1 : 0,
+ screen_data->status_register & SR_V_BLANK ? 1 : 0,
+ screen_data->status_register & SR_V_SYNC ? 1 : 0,
+ screen_data->status_register & SR_H_SYNC ? 1 : 0,
+ screen_data->status_register & SR_H_CK ? 1 : 0,
+ screen_data->cr1 & CR1_DV_CK ? 1 : 0,
+ screen_data->cr1 & CR1_DH_CK ? 1 : 0,
+ screen_data->cr1 & CR1_DP_CK ? 1 : 0,
+ screen_data->status_register & SR_V_DATA ? 1 : 0));
+}
+
+static void set_cr1(device_t *device, screen_data_t *screen_data,
+ UINT8 data) {
+ UINT8 diffs = screen_data->cr1 ^ data;
+ screen_data->cr1 = data;
+
+// if (screen_data->cr1 & CR1_SYNC_EN) {
+// // normal mode
+// } else
+
+ if ((screen_data->cr1 & CR1_RESET) == 0) {
+ if (diffs & CR1_RESET) {
+ screen_data->blt_cycle_count = 0;
+ screen_data->image_offset = 0;
+ screen_data->guard_latch = 0;
+
+ screen_data->h_clock = 0;
+ screen_data->v_clock = 0;
+ screen_data->pixel_clock = 0;
+ if (screen_data->device_id == SCREEN_DEVICE_ID_19I) {
+ screen_data->data_clock = -11; // TODO: why not 0 ????
+ screen_data->status_register = SR_H_CK | SR_V_BLANK | SR_H_SYNC
+ | SR_V_SYNC;
+ } else {
+ screen_data->data_clock = -9; // TODO: why not 0 ????
+ screen_data->status_register = SR_V_BLANK | SR_V_SYNC;
+ }
+ }
+ log_cr1("CR1_RESET", device, screen_data);
+ } else {
+ if ((diffs & CR1_RESET) && (screen_data->cr1 & CR1_RESET) != 0) {
+ log_cr1("CR1_RESET", device, screen_data);
+ }
+
+ if ((diffs & CR1_DH_CK) && (screen_data->cr1 & CR1_DH_CK) == 0) {
+ if (screen_data->device_id == SCREEN_DEVICE_ID_19I) {
+ switch (screen_data->h_clock %= 108) {
+ case 8:
+ screen_data->status_register |= SR_BLANK;
+ break;
+ case 88:
+ screen_data->status_register &= ~SR_BLANK;
+ break;
+ case 93:
+ screen_data->status_register &= ~SR_H_SYNC;
+ // trigger Dp_Ck
+ diffs |= CR1_DP_CK;
+ screen_data->cr1 &= ~CR1_DP_CK;
+ break;
+ case 104:
+ screen_data->status_register |= SR_H_SYNC;
+ break;
+ }
+ } else {
+ switch (screen_data->h_clock %= 84) {
+ case 1:
+ screen_data->status_register |= SR_H_SYNC;
+ break;
+ case 8:
+ screen_data->status_register |= SR_BLANK;
+ break;
+ case 72:
+ screen_data->status_register &= ~SR_BLANK;
+ break;
+ case 77:
+ screen_data->status_register &= ~SR_H_SYNC;
+ diffs |= CR1_DV_CK;
+ data &= ~CR1_DV_CK;
+ break;
+ }
+ }
+ screen_data->h_clock++;
+ log_cr1("CR1_DH_CK",device, screen_data);
+ }
+
+ if ((diffs & CR1_DV_CK) && (screen_data->cr1 & CR1_DV_CK) == 0) {
+ // this is used for disp.dex Test 19: Video RAM Shift Reg. Test
+ if (screen_data->device_id == SCREEN_DEVICE_ID_15I) {
+ switch (screen_data->v_clock %= 842) {
+ case 799:
+ screen_data->status_register &= ~SR_V_BLANK;
+ break;
+ case 804:
+ screen_data->status_register &= ~SR_V_SYNC;
+ break;
+ case 808:
+ screen_data->status_register |= SR_V_SYNC;
+ break;
+ case 841:
+ screen_data->status_register |= SR_V_BLANK;
+ break;
+ }
+ screen_data->v_clock++;
+ log_cr1("CR1_DV_CK",device, screen_data);
+ }
+ }
+
+ if ((diffs & CR1_DP_CK) && (screen_data->cr1 & CR1_DP_CK) == 0) {
+ if (screen_data->device_id == SCREEN_DEVICE_ID_19I) {
+ switch (screen_data->pixel_clock %= 1066) {
+ case 1023:
+ screen_data->status_register &= ~SR_V_BLANK;
+ break;
+ case 1028:
+ screen_data->status_register &= ~SR_V_SYNC;
+ break;
+ case 1032:
+ screen_data->status_register |= SR_V_SYNC;
+ break;
+ case 1065:
+ screen_data->status_register |= SR_V_BLANK;
+ break;
+ }
+ } else /*if (screen_data->pixel_clock == 0)*/ {
+ // this is used for disp.dex Test 6: Vertical Counter Test
+ switch (screen_data->pixel_clock %= 842) {
+ case 799:
+ screen_data->status_register &= ~SR_V_BLANK;
+ break;
+ case 804:
+ screen_data->status_register &= ~SR_V_SYNC;
+ break;
+ case 808:
+ screen_data->status_register |= SR_V_SYNC;
+ break;
+ case 841:
+ screen_data->status_register |= SR_V_BLANK;
+ break;
+ }
+ }
+
+ if ((screen_data->cr1 & CR1_DISP_EN) == 0) {
+ screen_data->status_register &= ~SR_V_DATA;
+ }else {
+ UINT16 pixel = screen_data->image_memory[screen_data->data_clock / 16]
+ & (0x8000 >> (screen_data->data_clock % 16));
+ pixel = (pixel ? 1 : 0) ^ ((screen_data->cr1 & CR1_INV) ? 0 : 1);
+
+ if (pixel) {
+ screen_data->status_register |= SR_V_DATA;
+ } else {
+ screen_data->status_register &= ~SR_V_DATA;
+ }
+ screen_data->data_clock++;
+ }
+
+ screen_data->pixel_clock++;
+ if ((screen_data->pixel_clock % 8) == 0) {
+ screen_data->status_register ^= SR_H_CK;
+ }
+
+ log_cr1("CR1_DP_CK", device, screen_data);
+ }
+
+ if ((screen_data->status_register & SR_V_BLANK) == 0) {
+ screen_data->status_register &= ~SR_BLANK;
+ }
+
+ if (diffs & CR1_DISP_EN) {
+ // update screen
+ screen_data->update_flag = 1;
+ }
+ }
+}
+
+static void set_cr3(device_t *device, screen_data_t *screen_data, UINT8 data) {
+ screen_data->cr3a = data;
+ if ((data & 0x80) == 0) {
+ int shift = (data & 0x0f) >> 1;
+ UINT8 bit_mask = 1 << shift;
+ if (data & 0x01) {
+ set_cr1(device, screen_data, screen_data->cr1 | bit_mask);
+ } else {
+ set_cr1(device, screen_data, screen_data->cr1 & ~bit_mask);
+ }
+ }
+}
+
+READ16_DEVICE_HANDLER( apollo_mcr_r ) {
+ screen_data_t *screen_data = get_safe_token(device);
+ UINT16 data;
+ switch (offset & 0x203) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ data = (screen_data->status_register << 8)
+ | screen_data->device_id;
+ break;
+ case 0x200:
+ data = screen_data->cr0 << 8 | 0xff;
+ break;
+ case 0x201:
+ data = screen_data->cr1 << 8 | 0xff;
+ break;
+ case 0x202:
+ data = screen_data->cr2 << 8 | 0xff;
+ break;
+ case 0x203:
+ data = screen_data->cr3a << 8 | 0xff;
+ break;
+ default:
+ data = screen_data->device_id;
+ break;
+ }
+ DLOG1(("reading Monochrome Controller at offset %03x = %04x and %04x", offset, data, mem_mask));
+ return data;
+}
+
+WRITE16_DEVICE_HANDLER(apollo_mcr_w ) {
+ screen_data_t *screen_data = get_safe_token(device);
+ if (offset != 0 && data != 0)
+ DLOG1(("writing Monochrome Controller at offset %03x = %04x and %04x", offset, data, mem_mask));
+
+ switch (offset & 0x203) {
+ case 0:
+ screen_data->write_enable_register = data;
+ screen_data->blt_cycle_count = 0;
+ screen_data->status_register &= ~SR_ALT;
+ break;
+ case 1:
+ screen_data->rop_register_0 = data;
+ switch (data & 0x0f) {
+ case 0: // zero
+ case 3: // Source
+ case 0x0c: // ~Source
+ case 0x0f: // one
+ screen_data->status_register &= ~SR_R_M_W;
+ break;
+ default:
+ screen_data->status_register |= SR_R_M_W;
+ break;
+ }
+ break;
+ case 2:
+ // trigger memory refresh in diagnostic mode
+ screen_data->diag_mem_request = data;
+ break;
+ case 0x200:
+ screen_data->cr0 = data >> 8;
+ screen_data->blt_cycle_count = 0;
+ break;
+ case 0x201:
+ set_cr1(device, screen_data, data >> 8);
+ break;
+ case 0x202:
+ screen_data->cr2 = data >> 8;
+ break;
+ case 0x203:
+ set_cr3(device, screen_data, data >> 8);
+ break;
+ }
+}
+
+/***************************************************************************
+ Monochrome graphics memory space at FA0000 - FDFFFF
+ ***************************************************************************/
+
+static UINT32 get_source_data(screen_data_t *screen_data, UINT32 src_data) {
+ switch (CR2_S_DATA(screen_data->cr2)) {
+ case CR2_CONST_ACCESS: // 0x00
+ // set source to all ones (used for vectors)
+ src_data= 0xffff;
+ break;
+ case CR2_PIXEL_ACCESS: // 0x01
+ // replicate 4 LSB of data bus
+ src_data= src_data & 1 ? 0xffff : 0;
+ break;
+ case CR2_SHIFT_ACCESS: // 0x02
+ // replicate LSB of shifter
+ src_data = src_data & 0xffff;
+ break;
+ case CR2_PLANE_ACCESS: // 0x03
+ // use source data unchanged (normal use)
+ if (CR0_SHIFT(screen_data->cr0) >= 16) {
+ src_data = (src_data << 16) | (src_data >> 16);
+ }
+ src_data >>= (CR0_SHIFT(screen_data->cr0) & 0x0f);
+ break;
+ }
+ return src_data;
+}
+
+static UINT16 rop(screen_data_t *screen_data, UINT16 dest_data) {
+
+ UINT32 src_data = get_source_data(screen_data, screen_data->guard_latch);
+
+ if ((screen_data->cr1 & CR1_ROP_EN)
+ /*&& (CR2_S_DATA(screen_data->cr2) == CR2_PLANE_ACCESS)*/) {
+ switch (screen_data->rop_register_0 & 0x0f) {
+ case 0: // zero
+ src_data = 0;
+ break;
+ case 1: // Source AND Destination
+ src_data = src_data & dest_data;
+ break;
+ case 2: // Source AND ~Destination
+ src_data = src_data & (~dest_data);
+ break;
+ case 3: // Source
+ break;
+ case 4: // ~Source AND Destination
+ src_data = (~src_data) & dest_data;
+ break;
+ case 5: // Destination
+ src_data = dest_data;
+ break;
+ case 6: // Source XOR Destination
+ src_data = src_data ^ dest_data;
+ break;
+ case 7: // Source OR Destination
+ src_data = src_data | dest_data;
+ break;
+ case 8: // Source NOR Destination
+ src_data = ~(src_data | dest_data);
+ break;
+ case 9: // Source XNOR Destination
+ src_data = ~(src_data ^ dest_data);
+ break;
+ case 0x0a: // ~Destination
+ src_data = ~dest_data;
+ break;
+ case 0x0b: // Source OR ~Destination
+ src_data = src_data | (~dest_data);
+ break;
+ case 0x0c: // ~Source
+ src_data = ~src_data;
+ break;
+ case 0x0d: // ~Source OR Destination
+ src_data = (~src_data) | dest_data;
+ break;
+ case 0x0e: // Source NAND Destination
+ src_data = ~(src_data & dest_data);
+ break;
+ case 0x0f: // One
+ src_data = 0xffff;
+ break;
+ }
+ }
+
+ return src_data & 0xffff;
+}
+
+READ16_DEVICE_HANDLER( apollo_mgm_r ) {
+ screen_data_t *screen_data = get_safe_token(device);
+ UINT16 data;
+
+ if (CR0_MODE(screen_data->cr0) == CR0_MODE_0
+ && screen_data->blt_cycle_count > 0) {
+ offset = screen_data->image_offset;
+ screen_data->blt_cycle_count = 0;
+ }
+
+ if (offset >= screen_data->image_memory_size) {
+ // 128 kB display buffer of 15" screen seems to be shadowed from $fa0000 to $fc0000
+ DLOG1(("reading Monochrome Graphics Memory at invalid offset %05x", offset));
+ offset %= screen_data->image_memory_size;
+ }
+
+ switch (CR0_MODE(screen_data->cr0)) {
+ case CR0_MODE_VECTOR:
+ // vector or fill mode
+ UINT16 src_data, dest_data;
+ screen_data->status_register &= ~SR_ALT;
+
+ dest_data = screen_data->image_memory[offset];
+ src_data = rop(screen_data, dest_data);
+
+ src_data &= ~screen_data->write_enable_register;
+ dest_data &= (screen_data->write_enable_register | ~mem_mask);
+ screen_data->image_memory[offset] = dest_data | src_data;
+ data = screen_data->image_memory[offset];
+ break;
+ case CR0_MODE_3:
+ // CPU source BLT: read internal data bus
+ data = screen_data->guard_latch;
+ break;
+ default:
+ data = screen_data->image_memory[offset];
+ screen_data->guard_latch <<= 16;
+ screen_data->guard_latch |= data;
+ break;
+ }
+ DLOG1(("reading Monochrome Graphics Memory with mode %d: offset %05x = %04x & %04x", CR0_MODE(screen_data->cr0), offset, data, mem_mask));
+ return data;
+}
+
+WRITE16_DEVICE_HANDLER( apollo_mgm_w ) {
+ screen_data_t *screen_data = get_safe_token(device);
+ UINT16 src_data, dest_data;
+ UINT32 dest_addr;
+
+ if (offset >= screen_data->image_memory_size) {
+ // 128 kB display buffer of 15" screen seems to be shadowed from $fa0000 to $fc0000
+ DLOG1(("writing Monochrome Graphics Memory at invalid offset %05x = %04x & %04x ", offset, data, mem_mask));
+ offset %= screen_data->image_memory_size;
+ }
+
+ DLOG1(("writing Monochrome Graphics Memory with mode %d: offset=%04x data=%04x mask=%04x", CR0_MODE(screen_data->cr0), offset, data, mem_mask));
+ switch (CR0_MODE(screen_data->cr0)) {
+ case CR0_MODE_0:
+ // CPU destination BLT
+ // bus write to provide display memory address
+ // bus read to get data
+ screen_data->image_offset = offset;
+ screen_data->blt_cycle_count = 1;
+ break;
+ case CR0_MODE_1:
+ // Alternating BLT
+ // alternating bus writes provide src/dest address
+ // second write provides Write-enables
+ if (++screen_data->blt_cycle_count == 1) {
+ screen_data->status_register |= SR_ALT;
+ screen_data->guard_latch <<= 16;
+ screen_data->guard_latch |= screen_data->image_memory[offset];
+ } else {
+ screen_data->blt_cycle_count = 0;
+ screen_data->status_register &= ~SR_ALT;
+
+ dest_data = screen_data->image_memory[offset];
+ src_data = rop(screen_data, dest_data);
+
+ src_data &= (~data & mem_mask);
+ dest_data &= (data | ~mem_mask);
+ screen_data->image_memory[offset] = dest_data | src_data;
+ }
+ break;
+ case CR0_MODE_VECTOR:
+ // Vector or fill mode
+ // write provides Write-enables and address
+ screen_data->status_register &= ~SR_ALT;
+
+ dest_data = screen_data->image_memory[offset];
+ src_data = rop(screen_data, dest_data);
+
+ src_data &= (~data & mem_mask);
+ dest_data &= (data | ~mem_mask);
+ screen_data->image_memory[offset] = dest_data | src_data;
+ break;
+ case CR0_MODE_3:
+ // CPU source BLT
+ // bus write to provide src data
+ // bus write to provide Write-enables and address
+ if (++screen_data->blt_cycle_count == 1) {
+ screen_data->status_register |= SR_ALT;
+
+ // strange: must fix byte access for /systest/grtest on sr10.2
+ if (mem_mask == 0xff00)
+ {
+ data >>=8;
+ mem_mask >>= 8;
+ }
+
+ screen_data->guard_latch <<= 16;
+ screen_data->guard_latch |= data;
+
+ } else {
+ screen_data->blt_cycle_count = 0;
+ screen_data->status_register &= ~SR_ALT;
+
+ dest_data = screen_data->image_memory[offset];
+ dest_data &= (data | ~mem_mask);
+
+ src_data = rop(screen_data, dest_data);
+ src_data &= (~data & mem_mask);
+
+ screen_data->image_memory[offset] = dest_data | src_data;
+ }
+ break;
+ case CR0_MODE_BLT:
+ // Double access BLT
+ // bus write to provide src addr on address lines
+ // dest addr on data lines (16-bit WORD Offset)
+ screen_data->guard_latch <<= 16;
+ screen_data->guard_latch |= screen_data->image_memory[offset];
+
+ dest_addr = (data & mem_mask);
+ if (screen_data->device_id == SCREEN_DEVICE_ID_19I && (screen_data->cr1
+ & CR1_DADDR_16)) {
+ dest_addr += 0x10000;
+ }
+ dest_data = screen_data->image_memory[dest_addr];
+
+ src_data = rop(screen_data, dest_data);
+ src_data &= ~screen_data->write_enable_register;
+
+ dest_data &= (screen_data->write_enable_register | ~mem_mask);
+ screen_data->image_memory[dest_addr] = dest_data | src_data;
+ break;
+ case CR0_MODE_NORMAL:
+ screen_data->guard_latch <<= 16;
+ screen_data->guard_latch |= (data & mem_mask);;
+ dest_data = screen_data->image_memory[offset];
+ src_data = rop(screen_data, dest_data);
+
+ src_data &= ~screen_data->write_enable_register;
+ dest_data &= (screen_data->write_enable_register | ~mem_mask);
+ screen_data->image_memory[offset] = dest_data | src_data;
+ break;
+ default:
+ DLOG(("writing Monochrome Graphics Memory - unexpected cr0 mode %d", CR0_MODE(screen_data->cr0)));
+ }
+ screen_data->update_flag = 1;
+}
+
+/***************************************************************************
+ VIDEO HARDWARE
+ ***************************************************************************/
+
+static void apollo_screen_update(device_t *device, bitmap_ind16 &bitmap,
+ const rectangle &cliprect) {
+ screen_data_t *screen_data = get_safe_token(device);
+
+ UINT16 *source_ptr = screen_data->image_memory;
+ int x, y;
+ UINT16 data, mask;
+ UINT16 inverse = (screen_data->cr1 & CR1_INV) ? 0xffff : 0;
+
+ DLOG1(("apollo_screen_update: size=%0x rowpixels=%d", screen_data->image_memory_size, bitmap.rowpixels()));
+
+ if ((screen_data->cr1 & CR1_DISP_EN) == 0) {
+ // display is disabled
+ for (y = 0; y < screen_data->height; y++) {
+ int dest = 0;
+ for (x = 0; x < screen_data->width; x += 16) {
+ for (mask = 0x8000; mask; mask >>= 1) {
+ bitmap.pix16(y, dest++) = 0;
+ }
+ }
+ source_ptr += (screen_data->buffer_width - screen_data->width) / 16;
+ }
+ } else {
+ for (y = 0; y < screen_data->height; y++) {
+ int dest = 0;
+ for (x = 0; x < screen_data->width; x += 16) {
+ data = *source_ptr++ ^ inverse;
+ for (mask = 0x8000; mask; mask >>= 1) {
+ bitmap.pix16(y, dest++) = data & mask ? 0 : 1;
+ }
+ }
+ source_ptr += (screen_data->buffer_width - screen_data->width) / 16;
+ }
+ }
+}
+
+/*-------------------------------------------------
+ vblank_state_changed -
+ called on each state change of the VBLANK signal
+-------------------------------------------------*/
+
+static void vblank_state_changed(device_t *device, screen_device &screen, bool vblank_state)
+{
+ screen_data_t *screen_data = get_safe_token(device);
+
+ if ((screen_data->cr1 & CR1_RESET) && (screen_data->cr1 & CR1_SYNC_EN)) {
+ if (vblank_state) {
+ screen_data->status_register &= ~(SR_V_BLANK | SR_BLANK);
+ // faking V_DATA for disp.dex test 16
+ if (screen_data->image_memory[0]) {
+ screen_data->status_register |= SR_V_DATA;
+ }
+ } else {
+ screen_data->status_register |= (SR_V_BLANK | SR_BLANK);
+ screen_data->status_register &= ~SR_V_DATA;
+ }
+ }
+}
+
+VIDEO_START( apollo_screen ) {
+}
+
+SCREEN_UPDATE_IND16( apollo_screen ) {
+ // FIXME: omit using APOLLO_SCREEN_TAG
+ device_t *apollo_screen = screen.machine().device( APOLLO_SCREEN_TAG );
+ screen_data_t *screen_data = get_safe_token(apollo_screen);
+
+ int has_changed = 0;
+
+ if (screen_data->update_flag && !screen_data->update_pending) {
+ has_changed = 1;
+ screen_data->update_flag = 0;
+ screen_data->update_pending = 1;
+ apollo_screen_update(apollo_screen, bitmap, cliprect);
+ screen_data->update_pending = 0;
+ }
+ return has_changed ? 0 : UPDATE_HAS_NOT_CHANGED;
+}
+
+/***************************************************************************
+ MACHINE DRIVERS
+ ***************************************************************************/
+MACHINE_CONFIG_FRAGMENT( apollo_mono19i )
+ MCFG_DEFAULT_LAYOUT( layout_apollo )
+ MCFG_SCREEN_ADD(VIDEO_SCREEN_TAG, RASTER)
+ MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_AFTER_VBLANK)
+// MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(black_and_white)
+ // dot clock, htotal, hstart, hend, vtotal, vstart, vend
+ // MCFG_SCREEN_RAW_PARAMS(118000000, 1280, 0, 1728, 1024, 0, 1065)
+ MCFG_SCREEN_REFRESH_RATE(64)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(616))
+ MCFG_SCREEN_SIZE(1280, 1024)
+ MCFG_SCREEN_VISIBLE_AREA(0, 1279, 0, 1023)
+ MCFG_VIDEO_START(apollo_screen)
+ MCFG_SCREEN_UPDATE_STATIC(apollo_screen)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( apollo_mono15i )
+ MCFG_DEFAULT_LAYOUT( layout_apollo_15i )
+ MCFG_SCREEN_ADD(VIDEO_SCREEN_TAG, RASTER)
+ MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_AFTER_VBLANK)
+// MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(black_and_white)
+ // dot clock, htotal, hstart, hend, vtotal, vstart, vend
+ // MCFG_SCREEN_RAW_PARAMS(85963000, 1024, 0, 1344, 800, 0, 842)
+ MCFG_SCREEN_REFRESH_RATE(76)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(657))
+ MCFG_SCREEN_SIZE(1024, 800)
+ MCFG_SCREEN_VISIBLE_AREA(0, 1023, 0, 799)
+ MCFG_VIDEO_START(apollo_screen)
+ MCFG_SCREEN_UPDATE_STATIC(apollo_screen)
+MACHINE_CONFIG_END
+
+/*-------------------------------------------------
+ DEVICE_START( apollo_mono19i/15i )
+ -------------------------------------------------*/
+
+static DEVICE_START( apollo_mono ) {
+ screen_data_t *screen_data = get_safe_token(device);
+
+ /* get the video screen */
+ screen_data->screen = (screen_device *)device->machine().device(VIDEO_SCREEN_TAG);
+ assert(screen_data->screen != NULL);
+
+ /* allocate the memory image */
+ screen_data->image_memory_size = screen_data->buffer_height
+ * screen_data->buffer_width / 16;
+// screen_data->image_memory = (UINT16 *) malloc(screen_data->image_memory_size * 2);
+ screen_data->image_memory = auto_alloc_array(device->machine(), UINT16, screen_data->image_memory_size);
+ assert(screen_data->image_memory != NULL);
+
+ DLOG1(("device start apollo screen buffer=%p size=%0x", screen_data->image_memory, screen_data->image_memory_size));
+}
+
+static DEVICE_START( apollo_mono19i ) {
+ screen_data_t *screen_data = get_safe_token(device);
+
+ memset(screen_data, 0, sizeof(screen_data_t));
+
+ // monochrome 1280x1024
+ screen_data->device_id = SCREEN_DEVICE_ID_19I;
+ screen_data->width = 1280;
+ screen_data->height = 1024;
+ screen_data->buffer_width = 2048;
+ screen_data->buffer_height = 1024;
+
+ device_start_apollo_mono(device);
+}
+
+static DEVICE_START( apollo_mono15i ) {
+ screen_data_t *screen_data = get_safe_token(device);
+
+ memset(screen_data, 0, sizeof(screen_data_t));
+
+ // monochrome 1024x800
+ screen_data->device_id = SCREEN_DEVICE_ID_15I;
+ screen_data->width = 1024;
+ screen_data->height = 800;
+ screen_data->buffer_width = 1024;
+ screen_data->buffer_height = 1024;
+
+ device_start_apollo_mono(device);
+}
+
+/*-------------------------------------------------
+ DEVICE_RESET( apollo_mono19i/15i )
+ -------------------------------------------------*/
+
+static DEVICE_RESET( apollo_mono19i ) {
+ screen_data_t *screen_data = get_safe_token(device);
+
+ DLOG1(("device reset apollo screen"));
+
+ memset(screen_data->image_memory, 0, screen_data->image_memory_size * 2);
+
+ /* register for VBLANK callbacks */
+ screen_data->screen->register_vblank_callback(vblank_state_delegate(FUNC(vblank_state_changed), device));
+}
+
+static DEVICE_RESET( apollo_mono15i ) {
+ DEVICE_RESET_CALL(apollo_mono19i);
+}
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( apollo_mono19i/15i )
+ -------------------------------------------------*/
+
+DEVICE_GET_INFO( apollo_mono19i ) {
+ switch (state) {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(screen_data_t); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(apollo_mono19i); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(apollo_mono19i); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Apollo 19\" Monochrome Screen"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Terminal"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ }
+}
+
+DEVICE_GET_INFO( apollo_mono15i ) {
+ switch (state) {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(screen_data_t); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(apollo_mono15i); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(apollo_mono15i); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Apollo 15\" Monochrome Screen"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Terminal"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(APOLLO_MONO19I, apollo_mono19i);
+DEFINE_LEGACY_DEVICE(APOLLO_MONO15I, apollo_mono15i);
diff --git a/src/mess/video/apple1.c b/src/mess/video/apple1.c
new file mode 100644
index 00000000000..d12d1c15efe
--- /dev/null
+++ b/src/mess/video/apple1.c
@@ -0,0 +1,401 @@
+/***************************************************************************
+
+ apple1.c
+
+ Functions to emulate the video hardware of the Apple I.
+
+ The Apple I video hardware was basically a dumb video terminal; in
+ fact it was based on Steve Wozniak's own design for a simple video
+ terminal. It had 40 columns by 24 lines of uppercase-only text.
+ Text could only be output at 60 characters per second, one character
+ per video frame. The cursor (a blinking @) could only be advanced
+ using spaces or carriage returns. Carriage returns were the only
+ control characters recognized. Previously written text could not be
+ altered, only scrolled off the top of the screen.
+
+ The video memory used seven 1k-bit dynamic shift registers. Six of
+ these held the 6-bit visible character codes, and one stored the
+ cursor location as a simple bitmap--the bit for the cursor position
+ was set to 0, and all the other bits were 1.
+
+ These shift registers were continuously recirculated, completing one
+ cycle per video frame. As a new line of characters was about to be
+ scanned by the video beam, that character line would be recirculated
+ into the shift registers and would simultaneously be stored into a
+ 6x40-bit line buffer (also a shift register). At this point, if the
+ cursor location was in this line, a new character could be written
+ into that location in the shift registers and the cursor could be
+ advanced. (Carriage returns were not written into the shift
+ registers; they only advanced the cursor.)
+
+ The characters in the line buffer were recirculated 7 times to
+ display the 8 scan lines of the characters, before being replaced by
+ a new line of characters from the main shift registers.
+
+ Cursor blinking was performed by a Signetics 555 timer IC whose
+ output was gated into the character code signals as they passed into
+ the line buffer.
+
+ Character images were provided by a Signetics 2513 character
+ generator ROM, a chip also used in computer terminals such as the
+ ADM-3A. This ROM had 9 address lines and 5 data lines; it contained
+ 64 character images, each 5 pixels wide by 8 pixels high, with one
+ line of pixels being blank for vertical separation. The video
+ circuitry added the 2 pixels of horizontal separation for each
+ character.
+
+ A special CLEAR SCREEN switch on the keyboard, directly connected to
+ the video hardware, could be used to clear the video memory and
+ return the cursor to the home position. This was completely
+ independent of the processor.
+
+ A schematic of the Apple I video hardware can be found in the
+ Apple-1 Operation Manual; look for the schematic titled "Terminal
+ Section". Most of the functionality modeled here was determined by
+ reading this schematic. Many of the chips used were standard 74xx
+ TTL chips, but the shift registers used for the video memory and
+ line buffer were Signetics 25xx PMOS ICs. These were already
+ becoming obsolete when the Apple I was built, and detailed
+ information on them is very hard to find today.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/apple1.h"
+
+
+/***************************************************************************
+
+ Terminal code
+
+***************************************************************************/
+
+static TILE_GET_INFO(terminal_gettileinfo)
+{
+ apple1_state *state = machine.driver_data<apple1_state>();
+ int ch, gfxfont, code, color;
+
+ ch = state->m_current_terminal->mem[tile_index];
+ code = ch & ((1 << state->m_current_terminal->char_bits) - 1);
+ color = ch >> state->m_current_terminal->char_bits;
+ gfxfont = state->m_current_terminal->gfx;
+
+ if ((tile_index == state->m_current_terminal->cur_offset) && !state->m_current_terminal->cur_hidden && state->m_current_terminal->getcursorcode)
+ code = state->m_current_terminal->getcursorcode(code);
+
+ SET_TILE_INFO(
+ gfxfont, /* gfx */
+ code, /* character */
+ color, /* color */
+ 0); /* flags */
+}
+
+static void terminal_draw(running_machine &machine, bitmap_ind16 &dest, const rectangle &cliprect, terminal_t *terminal)
+{
+ apple1_state *state = machine.driver_data<apple1_state>();
+ state->m_current_terminal = terminal;
+ terminal->tm->draw(dest, cliprect, 0, 0);
+ state->m_current_terminal = NULL;
+}
+
+static void verify_coords(terminal_t *terminal, int x, int y)
+{
+ assert(x >= 0);
+ assert(y >= 0);
+ assert(x < terminal->num_cols);
+ assert(y < terminal->num_rows);
+}
+
+static void terminal_putchar(terminal_t *terminal, int x, int y, int ch)
+{
+ int offs;
+
+ verify_coords(terminal, x, y);
+
+ offs = y * terminal->num_cols + x;
+ if (terminal->mem[offs] != ch)
+ {
+ terminal->mem[offs] = ch;
+ terminal->tm->mark_tile_dirty(offs);
+ }
+}
+
+static int terminal_getchar(terminal_t *terminal, int x, int y)
+{
+ int offs;
+
+ verify_coords(terminal, x, y);
+ offs = y * terminal->num_cols + x;
+ return terminal->mem[offs];
+}
+
+static void terminal_putblank(terminal_t *terminal, int x, int y)
+{
+ terminal_putchar(terminal, x, y, terminal->blank_char);
+}
+
+static void terminal_dirtycursor(terminal_t *terminal)
+{
+ if (terminal->cur_offset >= 0)
+ terminal->tm->mark_tile_dirty(terminal->cur_offset);
+}
+
+static void terminal_setcursor(terminal_t *terminal, int x, int y)
+{
+ terminal_dirtycursor(terminal);
+ terminal->cur_offset = y * terminal->num_cols + x;
+ terminal_dirtycursor(terminal);
+}
+
+static void terminal_hidecursor(terminal_t *terminal)
+{
+ terminal->cur_hidden = 1;
+ terminal_dirtycursor(terminal);
+}
+
+static void terminal_showcursor(terminal_t *terminal)
+{
+ terminal->cur_hidden = 0;
+ terminal_dirtycursor(terminal);
+}
+
+static void terminal_getcursor(terminal_t *terminal, int *x, int *y)
+{
+ *x = terminal->cur_offset % terminal->num_cols;
+ *y = terminal->cur_offset / terminal->num_cols;
+}
+
+static void terminal_fill(terminal_t *terminal, int val)
+{
+ int i;
+ for (i = 0; i < terminal->num_cols * terminal->num_rows; i++)
+ terminal->mem[i] = val;
+ terminal->tm->mark_all_dirty();
+}
+
+static void terminal_clear(terminal_t *terminal)
+{
+ terminal_fill(terminal, terminal->blank_char);
+}
+
+static terminal_t *terminal_create(
+ running_machine &machine,
+ int gfx, int blank_char, int char_bits,
+ int (*getcursorcode)(int original_code),
+ int num_cols, int num_rows)
+{
+ terminal_t *term;
+ int char_width, char_height;
+
+ char_width = machine.gfx[gfx]->width;
+ char_height = machine.gfx[gfx]->height;
+
+ term = (terminal_t *) auto_alloc_array(machine, char, sizeof(terminal_t) - sizeof(term->mem)
+ + (num_cols * num_rows * sizeof(termchar_t)));
+
+ term->tm = tilemap_create(machine, terminal_gettileinfo, tilemap_scan_rows,
+ char_width, char_height, num_cols, num_rows);
+
+ term->gfx = gfx;
+ term->blank_char = blank_char;
+ term->char_bits = char_bits;
+ term->num_cols = num_cols;
+ term->num_rows = num_rows;
+ term->getcursorcode = getcursorcode;
+ term->cur_offset = -1;
+ term->cur_hidden = 0;
+ terminal_clear(term);
+ return term;
+}
+
+
+/**************************************************************************/
+
+
+
+/* The cursor blinking is generated by a free-running timer with a
+ 0.52-second period. It is on for 2/3 of this period and off for
+ 1/3. */
+#define CURSOR_OFF_LENGTH (0.52/3)
+
+/**************************************************************************/
+
+static int apple1_getcursorcode(int original_code)
+{
+ /* Cursor uses symbol 0 (an @ sign) in the character generator ROM. */
+ return 0;
+}
+
+/**************************************************************************/
+
+VIDEO_START( apple1 )
+{
+ apple1_state *state = machine.driver_data<apple1_state>();
+ state->m_blink_on = 1; /* cursor is visible initially */
+ state->m_terminal = terminal_create(
+ machine,
+ 0, /* graphics font 0 (the only one we have) */
+ 32, /* Blank character is symbol 32 in the ROM */
+ 8, /* use 8 bits for the character code */
+ apple1_getcursorcode,
+ 40, 24); /* 40 columns, 24 rows */
+
+ terminal_setcursor(state->m_terminal, 0, 0);
+}
+
+/* This function handles all writes to the video display. */
+void apple1_vh_dsp_w (running_machine &machine, int data)
+{
+ apple1_state *state = machine.driver_data<apple1_state>();
+ int x, y;
+ int cursor_x, cursor_y;
+
+ /* While CLEAR SCREEN is being held down, the hardware is forced
+ to clear the video memory, so video writes have no effect. */
+ if (state->m_vh_clrscrn_pressed)
+ return;
+
+ /* The video display port only accepts the 7 lowest bits of the char. */
+ data &= 0x7f;
+
+ terminal_getcursor(state->m_terminal, &cursor_x, &cursor_y);
+
+ if (data == '\r') {
+ /* Carriage-return moves the cursor to the start of the next
+ line. */
+ cursor_x = 0;
+ cursor_y++;
+ }
+ else if (data < ' ') {
+ /* Except for carriage-return, the video hardware completely
+ ignores all control characters. */
+ return;
+ }
+ else {
+ /* For visible characters, only 6 bits of the ASCII code are
+ used, because the 2513 character generator ROM only
+ contains 64 symbols. The low 5 bits of the ASCII code are
+ used directly. Bit 6 is ignored, since it is the same for
+ all the available characters in the ROM. Bit 7 is inverted
+ before being used as the high bit of the 6-bit ROM symbol
+ index, because the block of 32 ASCII symbols containing the
+ uppercase letters comes first in the ROM. */
+
+ int romindx = (data & 0x1f) | (((data ^ 0x40) & 0x40) >> 1);
+
+ terminal_putchar(state->m_terminal, cursor_x, cursor_y, romindx);
+ if (cursor_x < 39)
+ {
+ cursor_x++;
+ }
+ else
+ {
+ cursor_x = 0;
+ cursor_y++;
+ }
+ }
+
+ /* If the cursor went past the bottom line, scroll the text up one line. */
+ if (cursor_y == 24)
+ {
+ for (y = 1; y < 24; y++)
+ for (x = 0; x < 40; x++)
+ terminal_putchar(state->m_terminal, x, y-1,
+ terminal_getchar(state->m_terminal, x, y));
+
+ for (x = 0; x < 40; x++)
+ terminal_putblank(state->m_terminal, x, 23);
+
+ cursor_y--;
+ }
+
+ terminal_setcursor(state->m_terminal, cursor_x, cursor_y);
+}
+
+/* This function handles clearing the video display on cold-boot or in
+ response to a press of the CLEAR SCREEN switch. */
+void apple1_vh_dsp_clr (running_machine &machine)
+{
+ apple1_state *state = machine.driver_data<apple1_state>();
+ terminal_setcursor(state->m_terminal, 0, 0);
+ terminal_clear(state->m_terminal);
+}
+
+/* Calculate how long it will take for the display to assert the RDA
+ signal in response to a video display write. This signal indicates
+ the display has completed the write and is ready to accept another
+ write. */
+attotime apple1_vh_dsp_time_to_ready (running_machine &machine)
+{
+ apple1_state *state = machine.driver_data<apple1_state>();
+ int cursor_x, cursor_y;
+ int cursor_scanline;
+ double scanline_period = machine.primary_screen->scan_period().as_double();
+ double cursor_hfrac;
+
+ /* The video hardware refreshes the screen by reading the
+ character codes from its circulating shift-register memory.
+ Because of the way this memory works, a new character can only
+ be written into the cursor location at the moment this location
+ is about to be read. This happens during the first scanline of
+ the cursor's character line, when the beam reaches the cursor's
+ horizontal position. */
+
+ terminal_getcursor(state->m_terminal, &cursor_x, &cursor_y);
+ cursor_scanline = cursor_y * apple1_charlayout.height;
+
+ /* Each scanline is composed of 455 pixel times. The first 175 of
+ these are the horizontal blanking period; the remaining 280 are
+ for the visible part of the scanline. */
+ cursor_hfrac = (175 + cursor_x * apple1_charlayout.width) / 455;
+
+ if (machine.primary_screen->vpos() == cursor_scanline) {
+ /* video_screen_get_hpos() doesn't account for the horizontal
+ blanking interval; it acts as if the scanline period is
+ entirely composed of visible pixel times. However, we can
+ still use it to find what fraction of the current scanline
+ period has elapsed. */
+ double current_hfrac = machine.primary_screen->hpos() /
+ machine.first_screen()->width();
+ if (current_hfrac < cursor_hfrac)
+ return attotime::from_double(scanline_period * (cursor_hfrac - current_hfrac));
+ }
+
+ return attotime::from_double(
+ machine.primary_screen->time_until_pos(cursor_scanline, 0).as_double() +
+ scanline_period * cursor_hfrac);
+}
+
+/* Blink the cursor on or off, as appropriate. */
+static void apple1_vh_cursor_blink (running_machine &machine)
+{
+ apple1_state *state = machine.driver_data<apple1_state>();
+ int new_blink_on;
+
+ /* The cursor is on for 2/3 of its blink period and off for 1/3.
+ This is most easily handled by dividing the total elapsed time
+ by the length of the off-portion of the cycle, giving us the
+ number of one-third-cycles elapsed, then checking the result
+ modulo 3. */
+
+ if (((int) (machine.time().as_double() / CURSOR_OFF_LENGTH)) % 3 < 2)
+ new_blink_on = 1;
+ else
+ new_blink_on = 0;
+
+ if (new_blink_on != state->m_blink_on) { /* have we changed state? */
+ if (new_blink_on)
+ terminal_showcursor(state->m_terminal);
+ else
+ terminal_hidecursor(state->m_terminal);
+ state->m_blink_on = new_blink_on;
+ }
+}
+
+SCREEN_UPDATE_IND16( apple1 )
+{
+ apple1_state *state = screen.machine().driver_data<apple1_state>();
+ apple1_vh_cursor_blink(screen.machine());
+ terminal_draw(screen.machine(), bitmap, cliprect, state->m_terminal);
+ return 0;
+}
diff --git a/src/mess/video/apple2.c b/src/mess/video/apple2.c
new file mode 100644
index 00000000000..5b280928a8e
--- /dev/null
+++ b/src/mess/video/apple2.c
@@ -0,0 +1,537 @@
+/***************************************************************************
+
+ video/apple2.c
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/apple2.h"
+#include "machine/ram.h"
+
+/***************************************************************************/
+
+
+#define BLACK 0
+#define DKRED 1
+#define DKBLUE 2
+#define PURPLE 3
+#define DKGREEN 4
+#define DKGRAY 5
+#define BLUE 6
+#define LTBLUE 7
+#define BROWN 8
+#define ORANGE 9
+#define GRAY 10
+#define PINK 11
+#define GREEN 12
+#define YELLOW 13
+#define AQUA 14
+#define WHITE 15
+
+#define ALWAYS_REFRESH 0
+#define PROFILER_VIDEOTOUCH PROFILER_USER3
+
+/***************************************************************************
+ HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ effective_a2 - calculates the effective a2
+ register
+-------------------------------------------------*/
+
+INLINE UINT32 effective_a2(apple2_state *state)
+{
+ return state->m_flags & state->m_a2_videomask;
+}
+
+
+/*-------------------------------------------------
+ compute_video_address - performs funky Apple II
+ video address lookup
+-------------------------------------------------*/
+
+static UINT32 compute_video_address(int col, int row)
+{
+ /* special Apple II addressing - gotta love it */
+ return (((row & 0x07) << 7) | ((row & 0x18) * 5 + col));
+}
+
+
+
+/*-------------------------------------------------
+ adjust_begin_and_end_row - processes the cliprect
+-------------------------------------------------*/
+
+static void adjust_begin_and_end_row(const rectangle &cliprect, int *beginrow, int *endrow)
+{
+ /* assumptions of the code */
+ assert((*beginrow % 8) == 0);
+ assert((*endrow % 8) == 7);
+
+ *beginrow = MAX(*beginrow, cliprect.min_y - (cliprect.min_y % 8));
+ *endrow = MIN(*endrow, cliprect.max_y - (cliprect.max_y % 8) + 7);
+
+ /* sanity check again */
+ assert((*beginrow % 8) == 0);
+ assert((*endrow % 8) == 7);
+}
+
+
+
+/***************************************************************************
+ TEXT
+***************************************************************************/
+
+/*-------------------------------------------------
+ apple2_plot_text_character - plots a single
+ textual character
+-------------------------------------------------*/
+
+INLINE void apple2_plot_text_character(running_machine &machine, bitmap_ind16 &bitmap, int xpos, int ypos, int xscale, UINT32 code,
+ const UINT8 *textgfx_data, UINT32 textgfx_datalen, UINT32 my_a2)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ int x, y, i;
+ int fg = state->m_fgcolor;
+ int bg = state->m_bgcolor;
+ const UINT8 *chardata;
+ UINT16 color;
+
+ if (my_a2 & VAR_ALTCHARSET)
+ {
+ /* we're using an alternate charset */
+ code |= state->m_alt_charset_value;
+ }
+ else if (state->m_flash && (code >= 0x40) && (code <= 0x7f))
+ {
+ /* we're flashing; swap */
+ i = fg;
+ fg = bg;
+ bg = i;
+ }
+
+ /* look up the character data */
+ chardata = &textgfx_data[(code * 8) % textgfx_datalen];
+
+ /* and finally, plot the character itself */
+ if (state->m_machinetype == SPACE84)
+ {
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 7; x++)
+ {
+ color = (chardata[y] & (1 << (6-x))) ? bg : fg;
+
+ for (i = 0; i < xscale; i++)
+ {
+ bitmap.pix16(ypos + y, xpos + (x * xscale) + i) = color;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 7; x++)
+ {
+ color = (chardata[y] & (1 << x)) ? bg : fg;
+
+ for (i = 0; i < xscale; i++)
+ {
+ bitmap.pix16(ypos + y, xpos + (x * xscale) + i) = color;
+ }
+ }
+ }
+ }
+}
+
+
+
+/*-------------------------------------------------
+ apple2_text_draw - renders text (either 40
+ column or 80 column)
+-------------------------------------------------*/
+
+static void apple2_text_draw(running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int page, int beginrow, int endrow)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ int row, col;
+ UINT32 start_address = (page ? 0x0800 : 0x0400);
+ UINT32 address;
+ const UINT8 *textgfx_data = machine.root_device().memregion("gfx1")->base();
+ UINT32 textgfx_datalen = state->memregion("gfx1")->bytes();
+ UINT32 my_a2 = effective_a2(state);
+
+ /* perform adjustments */
+ adjust_begin_and_end_row(cliprect, &beginrow, &endrow);
+
+ for (row = beginrow; row <= endrow; row += 8)
+ {
+ for (col = 0; col < 40; col++)
+ {
+ /* calculate adderss */
+ address = start_address + compute_video_address(col, row / 8);
+
+ if (my_a2 & VAR_80COL)
+ {
+ apple2_plot_text_character(machine, bitmap, col * 14 + 0, row, 1, state->m_a2_videoram[address + 0x10000],
+ textgfx_data, textgfx_datalen, my_a2);
+ apple2_plot_text_character(machine, bitmap, col * 14 + 7, row, 1, state->m_a2_videoram[address + 0x00000],
+ textgfx_data, textgfx_datalen, my_a2);
+ }
+ else
+ {
+ apple2_plot_text_character(machine, bitmap, col * 14, row, 2, state->m_a2_videoram[address],
+ textgfx_data, textgfx_datalen, my_a2);
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ apple2_lores_draw - renders lo-res text
+-------------------------------------------------*/
+
+static void apple2_lores_draw(running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int page, int beginrow, int endrow)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ int row, col, y, x;
+ UINT8 code;
+ UINT32 start_address = (page ? 0x0800 : 0x0400);
+ UINT32 address;
+
+ /* perform adjustments */
+ adjust_begin_and_end_row(cliprect, &beginrow, &endrow);
+
+ for (row = beginrow; row <= endrow; row += 8)
+ {
+ for (col = 0; col < 40; col++)
+ {
+ /* calculate adderss */
+ address = start_address + compute_video_address(col, row / 8);
+
+ /* perform the lookup */
+ code = state->m_a2_videoram[address];
+
+ /* and now draw */
+ for (y = 0; y < 4; y++)
+ {
+ for (x = 0; x < 14; x++)
+ bitmap.pix16(row + y, col * 14 + x) = (code >> 0) & 0x0F;
+ }
+ for (y = 4; y < 8; y++)
+ {
+ for (x = 0; x < 14; x++)
+ bitmap.pix16(row + y, col * 14 + x) = (code >> 4) & 0x0F;
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+ HIGH RESOLUTION GRAPHICS
+***************************************************************************/
+
+static void apple2_hires_draw(running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int page, int beginrow, int endrow)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ const UINT8 *vram;
+ int row, col, b;
+ int offset;
+ int columns;
+ UINT8 vram_row[82];
+ UINT16 v;
+ UINT16 *p;
+ UINT32 w;
+ UINT16 *artifact_map_ptr;
+
+ /* sanity checks */
+ if (beginrow < cliprect.min_y)
+ beginrow = cliprect.min_y;
+ if (endrow > cliprect.max_y)
+ endrow = cliprect.max_y;
+ if (endrow < beginrow)
+ return;
+
+ if (state->m_machinetype == TK2000)
+ {
+ vram = state->m_a2_videoram + (page ? 0xa000 : 0x2000);
+ }
+ else
+ {
+ vram = state->m_a2_videoram + (page ? 0x4000 : 0x2000);
+ }
+ columns = ((effective_a2(state) & (VAR_DHIRES|VAR_80COL)) == (VAR_DHIRES|VAR_80COL)) ? 80 : 40;
+
+ vram_row[0] = 0;
+ vram_row[columns + 1] = 0;
+
+ for (row = beginrow; row <= endrow; row++)
+ {
+ for (col = 0; col < 40; col++)
+ {
+ offset = compute_video_address(col, row / 8) | ((row & 7) << 10);
+
+ switch(columns)
+ {
+ case 40:
+ vram_row[1+col] = vram[offset];
+ break;
+
+ case 80:
+ vram_row[1+(col*2)+0] = vram[offset + 0x10000];
+ vram_row[1+(col*2)+1] = vram[offset + 0x00000];
+ break;
+
+ default:
+ fatalerror("Invalid column count");
+ break;
+ }
+ }
+
+ p = &bitmap.pix16(row);
+
+ for (col = 0; col < columns; col++)
+ {
+ w = (((UINT32) vram_row[col+0] & 0x7f) << 0)
+ | (((UINT32) vram_row[col+1] & 0x7f) << 7)
+ | (((UINT32) vram_row[col+2] & 0x7f) << 14);
+
+ switch(columns)
+ {
+ case 40:
+ artifact_map_ptr = &state->m_hires_artifact_map[((vram_row[col+1] & 0x80) >> 7) * 16];
+ for (b = 0; b < 7; b++)
+ {
+ v = artifact_map_ptr[((w >> (b + 7-1)) & 0x07) | (((b ^ col) & 0x01) << 3)];
+ *(p++) = v;
+ *(p++) = v;
+ }
+ break;
+
+ case 80:
+ if (state->m_monochrome_dhr)
+ {
+ for (b = 0; b < 7; b++)
+ {
+ v = (w & 1);
+ w >>= 1;
+ *(p++) = v ? WHITE : BLACK;
+ }
+ }
+ else
+ {
+ for (b = 0; b < 7; b++)
+ {
+ v = state->m_dhires_artifact_map[((((w >> (b + 7-1)) & 0x0F) * 0x11) >> (((2-(col*7+b))) & 0x03)) & 0x0F];
+ *(p++) = v;
+ }
+ }
+ break;
+
+ default:
+ fatalerror("Invalid column count");
+ break;
+ }
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ VIDEO CORE
+***************************************************************************/
+
+void apple2_video_start(running_machine &machine, const UINT8 *vram, size_t vram_size, UINT32 ignored_softswitches, int hires_modulo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ int i, j;
+ UINT16 c;
+ UINT8 *apple2_font;
+
+ static const UINT8 hires_artifact_color_table[] =
+ {
+ BLACK, PURPLE, GREEN, WHITE,
+ BLACK, BLUE, ORANGE, WHITE
+ };
+
+ static const UINT8 dhires_artifact_color_table[] =
+ {
+ BLACK, DKGREEN, BROWN, GREEN,
+ DKRED, DKGRAY, ORANGE, YELLOW,
+ DKBLUE, BLUE, GRAY, AQUA,
+ PURPLE, LTBLUE, PINK, WHITE
+ };
+
+ state->m_fgcolor = 15;
+ state->m_bgcolor = 0;
+ state->m_flash = 0;
+ apple2_font = machine.root_device().memregion("gfx1")->base();
+ state->m_alt_charset_value = machine.root_device().memregion("gfx1")->bytes() / 16;
+ state->m_a2_videoram = vram;
+
+ /* 2^3 dependent pixels * 2 color sets * 2 offsets */
+ state->m_hires_artifact_map = auto_alloc_array(machine, UINT16, 8 * 2 * 2);
+
+ /* 2^4 dependent pixels */
+ state->m_dhires_artifact_map = auto_alloc_array(machine, UINT16, 16);
+
+ /* build hires artifact map */
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 2; j++)
+ {
+ if (i & 0x02)
+ {
+ if ((i & 0x05) != 0)
+ c = 3;
+ else
+ c = j ? 2 : 1;
+ }
+ else
+ {
+ if ((i & 0x05) == 0x05)
+ c = j ? 1 : 2;
+ else
+ c = 0;
+ }
+ state->m_hires_artifact_map[ 0 + j*8 + i] = hires_artifact_color_table[(c + 0) % hires_modulo];
+ state->m_hires_artifact_map[16 + j*8 + i] = hires_artifact_color_table[(c + 4) % hires_modulo];
+ }
+ }
+
+ /* Fix for Ivel Ultra */
+ if (!strcmp(machine.system().name, "ivelultr")) {
+ int len = machine.root_device().memregion("gfx1")->bytes();
+ for (i = 0; i < len; i++)
+ {
+ apple2_font[i] = BITSWAP8(apple2_font[i], 7, 7, 6, 5, 4, 3, 2, 1);
+ }
+ }
+
+ /* do we need to flip the gfx? */
+ if (!strcmp(machine.system().name, "apple2")
+ || !strcmp(machine.system().name, "apple2p")
+ || !strcmp(machine.system().name, "prav82")
+ || !strcmp(machine.system().name, "prav8m")
+ || !strcmp(machine.system().name, "ace100")
+ || !strcmp(machine.system().name, "apple2jp"))
+ {
+ int len = machine.root_device().memregion("gfx1")->bytes();
+ for (i = 0; i < len; i++)
+ {
+ apple2_font[i] = BITSWAP8(apple2_font[i], 7, 0, 1, 2, 3, 4, 5, 6);
+ }
+ }
+
+
+ /* build double hires artifact map */
+ for (i = 0; i < 16; i++)
+ {
+ state->m_dhires_artifact_map[i] = dhires_artifact_color_table[i];
+ }
+
+ memset(&state->m_old_a2, 0, sizeof(state->m_old_a2));
+ state->m_a2_videomask = ~ignored_softswitches;
+}
+
+
+
+VIDEO_START( apple2 )
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ apple2_video_start(machine, machine.device<ram_device>(RAM_TAG)->pointer(), machine.device<ram_device>(RAM_TAG)->size(), VAR_80COL | VAR_ALTCHARSET | VAR_DHIRES, 4);
+
+ /* hack to fix the colors on apple2/apple2p */
+ state->m_fgcolor = 0;
+ state->m_bgcolor = 15;
+
+ state->m_monochrome_dhr = false;
+}
+
+
+VIDEO_START( apple2p )
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ apple2_video_start(machine, machine.device<ram_device>(RAM_TAG)->pointer(), machine.device<ram_device>(RAM_TAG)->size(), VAR_80COL | VAR_ALTCHARSET | VAR_DHIRES, 8);
+
+ /* hack to fix the colors on apple2/apple2p */
+ state->m_fgcolor = 0;
+ state->m_bgcolor = 15;
+
+ state->m_monochrome_dhr = false;
+}
+
+
+VIDEO_START( apple2e )
+{
+ apple2_video_start(machine, machine.device<ram_device>(RAM_TAG)->pointer(), machine.device<ram_device>(RAM_TAG)->size(), 0, 8);
+}
+
+
+SCREEN_UPDATE_IND16( apple2 )
+{
+ apple2_state *state = screen.machine().driver_data<apple2_state>();
+ int page;
+ UINT32 new_a2;
+ running_machine &machine = screen.machine();
+
+ /* calculate the state->m_flash value */
+ state->m_flash = ((screen.machine().time() * 4).seconds & 1) ? 1 : 0;
+
+ /* read out relevant softswitch variables; to see what has changed */
+ new_a2 = effective_a2(state);
+ if (new_a2 & VAR_80STORE)
+ new_a2 &= ~VAR_PAGE2;
+ new_a2 &= VAR_TEXT | VAR_MIXED | VAR_HIRES | VAR_DHIRES | VAR_80COL | VAR_PAGE2 | VAR_ALTCHARSET;
+
+ if (ALWAYS_REFRESH || (new_a2 != state->m_old_a2))
+ {
+ state->m_old_a2 = new_a2;
+ }
+
+ /* choose which page to use */
+ page = (new_a2 & VAR_PAGE2) ? 1 : 0;
+
+ /* choose the video mode to draw */
+ if (effective_a2(state) & VAR_TEXT)
+ {
+ /* text screen - TK2000 uses HGR for text */
+ if (state->m_machinetype == TK2000)
+ {
+ apple2_hires_draw(machine, bitmap, cliprect, page, 0, 191);
+ }
+ else
+ {
+ apple2_text_draw(machine, bitmap, cliprect, page, 0, 191);
+ }
+ }
+ else if ((effective_a2(state) & VAR_HIRES) && (effective_a2(state) & VAR_MIXED))
+ {
+ /* hi-res on top; text at bottom */
+ apple2_hires_draw(machine, bitmap, cliprect, page, 0, 159);
+ apple2_text_draw(machine, bitmap, cliprect, page, 160, 191);
+ }
+ else if (effective_a2(state) & VAR_HIRES)
+ {
+ /* hi-res screen */
+ apple2_hires_draw(machine, bitmap, cliprect, page, 0, 191);
+ }
+ else if (effective_a2(state) & VAR_MIXED)
+ {
+ /* lo-res on top; text at bottom */
+ apple2_lores_draw(machine, bitmap, cliprect, page, 0, 159);
+ apple2_text_draw(machine, bitmap, cliprect, page, 160, 191);
+ }
+ else
+ {
+ /* lo-res screen */
+ apple2_lores_draw(machine, bitmap, cliprect, page, 0, 191);
+ }
+ return 0;
+}
diff --git a/src/mess/video/apple2gs.c b/src/mess/video/apple2gs.c
new file mode 100644
index 00000000000..d261a4561ab
--- /dev/null
+++ b/src/mess/video/apple2gs.c
@@ -0,0 +1,164 @@
+/*********************************************************************
+
+ video/apple2gs.c
+
+ Apple IIgs video code
+
+*********************************************************************/
+
+
+#include "emu.h"
+#include "includes/apple2.h"
+#include "includes/apple2gs.h"
+
+
+
+VIDEO_START( apple2gs )
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ state->m_bordercolor = 0;
+ apple2_video_start(machine, state->m_slowmem, 0x20000, 0, 8);
+ state->m_legacy_gfx = auto_bitmap_ind16_alloc(machine, 560, 192);
+
+ state_save_register_item(machine, "BORDERCLR", NULL, 0, state->m_bordercolor);
+}
+
+
+
+SCREEN_UPDATE_IND16( apple2gs )
+{
+ apple2gs_state *state = screen.machine().driver_data<apple2gs_state>();
+ const UINT8 *vram;
+ UINT16 *scanline;
+ UINT8 scb, b;
+ int col, palette;
+ UINT16 last_pixel = 0, pixel;
+ int beamy;
+
+ beamy = cliprect.min_y;
+
+ if (state->m_newvideo & 0x80)
+ {
+ // in top or bottom border?
+ if ((beamy < BORDER_TOP) || (beamy >= 200+BORDER_TOP))
+ {
+ // don't draw past the bottom border
+ if (beamy >= 231+BORDER_TOP)
+ {
+ return 0;
+ }
+
+ scanline = &bitmap.pix16(beamy);
+ for (col = 0; col < BORDER_LEFT+BORDER_RIGHT+640; col++)
+ {
+ scanline[col] = state->m_bordercolor;
+ }
+ }
+ else // regular screen area
+ {
+ int shrline = beamy - BORDER_TOP;
+
+ scb = state->m_slowmem[0x19D00 + shrline];
+ palette = ((scb & 0x0f) << 4) + 16;
+
+ vram = &state->m_slowmem[0x12000 + (shrline * 160)];
+ scanline = &bitmap.pix16(beamy);
+
+ // draw left and right borders
+ for (col = 0; col < BORDER_LEFT; col++)
+ {
+ scanline[col] = state->m_bordercolor;
+ scanline[col+BORDER_LEFT+640] = state->m_bordercolor;
+ }
+
+ if (scb & 0x80) // 640 mode
+ {
+ for (col = 0; col < 160; col++)
+ {
+ b = vram[col];
+ scanline[col * 4 + 0 + BORDER_LEFT] = palette + 0 + ((b >> 6) & 0x03);
+ scanline[col * 4 + 1 + BORDER_LEFT] = palette + 4 + ((b >> 4) & 0x03);
+ scanline[col * 4 + 2 + BORDER_LEFT] = palette + 8 + ((b >> 2) & 0x03);
+ scanline[col * 4 + 3 + BORDER_LEFT] = palette + 12 + ((b >> 0) & 0x03);
+ }
+ }
+ else // 320 mode
+ {
+ for (col = 0; col < 160; col++)
+ {
+ b = vram[col];
+ pixel = (b >> 4) & 0x0f;
+
+ if ((scb & 0x20) && !pixel)
+ pixel = last_pixel;
+ else
+ last_pixel = pixel;
+ pixel += palette;
+ scanline[col * 4 + 0 + BORDER_LEFT] = pixel;
+ scanline[col * 4 + 1 + BORDER_LEFT] = pixel;
+
+ b = vram[col];
+ pixel = (b >> 0) & 0x0f;
+
+ if ((scb & 0x20) && !pixel)
+ pixel = last_pixel;
+ else
+ last_pixel = pixel;
+ pixel += palette;
+ scanline[col * 4 + 2 + BORDER_LEFT] = pixel;
+ scanline[col * 4 + 3 + BORDER_LEFT] = pixel;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* call legacy Apple II video rendering at scanline 0 to draw into the off-screen buffer */
+ if (beamy == 0)
+ {
+ apple2_state *a2state = screen.machine().driver_data<apple2_state>();
+
+ // check if DHR should be monochrome 560x192
+ if (state->m_newvideo & 0x20)
+ {
+ a2state->m_monochrome_dhr = true;
+ }
+ else
+ {
+ a2state->m_monochrome_dhr = false;
+ }
+
+ rectangle new_cliprect(0, 559, 0, 191);
+ SCREEN_UPDATE_NAME(apple2)(NULL, screen, *state->m_legacy_gfx, new_cliprect);
+ }
+
+ if ((beamy < (BORDER_TOP+4)) || (beamy >= (192+4+BORDER_TOP)))
+ {
+ if (beamy >= (231+BORDER_TOP))
+ {
+ return 0;
+ }
+
+ scanline = &bitmap.pix16(beamy);
+ for (col = 0; col < BORDER_LEFT+BORDER_RIGHT+640; col++)
+ {
+ scanline[col] = state->m_bordercolor;
+ }
+ }
+ else
+ {
+ scanline = &bitmap.pix16(beamy);
+
+ // draw left and right borders
+ for (col = 0; col < BORDER_LEFT + 40; col++)
+ {
+ scanline[col] = state->m_bordercolor;
+ scanline[col+BORDER_LEFT+600] = state->m_bordercolor;
+ }
+
+ memcpy(scanline + 40 + BORDER_LEFT, &state->m_legacy_gfx->pix16(beamy-(BORDER_TOP+4)), 560 * sizeof(UINT16));
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/apple3.c b/src/mess/video/apple3.c
new file mode 100644
index 00000000000..130dbb51ded
--- /dev/null
+++ b/src/mess/video/apple3.c
@@ -0,0 +1,401 @@
+/***************************************************************************
+
+ video/apple3.c
+
+ Apple ///
+
+***************************************************************************/
+
+
+#include "emu.h"
+#include "includes/apple3.h"
+#include "machine/ram.h"
+
+#define BLACK 0
+#define DKRED 1
+#define DKBLUE 2
+#define PURPLE 3
+#define DKGREEN 4
+#define DKGRAY 5
+#define BLUE 6
+#define LTBLUE 7
+#define BROWN 8
+#define ORANGE 9
+#define GRAY 10
+#define PINK 11
+#define GREEN 12
+#define YELLOW 13
+#define AQUA 14
+#define WHITE 15
+
+
+static const UINT32 text_map[] =
+{
+ 0x400, 0x480, 0x500, 0x580, 0x600, 0x680, 0x700, 0x780,
+ 0x428, 0x4a8, 0x528, 0x5a8, 0x628, 0x6a8, 0x728, 0x7a8,
+ 0x450, 0x4d0, 0x550, 0x5d0, 0x650, 0x6d0, 0x750, 0x7d0
+};
+
+
+void apple3_write_charmem(running_machine &machine)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ static const UINT32 screen_hole_map[] =
+ {
+ 0x478, 0x4f8, 0x578, 0x5f8, 0x678, 0x6f8, 0x778, 0x7f8
+ };
+ int i, j, addr;
+ UINT8 val;
+
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 4; j++)
+ {
+ addr = 0x7f & space->read_byte(screen_hole_map[i] + 0x400 + j + 0);
+ val = space->read_byte(screen_hole_map[i] + j + 0);
+ state->m_char_mem[((addr * 8) + ((i & 3) * 2) + 0) & 0x3ff] = val;
+
+ addr = 0x7f & space->read_byte(screen_hole_map[i] + 0x400 + j + 4);
+ val = space->read_byte(screen_hole_map[i] + j + 4);
+ state->m_char_mem[((addr * 8) + ((i & 3) * 2) + 1) & 0x3ff] = val;
+ }
+ }
+}
+
+
+
+VIDEO_START( apple3 )
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ int i, j;
+ UINT32 v;
+
+ state->m_char_mem = auto_alloc_array(machine, UINT8, 0x800);
+ memset(state->m_char_mem, 0, 0x800);
+
+ state->m_hgr_map = auto_alloc_array(machine, UINT32, 192);
+ for (i = 0; i < 24; i++)
+ {
+ v = text_map[i] - 0x0400;
+ for (j = 0; j < 8; j++)
+ {
+ state->m_hgr_map[(i * 8) + j] = 0x2000 + v + (j * 0x400);
+ }
+ }
+}
+
+
+
+static void apple3_video_text40(running_machine &machine,bitmap_ind16 &bitmap)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ int x, y, col, row;
+ offs_t offset;
+ UINT8 ch;
+ const UINT8 *char_data;
+ pen_t fg, bg, temp;
+ UINT16 *dest;
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+ UINT32 ram_size = machine.device<ram_device>(RAM_TAG)->size();
+
+ for (y = 0; y < 24; y++)
+ {
+ for (x = 0; x < 40; x++)
+ {
+ offset = ram_size - 0x8000 + text_map[y] + x + (state->m_flags & VAR_VM2 ? 0x0400 : 0x0000);
+ ch = ram[offset];
+
+ if (state->m_flags & VAR_VM0)
+ {
+ /* color text */
+ offset = ram_size - 0x8000 + text_map[y] + x + (state->m_flags & VAR_VM2 ? 0x0000 : 0x0400);
+ bg = (ram[offset] >> 0) & 0x0F;
+ fg = (ram[offset] >> 4) & 0x0F;
+ }
+ else
+ {
+ /* monochrome */
+ bg = BLACK;
+ fg = GREEN;
+ }
+
+ /* inverse? */
+ if (!(ch & 0x80))
+ {
+ temp = fg;
+ fg = bg;
+ bg = temp;
+ }
+
+ char_data = &state->m_char_mem[(ch & 0x7F) * 8];
+
+ for (row = 0; row < 8; row++)
+ {
+ for (col = 0; col < 7; col++)
+ {
+ dest = &bitmap.pix16(y * 8 + row, x * 14 + col * 2);
+ dest[0] = (char_data[row] & (1 << col)) ? fg : bg;
+ dest[1] = (char_data[row] & (1 << col)) ? fg : bg;
+ }
+ }
+ }
+ }
+}
+
+
+
+static void apple3_video_text80(running_machine &machine,bitmap_ind16 &bitmap)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ int x, y, col, row;
+ offs_t offset;
+ UINT8 ch;
+ const UINT8 *char_data;
+ pen_t fg, bg;
+ UINT16 *dest;
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+ UINT32 ram_size = machine.device<ram_device>(RAM_TAG)->size();
+
+ for (y = 0; y < 24; y++)
+ {
+ for (x = 0; x < 40; x++)
+ {
+ offset = ram_size - 0x8000 + text_map[y] + x;
+
+ /* first character */
+ ch = ram[offset + 0x0000];
+ char_data = &state->m_char_mem[(ch & 0x7F) * 8];
+ fg = (ch & 0x80) ? GREEN : BLACK;
+ bg = (ch & 0x80) ? BLACK : GREEN;
+
+ for (row = 0; row < 8; row++)
+ {
+ for (col = 0; col < 7; col++)
+ {
+ dest = &bitmap.pix16(y * 8 + row, x * 14 + col + 0);
+ *dest = (char_data[row] & (1 << col)) ? fg : bg;
+ }
+ }
+
+ /* second character */
+ ch = ram[offset + 0x0400];
+ char_data = &state->m_char_mem[(ch & 0x7F) * 8];
+ fg = (ch & 0x80) ? GREEN : BLACK;
+ bg = (ch & 0x80) ? BLACK : GREEN;
+
+ for (row = 0; row < 8; row++)
+ {
+ for (col = 0; col < 7; col++)
+ {
+ dest = &bitmap.pix16(y * 8 + row, x * 14 + col + 7);
+ *dest = (char_data[row] & (1 << col)) ? fg : bg;
+ }
+ }
+ }
+ }
+}
+
+
+
+static void apple3_video_graphics_hgr(running_machine &machine,bitmap_ind16 &bitmap)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ /* hi-res mode: 280x192x2 */
+ int y, i, x;
+ const UINT8 *pix_info;
+ UINT16 *ptr;
+ UINT8 b;
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ for (y = 0; y < 192; y++)
+ {
+ if (state->m_flags & VAR_VM2)
+ pix_info = &ram[state->m_hgr_map[y]];
+ else
+ pix_info = &ram[state->m_hgr_map[y] - 0x2000];
+ ptr = &bitmap.pix16(y);
+
+ for (i = 0; i < 40; i++)
+ {
+ b = *(pix_info++);
+
+ for (x = 0; x < 7; x++)
+ {
+ ptr[0] = ptr[1] = (b & 0x01) ? WHITE : BLACK;
+ ptr += 2;
+ b >>= 1;
+ }
+ }
+ }
+}
+
+
+
+static UINT8 swap_bits(UINT8 b)
+{
+ return (b & 0x08 ? 0x01 : 0x00)
+ | (b & 0x04 ? 0x02 : 0x00)
+ | (b & 0x02 ? 0x04 : 0x00)
+ | (b & 0x01 ? 0x08 : 0x00);
+}
+
+
+
+static void apple3_video_graphics_chgr(running_machine &machine,bitmap_ind16 &bitmap)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ /* color hi-res mode: 280x192x16 */
+ int y, i, x;
+ const UINT8 *pix_info;
+ const UINT8 *col_info;
+ UINT16 *ptr;
+ UINT8 b;
+ UINT16 fgcolor, bgcolor;
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ for (y = 0; y < 192; y++)
+ {
+ if (state->m_flags & VAR_VM2)
+ {
+ pix_info = &ram[state->m_hgr_map[y]];
+ col_info = &ram[state->m_hgr_map[y] - 0x2000];
+ }
+ else
+ {
+ pix_info = &ram[state->m_hgr_map[y] - 0x2000];
+ col_info = &ram[state->m_hgr_map[y]];
+ }
+ ptr = &bitmap.pix16(y);
+
+ for (i = 0; i < 40; i++)
+ {
+ bgcolor = swap_bits((*col_info >> 0) & 0x0F);
+ fgcolor = swap_bits((*col_info >> 4) & 0x0F);
+
+ b = *pix_info;
+
+ for (x = 0; x < 7; x++)
+ {
+ ptr[0] = ptr[1] = (b & 1) ? fgcolor : bgcolor;
+ ptr += 2;
+ b >>= 1;
+ }
+ pix_info++;
+ col_info++;
+ }
+ }
+}
+
+
+
+static void apple3_video_graphics_shgr(running_machine &machine,bitmap_ind16 &bitmap)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ /* super hi-res mode: 560x192x2 */
+ int y, i, x;
+ const UINT8 *pix_info1;
+ const UINT8 *pix_info2;
+ UINT16 *ptr;
+ UINT8 b1, b2;
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ for (y = 0; y < 192; y++)
+ {
+ if (state->m_flags & VAR_VM2)
+ {
+ pix_info1 = &ram[state->m_hgr_map[y]];
+ pix_info2 = &ram[state->m_hgr_map[y] + 0x2000];
+ }
+ else
+ {
+ pix_info1 = &ram[state->m_hgr_map[y] - 0x2000];
+ pix_info2 = &ram[state->m_hgr_map[y]];
+ }
+ ptr = &bitmap.pix16(y);
+
+ for (i = 0; i < 40; i++)
+ {
+ b1 = *(pix_info1++);
+ b2 = *(pix_info2++);
+
+ for (x = 0; x < 7; x++)
+ {
+ *(ptr++) = (b1 & 0x01) ? WHITE : BLACK;
+ *(ptr++) = (b2 & 0x01) ? WHITE : BLACK;
+ b1 >>= 1;
+ b2 >>= 1;
+ }
+ }
+ }
+}
+
+
+
+static void apple3_video_graphics_chires(running_machine &machine,bitmap_ind16 &bitmap)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ UINT16 *pen;
+ PAIR pix;
+ int y, i;
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ for (y = 0; y < 192; y++)
+ {
+ pen = &bitmap.pix16(y);
+ for (i = 0; i < 20; i++)
+ {
+ pix.b.l = ram[state->m_hgr_map[y] - 0x2000 + (i * 2) + (state->m_flags & VAR_VM2 ? 1 : 0) + 0];
+ pix.b.h = ram[state->m_hgr_map[y] - 0x0000 + (i * 2) + (state->m_flags & VAR_VM2 ? 1 : 0) + 0];
+ pix.b.h2 = ram[state->m_hgr_map[y] - 0x2000 + (i * 2) + (state->m_flags & VAR_VM2 ? 1 : 0) + 1];
+ pix.b.h3 = ram[state->m_hgr_map[y] - 0x0000 + (i * 2) + (state->m_flags & VAR_VM2 ? 1 : 0) + 1];
+
+ pen[ 0] = pen[ 1] = pen[ 2] = pen[ 3] = ((pix.d >> 0) & 0x0F);
+ pen[ 4] = pen[ 5] = pen[ 6] = pen[ 7] = ((pix.d >> 4) & 0x07) | ((pix.d >> 1) & 0x08);
+ pen[ 8] = pen[ 9] = pen[10] = pen[11] = ((pix.d >> 9) & 0x0F);
+ pen[12] = pen[13] = pen[14] = pen[15] = ((pix.d >> 13) & 0x03) | ((pix.d >> 14) & 0x0C);
+ pen[16] = pen[17] = pen[18] = pen[19] = ((pix.d >> 18) & 0x0F);
+ pen[20] = pen[21] = pen[22] = pen[23] = ((pix.d >> 22) & 0x01) | ((pix.d >> 23) & 0x0E);
+ pen[24] = pen[25] = pen[26] = pen[27] = ((pix.d >> 27) & 0x0F);
+ pen += 28;
+ }
+ }
+}
+
+
+
+SCREEN_UPDATE_IND16( apple3 )
+{
+ apple3_state *state = screen.machine().driver_data<apple3_state>();
+ switch(state->m_flags & (VAR_VM3|VAR_VM1|VAR_VM0))
+ {
+ case 0:
+ case VAR_VM0:
+ apple3_video_text40(screen.machine(),bitmap);
+ break;
+
+ case VAR_VM1:
+ case VAR_VM1|VAR_VM0:
+ apple3_video_text80(screen.machine(),bitmap);
+ break;
+
+ case VAR_VM3:
+ apple3_video_graphics_hgr(screen.machine(),bitmap); /* hgr mode */
+ break;
+
+ case VAR_VM3|VAR_VM0:
+ apple3_video_graphics_chgr(screen.machine(),bitmap);
+ break;
+
+ case VAR_VM3|VAR_VM1:
+ apple3_video_graphics_shgr(screen.machine(),bitmap);
+ break;
+
+ case VAR_VM3|VAR_VM1|VAR_VM0:
+ apple3_video_graphics_chires(screen.machine(),bitmap);
+ break;
+ }
+ return 0;
+}
+
+
diff --git a/src/mess/video/aquarius.c b/src/mess/video/aquarius.c
new file mode 100644
index 00000000000..875d758af17
--- /dev/null
+++ b/src/mess/video/aquarius.c
@@ -0,0 +1,104 @@
+/***************************************************************************
+
+ aquarius.c
+
+ Functions to emulate the video hardware of the aquarius.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/aquarius.h"
+
+
+
+static const rgb_t aquarius_colors[] =
+{
+ RGB_BLACK, /* Black */
+ MAKE_RGB(0xff, 0x00, 0x00), /* Red */
+ MAKE_RGB(0x00, 0xff, 0x00), /* Green */
+ MAKE_RGB(0xff, 0xff, 0x00), /* Yellow */
+ MAKE_RGB(0x00, 0x00, 0xff), /* Blue */
+ MAKE_RGB(0x7f, 0x00, 0x7f), /* Violet */
+ MAKE_RGB(0x7f, 0xff, 0xff), /* Light Blue-Green */
+ RGB_WHITE, /* White */
+ MAKE_RGB(0xc0, 0xc0, 0xc0), /* Light Gray */
+ MAKE_RGB(0x00, 0xff, 0xff), /* Blue-Green */
+ MAKE_RGB(0xff, 0x00, 0xff), /* Magenta */
+ MAKE_RGB(0x00, 0x00, 0x7f), /* Dark Blue */
+ MAKE_RGB(0xff, 0xff, 0x7f), /* Light Yellow */
+ MAKE_RGB(0x7f, 0xff, 0x7f), /* Light Green */
+ MAKE_RGB(0xff, 0x7f, 0x00), /* Orange */
+ MAKE_RGB(0x7f, 0x7f, 0x7f) /* Dark Gray */
+};
+
+static const unsigned short aquarius_palette[] =
+{
+ 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0,10, 0,11, 0,12, 0,13, 0,14, 0,15, 0,
+ 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1,10, 1,11, 1,12, 1,13, 1,14, 1,15, 1,
+ 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2,10, 2,11, 2,12, 2,13, 2,14, 2,15, 2,
+ 0, 3, 1, 3, 2, 3, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3,10, 3,11, 3,12, 3,13, 3,14, 3,15, 3,
+ 0, 4, 1, 4, 2, 4, 3, 4, 4, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 4,10, 4,11, 4,12, 4,13, 4,14, 4,15, 4,
+ 0, 5, 1, 5, 2, 5, 3, 5, 4, 5, 5, 5, 6, 5, 7, 5, 8, 5, 9, 5,10, 5,11, 5,12, 5,13, 5,14, 5,15, 5,
+ 0, 6, 1, 6, 2, 6, 3, 6, 4, 6, 5, 6, 6, 6, 7, 6, 8, 6, 9, 6,10, 6,11, 6,12, 6,13, 6,14, 6,15, 6,
+ 0, 7, 1, 7, 2, 7, 3, 7, 4, 7, 5, 7, 6, 7, 7, 7, 8, 7, 9, 7,10, 7,11, 7,12, 7,13, 7,14, 7,15, 7,
+ 0, 8, 1, 8, 2, 8, 3, 8, 4, 8, 5, 8, 6, 8, 7, 8, 8, 8, 9, 8,10, 8,11, 8,12, 8,13, 8,14, 8,15, 8,
+ 0, 9, 1, 9, 2, 9, 3, 9, 4, 9, 5, 9, 6, 9, 7, 9, 8, 9, 9, 9,10, 9,11, 9,12, 9,13, 9,14, 9,15, 9,
+ 0,10, 1,10, 2,10, 3,10, 4,10, 5,10, 6,10, 7,10, 8,10, 9,10,10,10,11,10,12,10,13,10,14,10,15,10,
+ 0,11, 1,11, 2,11, 3,11, 4,11, 5,11, 6,11, 7,11, 8,11, 9,11,10,11,11,11,12,11,13,11,14,11,15,11,
+ 0,12, 1,12, 2,12, 3,12, 4,12, 5,12, 6,12, 7,12, 8,12, 9,12,10,12,11,12,12,12,13,12,14,12,15,12,
+ 0,13, 1,13, 2,13, 3,13, 4,13, 5,13, 6,13, 7,13, 8,13, 9,13,10,13,11,13,12,13,13,13,14,13,15,13,
+ 0,14, 1,14, 2,14, 3,14, 4,14, 5,14, 6,14, 7,14, 8,14, 9,14,10,14,11,14,12,14,13,14,14,14,15,14,
+ 0,15, 1,15, 2,15, 3,15, 4,15, 5,15, 6,15, 7,15, 8,15, 9,15,10,15,11,15,12,15,13,15,14,15,15,15,
+};
+
+PALETTE_INIT( aquarius )
+{
+ int i;
+
+ machine.colortable = colortable_alloc(machine, 16);
+
+ for (i = 0; i < 16; i++)
+ colortable_palette_set_color(machine.colortable, i, aquarius_colors[i]);
+
+ for (i = 0; i < 512; i++)
+ colortable_entry_set_value(machine.colortable, i, aquarius_palette[i]);
+}
+
+WRITE8_MEMBER(aquarius_state::aquarius_videoram_w)
+{
+ UINT8 *videoram = m_videoram;
+ videoram[offset] = data;
+ m_tilemap->mark_tile_dirty(offset);
+}
+
+WRITE8_MEMBER(aquarius_state::aquarius_colorram_w)
+{
+ m_colorram[offset] = data;
+ m_tilemap->mark_tile_dirty(offset);
+}
+
+static TILE_GET_INFO(aquarius_gettileinfo)
+{
+ aquarius_state *state = machine.driver_data<aquarius_state>();
+ UINT8 *videoram = state->m_videoram;
+ int bank = 0;
+ int code = videoram[tile_index];
+ int color = state->m_colorram[tile_index];
+ int flags = 0;
+
+ SET_TILE_INFO(bank, code, color, flags);
+}
+
+VIDEO_START( aquarius )
+{
+ aquarius_state *state = machine.driver_data<aquarius_state>();
+ state->m_tilemap = tilemap_create(machine, aquarius_gettileinfo, tilemap_scan_rows, 8, 8, 40, 25);
+}
+
+SCREEN_UPDATE_IND16( aquarius )
+{
+ aquarius_state *state = screen.machine().driver_data<aquarius_state>();
+ state->m_tilemap->draw(bitmap, cliprect, 0, 0);
+
+ return 0;
+}
diff --git a/src/mess/video/arcadia.c b/src/mess/video/arcadia.c
new file mode 100644
index 00000000000..1d6ee322c13
--- /dev/null
+++ b/src/mess/video/arcadia.c
@@ -0,0 +1,682 @@
+/******************************************************************************
+Consolidation and enhancment of documentation by Manfred Schneider based on previous work from
+ PeT mess@utanet.at and Paul Robson (autismuk@aol.com)
+
+ Schematics, manuals and anything you can desire for at http://amigan.1emu.net/
+
+ TODO: find a dump of the charactyer ROM
+ convert the drawing code to tilemap
+
+ emulation of signetics 2637 video/audio device
+
+General
+The UVI is capable of controlling 512 Bytes of RAM. It also generates a select signal
+for a 128 byte wide area.
+This whole addres space maps in the arcadia and compatible machines from $1800 - $1AFF.
+
+1. Video Memory
+
+The screen table is at 1800-CF and 1A00-CF. Each page has 13 lines of the
+screen (16 bytes per line,26 lines in total, 208 scan lines). The 2 most
+significant bits of each byte are colour data, the 6 least significant
+are character data. The resolution of the Arcadia is 128 x 208 pixels.
+
+It is possible to halve the screen resolution so 1A00..1ACF can
+be used for code. This is controlled by bit 6 of $19F8.
+
+The byte at location $18FF is the current Character Line address, lower
+4 bits only. The start line goes from 1800 to 18C0 then from 1900 to 19C0.
+The 4 least significant bits of this count 0123456789ABC0123456789ABC,
+going to D when in vertical blank. The 4 most significant bits are always
+'1'. Some games do use this for scrolling effects - a good example of this
+is the routine at $010F in Alien Invaders which scrolls the various bits of
+the screen about using the memory locations $18FF and $18FE.
+
+The screen can be scrolled upto 7 pixels to the left using the high 3 bits
+of $18FE. This is used in Alien Invaders.
+
+A line beginning with $C0 contains block graphics. Each square contains
+3 wide x 2 high pixels, coloured as normal. The 3 least significant bits
+are the top, the next 3 bits are the bottom. Alien Invaders uses this for
+shields. The graphics are returned to normal for the next line.
+
+The VBlank signal (maybe VSYNC) is connected to the SENSE input. This is
+logic '1' when the system is in VBLANK.
+
+The Flag line does.... something graphical - it might make the sprites
+half width/double height perhaps. Breakaway sets this when the bats are
+double size in vertical mode.
+
+
+2. Character codes
+
+Character codes 00..37 to be in a ROM somewhere in the Emerson. These
+are known, others may be discovered by comparing the screen snapshots
+against the character tables. If the emulator displays an exclamation
+mark you've found one. Get a snapshot to see what it looks like
+normally and let me know. Codes 38..3F are taken from RAM.
+
+00 (space)
+01..0F Graphic Characters
+10..19 0..9
+1A..33 A..Z
+34 Decimal Point
+35 comma
+36 +
+37 $
+38..3F User Defined Characters (8 off, from 1980..19FF)
+
+Character data is stored 8 bits per character , as a single plane graphic
+The 2nd and 3rd bits of palette data come from the screen tables, so there
+are two colours per character and 4 possible palette selections for the
+background.
+
+
+3. Sound
+
+fixed frequency sound and random Noise generator.
+18FD pitch (lower 7 bits)
+18FE volume ( bits 0 - 2)
+18fe bit 3 set means sound on
+18fe bit 4 set means random noise on
+
+Calculation of sound frequency is done as follows
+ 1/Freq = 2 (pitch +1) * (horizontal line period)
+
+
+4. Sprites
+
+Sprite pointers are at 18F0..18F7 (there are four of them). The graphics
+used are the ones in the 1980..19BF UDG table (the first four).
+
+Sprite addresses (x,y) are converted to offsets in the 128 x 208 as follows:
+
+1) 1's complement the y coordinate
+2) subtract 16 from the y coordinate
+3) subtract 43 from the x coordinate
+
+5. Palette
+
+The Palette is encoded between 19F8-19FB. This section describes the method
+by which colours are allocated. There are 8 colours, information is coded
+3 bits per colour (usually 2 colours per byte)
+
+ Colour Code Name
+ ------ ----- -------
+ 7 111 Black
+ 6 110 Blue
+ 5 101 Red
+ 4 100 Magenta
+ 3 011 Green
+ 2 010 Cyan
+ 1 001 Yellow
+ 0 000 White
+
+Bits 0..2 of $19F9 are the screen colour
+Bits 3..5 of $19F9 are the colours of characters
+Bit 6 of $19f9 is for poti axis
+Bit 7 of $19f9 is for character size (1 = 8x8; 0 = 8x16)
+Bits 0..5 of $19FA are the colours of Sprites 2 & 3 (sprite 3 is low bits)
+Bit 6 of $19FA is for size of sprite 3 (0 = 8x16; 1 = 8x8)
+Bit 7 of $19FA is for size of sprite 2 (0 = 8x16; 1 = 8x8)
+Bits 0..5 of $19FB are the colours of Sprites 0 & 1 (sprite 1 is low bits)
+Bit 6 of $19FB is for size of sprite 1 (0 = 8x16; 1 = 8x8)
+Bit 7 of $19FB is for size of sprite 0 (0 = 8x16; 1 = 8x8)
+
+
+6. Collision Detection
+
+Bits are set to zero on a collision - I think they are reset at the
+frame start. There are two locations : one is for sprite/background
+collisions, one is for sprite/sprite collisions.
+
+19FC bits 0..3 are collision between sprites 0..3 and the background.
+
+19FD bit 0 is sprite 0 / 1 collision
+ bit 1 is sprite 0 / 2 collision
+ bit 2 is sprite 0 / 3 collision
+ bit 3 is sprite 1 / 2 collision
+ bit 4 is sprite 1 / 3 collision (guess)
+ bit 5 is sprite 2 / 3 collision (guess)
+
+
+7. Graphic Mode
+19f8 bit 7 graphics mode on (lower 6 bits descripe rectangles)
+0xc0 in line switches to graphics mode in this line
+0x40 in line switches to char mode in this line
+ 22211100
+ 22211100
+ 22211100
+ 22211100
+ 55544433
+ 55544433
+ 55544433
+ 55544433
+
+ 8. Memory Map
+ The offsets in the following memory Map are from the view of the UVI.
+ In the arcadia and compatibles the base offset is $1800 thats how the CPU sees the UVI
+
+ 0000 - 00FF external RAM
+ 0000 - 00CF upper screen character/graphics codes organised as 16 char x 13 rows
+ 00D0 - 00EF RAM (not used by UVI, can be used by CPU)
+ 00F0 vertical offset object 0
+ 00F1 horizontal offset object 0
+ 00F2 vertical offset object 1
+ 00F3 horizontal offset object 1
+ 00F4 vertical offset object 2
+ 00F5 horizontal offset object 2
+ 00F6 vertical offset object 3
+ 00F7 horizontal offset object 3
+ 00F8 - 00FB RAM (not used by UVI, can be used by CPU)
+ 00FC complement number of rows from the trailing edge of VRST
+ to the start of character display
+ 00FD bit0 - 6 sound frequeny, bit 7 color mode
+ 00FE bit0 - 2 loudness, bit 3 sound enable when set, bit 4 random noise enable when set
+ bit 5 - 7 delay for row of characters
+ 00FF bit 0 - 3 DMA number, bit 4 - 7 unused
+0100 - 017F CE area. In arcadia used for keypad.
+0180 - 01FF internal UVI registers
+ 0180 - 0187 image of object 0 or UDC-code $38
+ 0188 - 018F image of object 1 or UDC-code $39
+ 0190 - 0197 image of object 2 or UDC-code $3A
+ 0198 - 019F image of object 3 or UDC-code $3B
+ 01A0 - 01A7 image of UDC-code $3C
+ 01A8 - 01AF image of UDC-code $3D
+ 01B0 - 01B7 image of UDC-code $3E
+ 01B8 - 01BF image of UDC-code $3F
+ 01C0 - 01F7 unused
+ 01F8 bit 0 - 2 alternate screen color, bit 3 - 5 alternate character color
+ bit 6 Refresh mode when set entire character field will be display twice
+ bit 7 Grahics mode
+ 01F9 bit 0 - 2 screen color, bit 3 - 5 character color
+ bit 6 poti mux control
+ bit 7 character size when set size=8x8 else size=8x16
+ 01FA bit 0 - 2 color of object 3, bit 3 - 5 color of object 2
+ bit 6 size of object 3 when set size=8x8 else size=8x16
+ bit 7 size of object 2 when set size=8x8 else size=8x16
+ 01FB bit 0 - 2 color of object 1, bit 3 - 5 color of object 0
+ bit 6 size of object 1 when set size=8x8 else size=8x16
+ bit 7 size of object 0 when set size=8x8 else size=8x16
+ 01FC object - character collision bits
+ bit 0 when low object 0 collided with character
+ bit 1 when low object 1 collided with character
+ bit 2 when low object 2 collided with character
+ bit 3 when low object 3 collided with character
+ bit 4 - 7 unused set to high
+ 01FD inter object collision
+ bit 0 - when low object 1 and 2 collide
+ bit 1 - when low object 1 and 3 collide
+ bit 2 - when low object 1 and 4 collide
+ bit 3 - when low object 2 and 3 collide
+ bit 4 - when low object 2 and 4 collide
+ bit 5 - when low object 3 and 4 collide
+ bit 6 - 7 unused set to high
+ 01FE digital value of POT1 or POT3 input. Valid only during VRST
+ 01FF digital value of POT2 or POT4 input. Valid only furing VRST
+0200 - 02FF 2nd external RAM
+ 0200 - 02CF lower screen character/graphics codes organised as 16 char x 13 rows
+ 02D0 - 02FF RAM (not used by UVI, can be used by CPU)
+*/
+
+
+#include "includes/arcadia.h"
+
+static const UINT8 chars[0x40][8]={
+ // read from the screen generated from a palladium
+ { 0,0,0,0,0,0,0,0 }, // 00 (space)
+ { 1,2,4,8,16,32,64,128 }, // 01 (\)
+ { 128,64,32,16,8,4,2,1 }, // 02 (/)
+ { 255,255,255,255,255,255,255,255 }, // 03 (solid block)
+ { 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00 },// 04 (?)
+ { 3,3,3,3,3,3,3,3 }, // 05 (half square right on)
+ { 0,0,0,0,0,0,255,255 }, // 06 (horz lower line)
+ { 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0 },// 07 (half square left on)
+ { 0xff,0xff,3,3,3,3,3,3 }, // 08 (?)
+ { 0xff,0xff,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0 },// 09 (?)
+ { 192,192,192,192,192,192,255,255 }, // 0A (!_)
+ { 3,3,3,3,3,3,255,255 }, // 0B (_!)
+ { 1,3,7,15,31,63,127,255 }, // 0C (diagonal block)
+ { 128,192,224,240,248,252,254,255 }, // 0D (diagonal block)
+ { 255,254,252,248,240,224,192,128 }, // 0E (diagonal block)
+ { 255,127,63,31,15,7,3,1 }, // 0F (diagonal block)
+ { 0x00,0x1c,0x22,0x26,0x2a,0x32,0x22,0x1c },// 10 0
+ { 0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x1c },// 11 1
+ { 0x00,0x1c,0x22,0x02,0x0c,0x10,0x20,0x3e },// 12 2
+ { 0x00,0x3e,0x02,0x04,0x0c,0x02,0x22,0x1c },// 13 3
+ { 0x00,0x04,0x0c,0x14,0x24,0x3e,0x04,0x04 },// 14 4
+ { 0x00,0x3e,0x20,0x3c,0x02,0x02,0x22,0x1c },// 15 5
+ { 0x00,0x0c,0x10,0x20,0x3c,0x22,0x22,0x1c },// 16 6
+ { 0x00,0x7c,0x02,0x04,0x08,0x10,0x10,0x10 },// 17 7
+ { 0x00,0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c },// 18 8
+ { 0x00,0x1c,0x22,0x22,0x3e,0x02,0x04,0x18 },// 19 9
+ { 0x00,0x08,0x14,0x22,0x22,0x3e,0x22,0x22 },// 1A A
+ { 0x00,0x3c,0x22,0x22,0x3c,0x22,0x22,0x3c },// 1B B
+ { 0x00,0x1c,0x22,0x20,0x20,0x20,0x22,0x1c },// 1C C
+ { 0x00,0x3c,0x22,0x22,0x22,0x22,0x22,0x3c },// 1D D
+ { 0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x3e },// 1E E
+ { 0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x20 },// 1F F
+ { 0x00,0x1e,0x20,0x20,0x20,0x26,0x22,0x1e },// 20 G
+ { 0x00,0x22,0x22,0x22,0x3e,0x22,0x22,0x22 },// 21 H
+ { 0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x1c },// 22 I
+ { 0x00,0x02,0x02,0x02,0x02,0x02,0x22,0x1c },// 23 J
+ { 0x00,0x22,0x24,0x28,0x30,0x28,0x24,0x22 },// 24 K
+ { 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x3e },// 25 L
+ { 0x00,0x22,0x36,0x2a,0x2a,0x22,0x22,0x22 },// 26 M
+ { 0x00,0x22,0x22,0x32,0x2a,0x26,0x22,0x22 },// 27 N
+ { 0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c },// 28 O
+ { 0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,0x20 },// 29 P
+ { 0x00,0x1c,0x22,0x22,0x22,0x2a,0x24,0x1a },// 2A Q
+ { 0x00,0x3c,0x22,0x22,0x3c,0x28,0x24,0x22 },// 2B R
+ { 0x00,0x1c,0x22,0x20,0x1c,0x02,0x22,0x1c },// 2C S
+ { 0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08 },// 2D T
+ { 0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1c },// 2E U
+ { 0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x08 },// 2F V
+ { 0x00,0x22,0x22,0x22,0x2a,0x2a,0x36,0x22 },// 30 W
+ { 0x00,0x22,0x22,0x14,0x08,0x14,0x22,0x22 },// 31 X
+ { 0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x08 },// 32 Y
+ { 0x00,0x3e,0x02,0x04,0x08,0x10,0x20,0x3e },// 33 Z
+ { 0,0,0,0,0,0,0,8 }, // 34 .
+ { 0,0,0,0,0,8,8,0x10 }, // 35 ,
+ { 0,0,8,8,0x3e,8,8,0 }, // 36 +
+ { 0,8,0x1e,0x28,0x1c,0xa,0x3c,8 }, // 37 $
+ // 8x user defined
+};
+
+VIDEO_START( arcadia )
+{
+ arcadia_state *state = machine.driver_data<arcadia_state>();
+ int i;
+ memcpy(&state->m_chars, chars, sizeof(chars));
+ for (i=0; i<0x40; i++)
+ {
+ state->m_rectangle[i][0]=0;
+ state->m_rectangle[i][4]=0;
+ if (i&1) state->m_rectangle[i][0]|=3;
+ if (i&2) state->m_rectangle[i][0]|=0x1c;
+ if (i&4) state->m_rectangle[i][0]|=0xe0;
+ if (i&8) state->m_rectangle[i][4]|=3;
+ if (i&0x10) state->m_rectangle[i][4]|=0x1c;
+ if (i&0x20) state->m_rectangle[i][4]|=0xe0;
+ state->m_rectangle[i][1]=state->m_rectangle[i][2]=state->m_rectangle[i][3]=state->m_rectangle[i][0];
+ state->m_rectangle[i][5]=state->m_rectangle[i][6]=state->m_rectangle[i][7]=state->m_rectangle[i][4];
+ }
+
+ {
+ screen_device *screen = machine.first_screen();
+ int width = screen->width();
+ int height = screen->height();
+ state->m_bitmap = auto_bitmap_ind16_alloc(machine, width, height);
+ }
+}
+
+READ8_MEMBER( arcadia_state::arcadia_video_r )
+{
+ UINT8 data=0;
+ switch (offset)
+ {
+ case 0xff: data=m_charline|0xf0;break;
+ case 0x100: data=ioport("controller1_col1")->read();break;
+ case 0x101: data=ioport("controller1_col2")->read();break;
+ case 0x102: data=ioport("controller1_col3")->read();break;
+ case 0x103: data=ioport("controller1_extra")->read();break;
+ case 0x104: data=ioport("controller2_col1")->read();break;
+ case 0x105: data=ioport("controller2_col2")->read();break;
+ case 0x106: data=ioport("controller2_col3")->read();break;
+ case 0x107: data=ioport("controller2_extra")->read();break;
+ case 0x108: data=ioport("panel")->read();break;
+#if 0
+ case 0x1fe:
+ if (m_ad_select)
+ data=ioport("controller1_joy_y")->read()<<3;
+ else
+ data=ioport("controller1_joy_x")->read()<<3;
+ break;
+ case 0x1ff:
+ if (m_ad_select)
+ data=ioport("controller2_joy_y")->read()<<3;
+ else
+ data=ioport("controller2_joy_x")->read()<<3;
+ break;
+#else
+ case 0x1fe:
+ data = 0x80;
+ if (m_ad_select)
+ {
+ if (ioport("joysticks")->read()&0x10) data=0;
+ if (ioport("joysticks")->read()&0x20) data=0xff;
+ }
+ else
+ {
+ if (ioport("joysticks")->read()&0x40) data=0xff;
+ if (ioport("joysticks")->read()&0x80) data=0;
+ }
+ break;
+ case 0x1ff:
+ data = 0x6f; // 0x7f too big for alien invaders (move right)
+ if (m_ad_select)
+ {
+ if (ioport("joysticks")->read()&0x1) data=0;
+ if (ioport("joysticks")->read()&0x2) data=0xff;
+ }
+ else
+ {
+ if (ioport("joysticks")->read()&0x4) data=0xff;
+ if (ioport("joysticks")->read()&0x8) data=0;
+ }
+ break;
+#endif
+ default:
+ data = m_reg.data[offset];
+ }
+ return data;
+}
+
+WRITE8_MEMBER( arcadia_state::arcadia_video_w )
+{
+ arcadia_sound_device *sound = machine().device<arcadia_sound_device>("custom");
+ m_reg.data[offset]=data;
+ switch (offset)
+ {
+ case 0xfc:
+ m_ypos=255-data+YPOS;
+ break;
+ case 0xfd:
+ sound->write(space, offset&3, data);
+ m_multicolor = data & 0x80;
+ break;
+ case 0xfe:
+ sound->write(space, offset&3, data);
+ m_shift = (data>>5);
+ break;
+ case 0xf0:
+ case 0xf2:
+ case 0xf4:
+ case 0xf6:
+ m_pos[(offset>>1)&3].y = (data^0xff)+1;
+ break;
+ case 0xf1:
+ case 0xf3:
+ case 0xf5:
+ case 0xf7:
+ m_pos[(offset>>1)&3].x = data-43;
+ break;
+ case 0x180: case 0x181: case 0x182: case 0x183: case 0x184: case 0x185: case 0x186: case 0x187:
+ case 0x188: case 0x189: case 0x18a: case 0x18b: case 0x18c: case 0x18d: case 0x18e: case 0x18f:
+ case 0x190: case 0x191: case 0x192: case 0x193: case 0x194: case 0x195: case 0x196: case 0x197:
+ case 0x198: case 0x199: case 0x19a: case 0x19b: case 0x19c: case 0x19d: case 0x19e: case 0x19f:
+ case 0x1a0: case 0x1a1: case 0x1a2: case 0x1a3: case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7:
+ case 0x1a8: case 0x1a9: case 0x1aa: case 0x1ab: case 0x1ac: case 0x1ad: case 0x1ae: case 0x1af:
+ case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7:
+ case 0x1b8: case 0x1b9: case 0x1ba: case 0x1bb: case 0x1bc: case 0x1bd: case 0x1be: case 0x1bf:
+ m_chars[0x38|((offset>>3)&7)][offset&7] = data;
+ break;
+ case 0x1f8:
+ m_lines26 = data & 0x40;
+ m_graphics = data & 0x80;
+ break;
+ case 0x1f9:
+ m_doublescan =! (data&0x80);
+ m_ad_delay = 10;
+ break;
+ }
+}
+
+INLINE void arcadia_draw_char(running_machine &machine, bitmap_ind16 &bitmap, UINT8 *ch, int charcode, int y, int x)
+{
+ arcadia_state *state = machine.driver_data<arcadia_state>();
+ int k,b,cc,sc, colour;
+ if (state->m_multicolor)
+ {
+ if (charcode&0x40)
+ cc=((state->m_reg.d.pal[1]>>3)&7);
+ else
+ cc=((state->m_reg.d.pal[0]>>3)&7);
+
+ if (charcode&0x80)
+ sc=(state->m_reg.d.pal[1]&7);
+ else
+ sc=(state->m_reg.d.pal[0]&7);
+ }
+ else
+ {
+ cc=((state->m_reg.d.pal[1]>>3)&1)|((charcode>>5)&6);
+ sc=(state->m_reg.d.pal[1]&7);
+ }
+ colour = (((sc << 3) | cc) + 4);
+
+ if (state->m_doublescan)
+ {
+ for (k=0; (k<8)&&(y<bitmap.height()); k++, y+=2)
+ {
+ b=ch[k];
+ state->m_bg[y][x>>3]|=b>>(x&7);
+ state->m_bg[y][(x>>3)+1]|=b<<(8-(x&7));
+
+ if (y+1<bitmap.height())
+ {
+ state->m_bg[y+1][x>>3]|=b>>(x&7);
+ state->m_bg[y+1][(x>>3)+1]|=b<<(8-(x&7));
+ drawgfx_opaque(bitmap, bitmap.cliprect(), machine.gfx[0], b,colour, 0,0,x,y);
+ drawgfx_opaque(bitmap, bitmap.cliprect(), machine.gfx[0], b,colour, 0,0,x,y+1);
+ }
+ }
+ }
+ else
+ {
+ for (k=0; (k<8)&&(y<bitmap.height()); k++, y++)
+ {
+ b=ch[k];
+ state->m_bg[y][x>>3]|=b>>(x&7);
+ state->m_bg[y][(x>>3)+1]|=b<<(8-(x&7));
+
+ drawgfx_opaque(bitmap, bitmap.cliprect(), machine.gfx[0], b,colour, 0,0,x,y);
+ }
+ }
+}
+
+INLINE void arcadia_vh_draw_line(running_machine &machine, bitmap_ind16 &bitmap, int y, UINT8 chars1[16])
+{
+ arcadia_state *state = machine.driver_data<arcadia_state>();
+ int x, ch, j, h;
+ int graphics=state->m_graphics;
+ h=state->m_doublescan ? 16 : 8 ;
+
+ if (bitmap.height()-state->m_line<h)
+ h=bitmap.height()-state->m_line;
+
+ bitmap.plot_box(0, y, bitmap.width(), h, (state->m_reg.d.pal[1]&7));
+ memset(state->m_bg[y], 0, sizeof(state->m_bg[0])*h);
+
+ for (x=XPOS+state->m_shift, j=0; j<16;j++,x+=8)
+ {
+ ch=chars1[j];
+// hangman switches with 0x40
+// alien invaders shield lines start with 0xc0
+ if ((ch&0x3f)==0)
+ {
+ switch (ch)
+ {
+ case 0xc0: graphics=TRUE;break;
+ case 0x40: graphics=FALSE;break;
+// case 0x80:
+// alien invaders shields are empty 0x80
+// popmessage(5, "graphics code 0x80 used");
+ }
+ }
+ if (graphics)
+ arcadia_draw_char(machine, bitmap, state->m_rectangle[ch&0x3f], ch, y, x);
+ else
+ arcadia_draw_char(machine, bitmap, state->m_chars[ch&0x3f], ch, y, x);
+ }
+}
+
+static int arcadia_sprite_collision(arcadia_state *state, int n1, int n2)
+{
+ int k, b1, b2, x;
+ if (state->m_pos[n1].x+8<=state->m_pos[n2].x)
+ return FALSE;
+ if (state->m_pos[n1].x>=state->m_pos[n2].x+8)
+ return FALSE;
+
+ for (k=0; k<8; k++)
+ {
+ if (state->m_pos[n1].y+k<state->m_pos[n2].y)
+ continue;
+ if (state->m_pos[n1].y+k>=state->m_pos[n2].y+8)
+ break;
+ x=state->m_pos[n1].x-state->m_pos[n2].x;
+ b1=state->m_reg.d.chars[n1][k];
+ b2=state->m_reg.d.chars[n2][state->m_pos[n1].y+k-state->m_pos[n2].y];
+ if (x<0)
+ b2>>=-x;
+ if (x>0)
+ b1>>=x;
+ if (b1&b2)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void arcadia_draw_sprites(running_machine &machine, bitmap_ind16 &bitmap)
+{
+ arcadia_state *state = machine.driver_data<arcadia_state>();
+ int i, k, x, y, color=0;
+ UINT8 b;
+
+ state->m_reg.d.collision_bg|=0xf;
+ state->m_reg.d.collision_sprite|=0x3f;
+ for (i=0; i<4; i++)
+ {
+ int doublescan = FALSE;
+ if (state->m_pos[i].y<=-YPOS) continue;
+ if (state->m_pos[i].y>=bitmap.height()-YPOS-8) continue;
+ if (state->m_pos[i].x<=-XPOS) continue;
+ if (state->m_pos[i].x>=128+XPOS-8) continue;
+
+ switch (i)
+ {
+ case 0:
+ color=(state->m_reg.d.pal[3]>>3)&7;
+ doublescan=state->m_reg.d.pal[3]&0x80?FALSE:TRUE;
+ break;
+ case 1:
+ color=state->m_reg.d.pal[3]&7;
+ doublescan=state->m_reg.d.pal[3]&0x40?FALSE:TRUE;
+ break;
+ case 2:
+ color=(state->m_reg.d.pal[2]>>3)&7;
+ doublescan=state->m_reg.d.pal[2]&0x80?FALSE:TRUE;
+ break;
+ case 3:
+ color=state->m_reg.d.pal[2]&7;
+ doublescan=state->m_reg.d.pal[2]&0x40?FALSE:TRUE;
+ break;
+ }
+ for (k=0; k<8; k++)
+ {
+ int j, m;
+ b=state->m_reg.d.chars[i][k];
+ x=state->m_pos[i].x+XPOS;
+ if (!doublescan)
+ {
+ y=state->m_pos[i].y+YPOS+k;
+ for (j=0,m=0x80; j<8; j++, m>>=1)
+ {
+ if (b & m)
+ bitmap.pix16(y, x + j) = color;
+ }
+ }
+ else
+ {
+ y=state->m_pos[i].y+YPOS+k*2;
+ for (j=0,m=0x80; j<8; j++, m>>=1)
+ {
+ if (b & m)
+ {
+ bitmap.pix16(y, x + j) = color;
+ bitmap.pix16(y+1, x + j) = color;
+ }
+ }
+ }
+ if (state->m_reg.d.collision_bg&(1<<i))
+ {
+ if ( (b<<(8-(x&7))) & ((state->m_bg[y][x>>3]<<8) | state->m_bg[y][(x>>3)+1]) )
+ state->m_reg.d.collision_bg&=~(1<<i);
+ }
+ }
+ }
+ if (arcadia_sprite_collision(state,0,1)) state->m_reg.d.collision_sprite&=~1;
+ if (arcadia_sprite_collision(state,0,2)) state->m_reg.d.collision_sprite&=~2;
+ if (arcadia_sprite_collision(state,0,3)) state->m_reg.d.collision_sprite&=~4;
+ if (arcadia_sprite_collision(state,1,2)) state->m_reg.d.collision_sprite&=~8;
+ if (arcadia_sprite_collision(state,1,3)) state->m_reg.d.collision_sprite&=~0x10; //guess
+ if (arcadia_sprite_collision(state,2,3)) state->m_reg.d.collision_sprite&=~0x20; //guess
+}
+
+INTERRUPT_GEN( arcadia_video_line )
+{
+ arcadia_state *state = device->machine().driver_data<arcadia_state>();
+ screen_device *screen = device->machine().first_screen();
+ int width = screen->width();
+
+ if (state->m_ad_delay<=0)
+ state->m_ad_select=state->m_reg.d.pal[1]&0x40;
+ else state->m_ad_delay--;
+
+ state->m_line++;
+ state->m_line%=262;
+ // unbelievable, reflects only charline, but alien invaders uses it for
+ // alien scrolling
+
+ if (state->m_line<state->m_ypos)
+ {
+ state->m_bitmap->plot_box(0, state->m_line, width, 1, (state->m_reg.d.pal[1])&7);
+ memset(state->m_bg[state->m_line], 0, sizeof(state->m_bg[0]));
+ }
+ else
+ {
+ int h=state->m_doublescan?16:8;
+
+ state->m_charline=(state->m_line-state->m_ypos)/h;
+
+ if (state->m_charline<13)
+ {
+ if (((state->m_line-state->m_ypos)&(h-1))==0)
+ {
+ arcadia_vh_draw_line(device->machine(), *state->m_bitmap, state->m_charline*h+state->m_ypos,
+ state->m_reg.d.chars1[state->m_charline]);
+ }
+ }
+ else
+ if (state->m_lines26 && (state->m_charline<26))
+ {
+ if (((state->m_line-state->m_ypos)&(h-1))==0)
+ {
+ arcadia_vh_draw_line(device->machine(), *state->m_bitmap, state->m_charline*h+state->m_ypos,
+ state->m_reg.d.chars2[state->m_charline-13]);
+ }
+ state->m_charline-=13;
+ }
+ else
+ {
+ state->m_charline=0xd;
+ state->m_bitmap->plot_box(0, state->m_line, width, 1, (state->m_reg.d.pal[1])&7);
+ memset(state->m_bg[state->m_line], 0, sizeof(state->m_bg[0]));
+ }
+ }
+ if (state->m_line==261)
+ arcadia_draw_sprites(device->machine(), *state->m_bitmap);
+}
+
+READ8_MEMBER( arcadia_state::arcadia_vsync_r )
+{
+ return m_line>=216 ? 0x80 : 0 ;
+}
+
+SCREEN_UPDATE_IND16( arcadia )
+{
+ arcadia_state *state = screen.machine().driver_data<arcadia_state>();
+ copybitmap(bitmap, *state->m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
diff --git a/src/mess/video/atarist.c b/src/mess/video/atarist.c
new file mode 100644
index 00000000000..d062d35d04f
--- /dev/null
+++ b/src/mess/video/atarist.c
@@ -0,0 +1,1182 @@
+/*
+
+ TODO:
+
+ - rewrite shifter
+ - STe pixelofs
+ - blitter hog
+ - high resolution
+
+*/
+
+#include "emu.h"
+#include "cpu/m68000/m68000.h"
+#include "machine/mc68901.h"
+#include "machine/ram.h"
+#include "video/atarist.h"
+#include "includes/atarist.h"
+
+
+
+//**************************************************************************
+// CONSTANTS / MACROS
+//**************************************************************************
+
+#define LOG 0
+
+static const int BLITTER_NOPS[16][4] =
+{
+ { 1, 1, 1, 1 },
+ { 2, 2, 3, 3 },
+ { 2, 2, 3, 3 },
+ { 1, 1, 2, 2 },
+ { 2, 2, 3, 3 },
+ { 2, 2, 2, 2 },
+ { 2, 2, 3, 3 },
+ { 2, 2, 3, 3 },
+ { 2, 2, 3, 3 },
+ { 2, 2, 3, 3 },
+ { 2, 2, 2, 2 },
+ { 2, 2, 3, 3 },
+ { 1, 1, 2, 2 },
+ { 2, 2, 3, 3 },
+ { 2, 2, 3, 3 },
+ { 1, 1, 1, 1 }
+};
+
+
+
+//**************************************************************************
+// SHIFTER
+//**************************************************************************
+
+//-------------------------------------------------
+// shift_mode_0 -
+//-------------------------------------------------
+
+inline pen_t st_state::shift_mode_0()
+{
+ int color = (BIT(m_shifter_rr[3], 15) << 3) | (BIT(m_shifter_rr[2], 15) << 2) | (BIT(m_shifter_rr[1], 15) << 1) | BIT(m_shifter_rr[0], 15);
+
+ m_shifter_rr[0] <<= 1;
+ m_shifter_rr[1] <<= 1;
+ m_shifter_rr[2] <<= 1;
+ m_shifter_rr[3] <<= 1;
+
+ return machine().pens[color];
+}
+
+
+//-------------------------------------------------
+// shift_mode_1 -
+//-------------------------------------------------
+
+inline pen_t st_state::shift_mode_1()
+{
+ int color = (BIT(m_shifter_rr[1], 15) << 1) | BIT(m_shifter_rr[0], 15);
+
+ m_shifter_rr[0] <<= 1;
+ m_shifter_rr[1] <<= 1;
+ m_shifter_shift++;
+
+ if (m_shifter_shift == 16)
+ {
+ m_shifter_rr[0] = m_shifter_rr[2];
+ m_shifter_rr[1] = m_shifter_rr[3];
+ m_shifter_rr[2] = m_shifter_rr[3] = 0;
+ m_shifter_shift = 0;
+ }
+
+ return machine().pens[color];
+}
+
+
+//-------------------------------------------------
+// shift_mode_2 -
+//-------------------------------------------------
+
+inline pen_t st_state::shift_mode_2()
+{
+ int color = BIT(m_shifter_rr[0], 15);
+
+ m_shifter_rr[0] <<= 1;
+ m_shifter_shift++;
+
+ switch (m_shifter_shift)
+ {
+ case 16:
+ m_shifter_rr[0] = m_shifter_rr[1];
+ m_shifter_rr[1] = m_shifter_rr[2];
+ m_shifter_rr[2] = m_shifter_rr[3];
+ m_shifter_rr[3] = 0;
+ break;
+
+ case 32:
+ m_shifter_rr[0] = m_shifter_rr[1];
+ m_shifter_rr[1] = m_shifter_rr[2];
+ m_shifter_rr[2] = 0;
+ break;
+
+ case 48:
+ m_shifter_rr[0] = m_shifter_rr[1];
+ m_shifter_rr[1] = 0;
+ m_shifter_shift = 0;
+ break;
+ }
+
+ return machine().pens[color];
+}
+
+
+//-------------------------------------------------
+// shifter_tick -
+//-------------------------------------------------
+
+void st_state::shifter_tick()
+{
+ int y = machine().primary_screen->vpos();
+ int x = machine().primary_screen->hpos();
+
+ pen_t pen;
+
+ switch (m_shifter_mode)
+ {
+ case 0:
+ pen = shift_mode_0();
+ break;
+
+ case 1:
+ pen = shift_mode_1();
+ break;
+
+ case 2:
+ pen = shift_mode_2();
+ break;
+
+ default:
+ pen = get_black_pen(machine());
+ break;
+ }
+
+ m_bitmap.pix32(y, x) = pen;
+}
+
+
+//-------------------------------------------------
+// TIMER_CALLBACK( atarist_shifter_tick )
+//-------------------------------------------------
+
+static TIMER_CALLBACK( atarist_shifter_tick )
+{
+ st_state *state = machine.driver_data<st_state>();
+
+ state->shifter_tick();
+}
+
+
+//-------------------------------------------------
+// shifter_load -
+//-------------------------------------------------
+
+inline void st_state::shifter_load()
+{
+ address_space *program = m_maincpu->memory().space(AS_PROGRAM);
+ UINT16 data = program->read_word(m_shifter_ofs);
+
+ m_shifter_ir[m_shifter_bitplane] = data;
+ m_shifter_bitplane++;
+ m_shifter_ofs += 2;
+
+ if (m_shifter_bitplane == 4)
+ {
+ m_shifter_bitplane = 0;
+
+ m_shifter_rr[0] = m_shifter_ir[0];
+ m_shifter_rr[1] = m_shifter_ir[1];
+ m_shifter_rr[2] = m_shifter_ir[2];
+ m_shifter_rr[3] = m_shifter_ir[3];
+ }
+}
+
+
+//-------------------------------------------------
+// glue_tick -
+//-------------------------------------------------
+
+void st_state::glue_tick()
+{
+ int y = machine().primary_screen->vpos();
+ int x = machine().primary_screen->hpos();
+
+ int v = (y >= m_shifter_y_start) && (y < m_shifter_y_end);
+ int h = (x >= m_shifter_x_start) && (x < m_shifter_x_end);
+
+ if(m_shifter_mode == 1) {
+ int dt = 8;
+ h = (x >= m_shifter_x_start-dt) && (x < m_shifter_x_end-dt);
+ }
+ int de = h && v;
+
+ if(!x) {
+ m_shifter_bitplane = 0;
+ m_shifter_shift = 0;
+ }
+
+ if (de != m_shifter_de)
+ {
+ m_mfp->tbi_w(de);
+ m_shifter_de = de;
+ }
+
+ if (de)
+ {
+ shifter_load();
+ }
+
+ if ((y == m_shifter_vblank_start) && (x == 0))
+ {
+ device_set_input_line(m_maincpu, M68K_IRQ_4, HOLD_LINE);
+ m_shifter_ofs = m_shifter_base;
+ }
+
+ if (x == m_shifter_hblank_start)
+ {
+ device_set_input_line(m_maincpu, M68K_IRQ_2, HOLD_LINE);
+// m_shifter_ofs += (m_shifter_lineofs * 2); // STe
+ }
+
+ pen_t pen;
+
+ switch (m_shifter_mode)
+ {
+ case 0:
+ pen = shift_mode_0();
+ m_bitmap.pix32(y, x) = pen;
+ m_bitmap.pix32(y, x+1) = pen;
+ pen = shift_mode_0();
+ m_bitmap.pix32(y, x+2) = pen;
+ m_bitmap.pix32(y, x+3) = pen;
+ pen = shift_mode_0();
+ m_bitmap.pix32(y, x+4) = pen;
+ m_bitmap.pix32(y, x+5) = pen;
+ pen = shift_mode_0();
+ m_bitmap.pix32(y, x+6) = pen;
+ m_bitmap.pix32(y, x+7) = pen;
+ break;
+
+ case 1:
+ pen = shift_mode_1();
+ m_bitmap.pix32(y, x) = pen;
+ pen = shift_mode_1();
+ m_bitmap.pix32(y, x+1) = pen;
+ pen = shift_mode_1();
+ m_bitmap.pix32(y, x+2) = pen;
+ pen = shift_mode_1();
+ m_bitmap.pix32(y, x+3) = pen;
+ pen = shift_mode_1();
+ m_bitmap.pix32(y, x+4) = pen;
+ pen = shift_mode_1();
+ m_bitmap.pix32(y, x+5) = pen;
+ pen = shift_mode_1();
+ m_bitmap.pix32(y, x+6) = pen;
+ pen = shift_mode_1();
+ m_bitmap.pix32(y, x+7) = pen;
+ break;
+
+ case 2:
+ pen = shift_mode_2();
+ break;
+
+ default:
+ pen = get_black_pen(machine());
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// TIMER_CALLBACK( atarist_glue_tick )
+//-------------------------------------------------
+
+static TIMER_CALLBACK( atarist_glue_tick )
+{
+ st_state *state = machine.driver_data<st_state>();
+
+ state->glue_tick();
+}
+
+
+//-------------------------------------------------
+// set_screen_parameters -
+//-------------------------------------------------
+
+void st_state::set_screen_parameters()
+{
+ if (m_shifter_sync & 0x02)
+ {
+ m_shifter_x_start = ATARIST_HBDEND_PAL*2;
+ m_shifter_x_end = ATARIST_HBDSTART_PAL*2;
+ m_shifter_y_start = ATARIST_VBDEND_PAL;
+ m_shifter_y_end = ATARIST_VBDSTART_PAL;
+ m_shifter_hblank_start = ATARIST_HBSTART_PAL*2;
+ m_shifter_vblank_start = ATARIST_VBSTART_PAL;
+ }
+ else
+ {
+ m_shifter_x_start = ATARIST_HBDEND_NTSC*2;
+ m_shifter_x_end = ATARIST_HBDSTART_NTSC*2;
+ m_shifter_y_start = ATARIST_VBDEND_NTSC;
+ m_shifter_y_end = ATARIST_VBDSTART_NTSC;
+ m_shifter_hblank_start = ATARIST_HBSTART_NTSC*2;
+ m_shifter_vblank_start = ATARIST_VBSTART_NTSC;
+ }
+}
+
+
+//-------------------------------------------------
+// shifter_base_r -
+//-------------------------------------------------
+
+READ8_MEMBER( st_state::shifter_base_r )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case 0x00:
+ data = (m_shifter_base >> 16) & 0x3f;
+ break;
+
+ case 0x01:
+ data = (m_shifter_base >> 8) & 0xff;
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// shifter_base_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( st_state::shifter_base_w )
+{
+ switch (offset)
+ {
+ case 0x00:
+ m_shifter_base = (m_shifter_base & 0x00ff00) | (data & 0x3f) << 16;
+ logerror("SHIFTER Video Base Address %06x\n", m_shifter_base);
+ break;
+
+ case 0x01:
+ m_shifter_base = (m_shifter_base & 0x3f0000) | (data << 8);
+ logerror("SHIFTER Video Base Address %06x\n", m_shifter_base);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// shifter_counter_r -
+//-------------------------------------------------
+
+READ8_MEMBER( st_state::shifter_counter_r )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case 0x00:
+ data = (m_shifter_ofs >> 16) & 0x3f;
+ break;
+
+ case 0x01:
+ data = (m_shifter_ofs >> 8) & 0xff;
+ break;
+
+ case 0x02:
+ data = m_shifter_ofs & 0xff;
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// shifter_sync_r -
+//-------------------------------------------------
+
+READ8_MEMBER( st_state::shifter_sync_r )
+{
+ return m_shifter_sync;
+}
+
+
+//-------------------------------------------------
+// shifter_sync_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( st_state::shifter_sync_w )
+{
+ m_shifter_sync = data;
+ logerror("SHIFTER Sync %x\n", m_shifter_sync);
+ set_screen_parameters();
+}
+
+
+//-------------------------------------------------
+// shifter_mode_r -
+//-------------------------------------------------
+
+READ8_MEMBER( st_state::shifter_mode_r )
+{
+ return m_shifter_mode;
+}
+
+
+//-------------------------------------------------
+// shifter_mode_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( st_state::shifter_mode_w )
+{
+ m_shifter_mode = data;
+ logerror("SHIFTER Mode %x\n", m_shifter_mode);
+}
+
+
+//-------------------------------------------------
+// shifter_palette_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::shifter_palette_r )
+{
+ return m_shifter_palette[offset] | 0xf888;
+}
+
+
+//-------------------------------------------------
+// shifter_palette_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::shifter_palette_w )
+{
+ m_shifter_palette[offset] = data;
+ // logerror("SHIFTER Palette[%x] = %x\n", offset, data);
+
+ palette_set_color_rgb(machine(), offset, pal3bit(data >> 8), pal3bit(data >> 4), pal3bit(data));
+}
+
+
+
+//**************************************************************************
+// STE SHIFTER
+//**************************************************************************
+
+//-------------------------------------------------
+// shifter_base_low_r -
+//-------------------------------------------------
+
+READ8_MEMBER( ste_state::shifter_base_low_r )
+{
+ return m_shifter_base & 0xfe;
+}
+
+
+//-------------------------------------------------
+// shifter_base_low_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( ste_state::shifter_base_low_w )
+{
+ m_shifter_base = (m_shifter_base & 0x3fff00) | (data & 0xfe);
+ logerror("SHIFTER Video Base Address %06x\n", m_shifter_base);
+}
+
+
+//-------------------------------------------------
+// shifter_counter_r -
+//-------------------------------------------------
+
+READ8_MEMBER( ste_state::shifter_counter_r )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case 0x00:
+ data = (m_shifter_ofs >> 16) & 0x3f;
+ break;
+
+ case 0x01:
+ data = (m_shifter_ofs >> 8) & 0xff;
+ break;
+
+ case 0x02:
+ data = m_shifter_ofs & 0xfe;
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// shifter_counter_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( ste_state::shifter_counter_w )
+{
+ switch (offset)
+ {
+ case 0x00:
+ m_shifter_ofs = (m_shifter_ofs & 0x00fffe) | (data & 0x3f) << 16;
+ logerror("SHIFTER Video Address Counter %06x\n", m_shifter_ofs);
+ break;
+
+ case 0x01:
+ m_shifter_ofs = (m_shifter_ofs & 0x3f00fe) | (data << 8);
+ logerror("SHIFTER Video Address Counter %06x\n", m_shifter_ofs);
+ break;
+
+ case 0x02:
+ m_shifter_ofs = (m_shifter_ofs & 0x3fff00) | (data & 0xfe);
+ logerror("SHIFTER Video Address Counter %06x\n", m_shifter_ofs);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// shifter_palette_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( ste_state::shifter_palette_w )
+{
+ int r = ((data >> 7) & 0x0e) | BIT(data, 11);
+ int g = ((data >> 3) & 0x0e) | BIT(data, 7);
+ int b = ((data << 1) & 0x0e) | BIT(data, 3);
+
+ m_shifter_palette[offset] = data;
+ logerror("SHIFTER palette %x = %x\n", offset, data);
+
+ palette_set_color_rgb(machine(), offset, r, g, b);
+}
+
+
+//-------------------------------------------------
+// shifter_lineofs_r -
+//-------------------------------------------------
+
+READ8_MEMBER( ste_state::shifter_lineofs_r )
+{
+ return m_shifter_lineofs;
+}
+
+
+//-------------------------------------------------
+// shifter_lineofs_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( ste_state::shifter_lineofs_w )
+{
+ m_shifter_lineofs = data;
+ logerror("SHIFTER Line Offset %x\n", m_shifter_lineofs);
+}
+
+
+//-------------------------------------------------
+// shifter_pixelofs_r -
+//-------------------------------------------------
+
+READ8_MEMBER( ste_state::shifter_pixelofs_r )
+{
+ return m_shifter_pixelofs;
+}
+
+
+//-------------------------------------------------
+// shifter_pixelofs_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( ste_state::shifter_pixelofs_w )
+{
+ m_shifter_pixelofs = data & 0x0f;
+ logerror("SHIFTER Pixel Offset %x\n", m_shifter_pixelofs);
+}
+
+
+
+//**************************************************************************
+// BLITTER
+//**************************************************************************
+
+//-------------------------------------------------
+// blitter_source -
+//-------------------------------------------------
+
+void st_state::blitter_source()
+{
+ address_space *program = m_maincpu->memory().space(AS_PROGRAM);
+ UINT16 data = program->read_word(m_blitter_src);
+
+ if (m_blitter_src_inc_x < 0)
+ {
+ m_blitter_srcbuf = (data << 16) | (m_blitter_srcbuf >> 16);
+ }
+ else
+ {
+ m_blitter_srcbuf = (m_blitter_srcbuf << 16) | data;
+ }
+}
+
+
+//-------------------------------------------------
+// blitter_hop -
+//-------------------------------------------------
+
+UINT16 st_state::blitter_hop()
+{
+ UINT16 source = m_blitter_srcbuf >> (m_blitter_skew & 0x0f);
+ UINT16 halftone = m_blitter_halftone[m_blitter_ctrl & 0x0f];
+
+ if (m_blitter_ctrl & ATARIST_BLITTER_CTRL_SMUDGE)
+ {
+ halftone = m_blitter_halftone[source & 0x0f];
+ }
+
+ switch (m_blitter_hop)
+ {
+ case 0:
+ return 0xffff;
+ case 1:
+ return halftone;
+ case 2:
+ return source;
+ case 3:
+ return source & halftone;
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// blitter_op -
+//-------------------------------------------------
+
+void st_state::blitter_op(UINT16 s, UINT32 dstaddr, UINT16 mask)
+{
+ address_space *program = m_maincpu->memory().space(AS_PROGRAM);
+
+ UINT16 d = program->read_word(dstaddr);
+ UINT16 result = 0;
+
+ if (m_blitter_op & 0x08) result = (~s & ~d);
+ if (m_blitter_op & 0x04) result |= (~s & d);
+ if (m_blitter_op & 0x02) result |= (s & ~d);
+ if (m_blitter_op & 0x01) result |= (s & d);
+
+ program->write_word(dstaddr, result);
+}
+
+
+//-------------------------------------------------
+// blitter_tick -
+//-------------------------------------------------
+
+void st_state::blitter_tick()
+{
+ do
+ {
+ if (m_blitter_skew & ATARIST_BLITTER_SKEW_FXSR)
+ {
+ blitter_source();
+ m_blitter_src += m_blitter_src_inc_x;
+ }
+
+ blitter_source();
+ blitter_op(blitter_hop(), m_blitter_dst, m_blitter_endmask1);
+ m_blitter_xcount--;
+
+ while (m_blitter_xcount > 0)
+ {
+ m_blitter_src += m_blitter_src_inc_x;
+ m_blitter_dst += m_blitter_dst_inc_x;
+
+ if (m_blitter_xcount == 1)
+ {
+ if (!(m_blitter_skew & ATARIST_BLITTER_SKEW_NFSR))
+ {
+ blitter_source();
+ }
+
+ blitter_op(blitter_hop(), m_blitter_dst, m_blitter_endmask3);
+ }
+ else
+ {
+ blitter_source();
+ blitter_op(blitter_hop(), m_blitter_dst, m_blitter_endmask2);
+ }
+
+ m_blitter_xcount--;
+ }
+
+ m_blitter_src += m_blitter_src_inc_y;
+ m_blitter_dst += m_blitter_dst_inc_y;
+
+ if (m_blitter_dst_inc_y < 0)
+ {
+ m_blitter_ctrl = (m_blitter_ctrl & 0xf0) | (((m_blitter_ctrl & 0x0f) - 1) & 0x0f);
+ }
+ else
+ {
+ m_blitter_ctrl = (m_blitter_ctrl & 0xf0) | (((m_blitter_ctrl & 0x0f) + 1) & 0x0f);
+ }
+
+ m_blitter_xcount = m_blitter_xcountl;
+ m_blitter_ycount--;
+ }
+ while (m_blitter_ycount > 0);
+
+ m_blitter_ctrl &= 0x7f;
+
+ m_blitter_done = 0;
+ m_mfp->i3_w(m_blitter_done);
+}
+
+
+//-------------------------------------------------
+// TIMER_CALLBACK( atarist_blitter_tick )
+//-------------------------------------------------
+
+static TIMER_CALLBACK( atarist_blitter_tick )
+{
+ st_state *state = machine.driver_data<st_state>();
+
+ state->blitter_tick();
+}
+
+
+//-------------------------------------------------
+// blitter_halftone_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_halftone_r )
+{
+ return m_blitter_halftone[offset];
+}
+
+
+//-------------------------------------------------
+// blitter_src_inc_x_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_src_inc_x_r )
+{
+ return m_blitter_src_inc_x;
+}
+
+
+//-------------------------------------------------
+// blitter_src_inc_y_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_src_inc_y_r )
+{
+ return m_blitter_src_inc_y;
+}
+
+
+//-------------------------------------------------
+// blitter_src_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_src_r )
+{
+ switch (offset)
+ {
+ case 0:
+ return (m_blitter_src >> 16) & 0xff;
+ case 1:
+ return m_blitter_src & 0xfffe;
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// blitter_end_mask_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_end_mask_r )
+{
+ switch (offset)
+ {
+ case 0:
+ return m_blitter_endmask1;
+ case 1:
+ return m_blitter_endmask2;
+ case 2:
+ return m_blitter_endmask3;
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// blitter_dst_inc_x_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_dst_inc_x_r )
+{
+ return m_blitter_dst_inc_x;
+}
+
+
+//-------------------------------------------------
+// blitter_dst_inc_y_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_dst_inc_y_r )
+{
+ return m_blitter_dst_inc_y;
+}
+
+
+//-------------------------------------------------
+// blitter_dst_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_dst_r )
+{
+ switch (offset)
+ {
+ case 0:
+ return (m_blitter_dst >> 16) & 0xff;
+ case 1:
+ return m_blitter_dst & 0xfffe;
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// blitter_count_x_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_count_x_r )
+{
+ return m_blitter_xcount;
+}
+
+
+//-------------------------------------------------
+// blitter_count_y_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_count_y_r )
+{
+ return m_blitter_ycount;
+}
+
+
+//-------------------------------------------------
+// blitter_op_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_op_r )
+{
+ if (ACCESSING_BITS_0_7)
+ {
+ return m_blitter_hop;
+ }
+ else
+ {
+ return m_blitter_op;
+ }
+}
+
+
+//-------------------------------------------------
+// blitter_ctrl_r -
+//-------------------------------------------------
+
+READ16_MEMBER( st_state::blitter_ctrl_r )
+{
+ if (ACCESSING_BITS_0_7)
+ {
+ return m_blitter_ctrl;
+ }
+ else
+ {
+ return m_blitter_skew;
+ }
+}
+
+
+//-------------------------------------------------
+// blitter_halftone_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_halftone_w )
+{
+ m_blitter_halftone[offset] = data;
+}
+
+
+//-------------------------------------------------
+// blitter_src_inc_x_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_src_inc_x_w )
+{
+ m_blitter_src_inc_x = data & 0xfffe;
+}
+
+
+//-------------------------------------------------
+// blitter_src_inc_y_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_src_inc_y_w )
+{
+ m_blitter_src_inc_y = data & 0xfffe;
+}
+
+
+//-------------------------------------------------
+// blitter_src_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_src_w )
+{
+ switch (offset)
+ {
+ case 0:
+ m_blitter_src = (data & 0xff) | (m_blitter_src & 0xfffe);
+ break;
+
+ case 1:
+ m_blitter_src = (m_blitter_src & 0xff0000) | (data & 0xfffe);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// blitter_end_mask_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_end_mask_w )
+{
+ switch (offset)
+ {
+ case 0:
+ m_blitter_endmask1 = data;
+ break;
+
+ case 1:
+ m_blitter_endmask2 = data;
+ break;
+
+ case 2:
+ m_blitter_endmask3 = data;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// blitter_dst_inc_x_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_dst_inc_x_w )
+{
+ m_blitter_dst_inc_x = data & 0xfffe;
+}
+
+
+//-------------------------------------------------
+// blitter_dst_inc_y_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_dst_inc_y_w )
+{
+ m_blitter_dst_inc_y = data & 0xfffe;
+}
+
+
+//-------------------------------------------------
+// blitter_dst_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_dst_w )
+{
+ switch (offset)
+ {
+ case 0:
+ m_blitter_dst = (data & 0xff) | (m_blitter_dst & 0xfffe);
+ break;
+
+ case 1:
+ m_blitter_dst = (m_blitter_dst & 0xff0000) | (data & 0xfffe);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// blitter_count_x_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_count_x_w )
+{
+ m_blitter_xcount = data;
+}
+
+
+//-------------------------------------------------
+// blitter_count_y_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_count_y_w )
+{
+ m_blitter_ycount = data;
+}
+
+
+//-------------------------------------------------
+// blitter_op_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_op_w )
+{
+ if (ACCESSING_BITS_0_7)
+ {
+ m_blitter_hop = (data >> 8) & 0x03;
+ }
+ else
+ {
+ m_blitter_op = data & 0x0f;
+ }
+}
+
+
+//-------------------------------------------------
+// blitter_ctrl_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( st_state::blitter_ctrl_w )
+{
+ if (ACCESSING_BITS_0_7)
+ {
+ m_blitter_ctrl = (data >> 8) & 0xef;
+
+ if (!(m_blitter_ctrl & ATARIST_BLITTER_CTRL_BUSY))
+ {
+ if ((data >> 8) & ATARIST_BLITTER_CTRL_BUSY)
+ {
+ m_blitter_done = 1;
+ m_mfp->i3_w(m_blitter_done);
+
+ int nops = BLITTER_NOPS[m_blitter_op][m_blitter_hop]; // each NOP takes 4 cycles
+ machine().scheduler().timer_set(attotime::from_hz((Y2/4)/(4*nops)), FUNC(atarist_blitter_tick));
+ }
+ }
+ }
+ else
+ {
+ m_blitter_skew = data & 0xcf;
+ }
+}
+
+
+
+//**************************************************************************
+// VIDEO
+//**************************************************************************
+
+//-------------------------------------------------
+// VIDEO_START( st )
+//-------------------------------------------------
+
+void st_state::video_start()
+{
+ m_shifter_timer = machine().scheduler().timer_alloc(FUNC(atarist_shifter_tick));
+ m_glue_timer = machine().scheduler().timer_alloc(FUNC(atarist_glue_tick));
+
+// m_shifter_timer->adjust(machine().primary_screen->time_until_pos(0), 0, attotime::from_hz(Y2/4)); // 125 ns
+ m_glue_timer->adjust(machine().primary_screen->time_until_pos(0), 0, attotime::from_hz(Y2/16)); // 500 ns
+
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+
+ /* register for state saving */
+ save_item(NAME(m_shifter_base));
+ save_item(NAME(m_shifter_ofs));
+ save_item(NAME(m_shifter_sync));
+ save_item(NAME(m_shifter_mode));
+ save_item(NAME(m_shifter_palette));
+ save_item(NAME(m_shifter_rr));
+ save_item(NAME(m_shifter_ir));
+ save_item(NAME(m_shifter_bitplane));
+ save_item(NAME(m_shifter_shift));
+ save_item(NAME(m_shifter_h));
+ save_item(NAME(m_shifter_v));
+ save_item(NAME(m_shifter_de));
+
+ save_item(NAME(m_blitter_halftone));
+ save_item(NAME(m_blitter_src_inc_x));
+ save_item(NAME(m_blitter_src_inc_y));
+ save_item(NAME(m_blitter_dst_inc_x));
+ save_item(NAME(m_blitter_dst_inc_y));
+ save_item(NAME(m_blitter_src));
+ save_item(NAME(m_blitter_dst));
+ save_item(NAME(m_blitter_endmask1));
+ save_item(NAME(m_blitter_endmask2));
+ save_item(NAME(m_blitter_endmask3));
+ save_item(NAME(m_blitter_xcount));
+ save_item(NAME(m_blitter_ycount));
+ save_item(NAME(m_blitter_xcountl));
+ save_item(NAME(m_blitter_hop));
+ save_item(NAME(m_blitter_op));
+ save_item(NAME(m_blitter_ctrl));
+ save_item(NAME(m_blitter_skew));
+
+ set_screen_parameters();
+}
+
+
+//-------------------------------------------------
+// VIDEO_START( ste )
+//-------------------------------------------------
+
+void ste_state::video_start()
+{
+ st_state::video_start();
+
+ // register for state saving
+ save_item(NAME(m_shifter_lineofs));
+ save_item(NAME(m_shifter_pixelofs));
+}
+
+//-------------------------------------------------
+// VIDEO_START( stbook )
+//-------------------------------------------------
+
+void stbook_state::video_start()
+{
+}
+
+
+UINT32 st_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
diff --git a/src/mess/video/atarist.h b/src/mess/video/atarist.h
new file mode 100644
index 00000000000..f2d09879c2e
--- /dev/null
+++ b/src/mess/video/atarist.h
@@ -0,0 +1,39 @@
+#ifndef _VIDEO_ATARIST_H_
+#define _VIDEO_ATARIST_H_
+
+// 32028400 also exists
+#define Y2 32084988.0
+#define Y2_NTSC 32042400.0
+
+#define ATARIST_HBSTART_PAL 128*4
+#define ATARIST_HBEND_PAL 0
+#define ATARIST_HBSTART_NTSC 127*4
+#define ATARIST_HBEND_NTSC 0
+#define ATARIST_HTOT_PAL 129*4
+#define ATARIST_HTOT_NTSC 128*4
+
+#define ATARIST_HBDEND_PAL 14*4
+#define ATARIST_HBDSTART_PAL 94*4
+#define ATARIST_HBDEND_NTSC 13*4
+#define ATARIST_HBDSTART_NTSC 93*4
+
+#define ATARIST_VBEND_PAL 0
+#define ATARIST_VBEND_NTSC 0
+#define ATARIST_VBSTART_PAL 312
+#define ATARIST_VBSTART_NTSC 262
+#define ATARIST_VTOT_PAL 313
+#define ATARIST_VTOT_NTSC 263
+
+#define ATARIST_VBDEND_PAL 63
+#define ATARIST_VBDSTART_PAL 263
+#define ATARIST_VBDEND_NTSC 34
+#define ATARIST_VBDSTART_NTSC 234
+
+#define ATARIST_BLITTER_SKEW_NFSR 0x40
+#define ATARIST_BLITTER_SKEW_FXSR 0x80
+
+#define ATARIST_BLITTER_CTRL_SMUDGE 0x20
+#define ATARIST_BLITTER_CTRL_HOG 0x40
+#define ATARIST_BLITTER_CTRL_BUSY 0x80
+
+#endif
diff --git a/src/mess/video/avigo.c b/src/mess/video/avigo.c
new file mode 100644
index 00000000000..b2dbb7c0016
--- /dev/null
+++ b/src/mess/video/avigo.c
@@ -0,0 +1,117 @@
+/***************************************************************************
+
+ avigo.c
+
+ Functions to emulate the video hardware of the TI Avigo 10 PDA
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/avigo.h"
+
+/***************************************************************************
+ Start the video hardware emulation.
+***************************************************************************/
+
+/* mem size = 0x017c0 */
+
+
+/* current column to read/write */
+
+#define AVIGO_VIDEO_DEBUG 0
+#define LOG(x) do { if (AVIGO_VIDEO_DEBUG) logerror x; } while (0)
+
+
+READ8_MEMBER(avigo_state::vid_memory_r)
+{
+ if (!offset)
+ return m_screen_column;
+
+ if ((offset<0x0100) || (offset>=0x01f0) || (m_screen_column >= (AVIGO_SCREEN_WIDTH>>3)))
+ {
+ LOG(("vid mem read: %04x\n", offset));
+ return 0;
+ }
+
+ /* 0x0100-0x01f0 contains data for selected column */
+ return m_video_memory[m_screen_column + ((offset&0xff)*(AVIGO_SCREEN_WIDTH>>3))];
+}
+
+WRITE8_MEMBER(avigo_state::vid_memory_w)
+{
+ if (!offset)
+ {
+ /* select column to read/write */
+ m_screen_column = data;
+
+ LOG(("vid mem column write: %02x\n",data));
+
+ if (data>=(AVIGO_SCREEN_WIDTH>>3))
+ {
+ LOG(("error: vid mem column write: %02x\n",data));
+ }
+ return;
+ }
+
+ if ((offset<0x0100) || (offset>=0x01f0) || (m_screen_column >= (AVIGO_SCREEN_WIDTH>>3)))
+ {
+ LOG(("vid mem write: %04x %02x\n", offset, data));
+ return;
+ }
+
+ /* 0x0100-0x01f0 contains data for selected column */
+ m_video_memory[m_screen_column + ((offset&0xff)*(AVIGO_SCREEN_WIDTH>>3))] = data;
+}
+
+void avigo_state::video_start()
+{
+ /* current selected column to read/write */
+ m_screen_column = 0;
+
+ /* allocate video memory */
+ m_video_memory = machine().memory().region_alloc( "videoram", (AVIGO_SCREEN_WIDTH>>3) * AVIGO_SCREEN_HEIGHT + 1, 1, ENDIANNESS_LITTLE )->base();
+ memset(m_video_memory, 0, (AVIGO_SCREEN_WIDTH>>3) * AVIGO_SCREEN_HEIGHT + 1);
+
+ save_pointer(NAME(m_video_memory), (AVIGO_SCREEN_WIDTH>>3) * AVIGO_SCREEN_HEIGHT + 1);
+}
+
+/* Initialise the palette */
+PALETTE_INIT( avigo )
+{
+ palette_set_color(machine,0,MAKE_RGB(0xff,0xff,0xff)); /* white */
+ palette_set_color(machine,1,MAKE_RGB(0x00,0x00,0x00)); /* black */
+}
+
+UINT32 avigo_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ int y;
+ int b;
+ int x;
+
+ /* draw avigo display */
+ for (y=0; y<AVIGO_SCREEN_HEIGHT; y++)
+ {
+ int by;
+ UINT8 *line_ptr = m_video_memory + (y*(AVIGO_SCREEN_WIDTH>>3));
+
+ x = 0;
+ for (by=((AVIGO_SCREEN_WIDTH>>3)-1); by>=0; by--)
+ {
+ int px;
+ UINT8 byte = line_ptr[0];
+
+ px = x;
+ for (b=7; b>=0; b--)
+ {
+ bitmap.pix16(y, px) = ((byte>>7) & 0x01);
+ px++;
+ byte = byte<<1;
+ }
+
+ x = px;
+ line_ptr = line_ptr+1;
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/b2m.c b/src/mess/video/b2m.c
new file mode 100644
index 00000000000..0eac9177bd4
--- /dev/null
+++ b/src/mess/video/b2m.c
@@ -0,0 +1,59 @@
+/***************************************************************************
+
+ Bashkiria-2M video driver by Miodrag Milanovic
+
+ 28/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/b2m.h"
+#include "machine/ram.h"
+
+VIDEO_START( b2m )
+{
+}
+
+SCREEN_UPDATE_IND16( b2m )
+{
+ b2m_state *state = screen.machine().driver_data<b2m_state>();
+ UINT8 code1;
+ UINT8 code2;
+ UINT8 col;
+ int y, x, b;
+ UINT8 *ram = screen.machine().device<ram_device>(RAM_TAG)->pointer();
+
+ for (x = 0; x < 48; x++)
+ {
+ for (y = 0; y < 256; y++)
+ {
+ if (state->m_b2m_video_page==0) {
+ code1 = ram[0x11000 + x*256 + ((y + state->m_b2m_video_scroll) & 0xff)];
+ code2 = ram[0x15000 + x*256 + ((y + state->m_b2m_video_scroll) & 0xff)];
+ } else {
+ code1 = ram[0x19000 + x*256 + ((y + state->m_b2m_video_scroll) & 0xff)];
+ code2 = ram[0x1d000 + x*256 + ((y + state->m_b2m_video_scroll) & 0xff)];
+ }
+ for (b = 7; b >= 0; b--)
+ {
+ col = (((code2 >> b) & 0x01)<<1) + ((code1 >> b) & 0x01);
+ bitmap.pix16(y, x*8+b) = col;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const rgb_t b2m_palette[4] = {
+ MAKE_RGB(0x00, 0x00, 0x00), // 0
+ MAKE_RGB(0x00, 0x00, 0x00), // 1
+ MAKE_RGB(0x00, 0x00, 0x00), // 2
+ MAKE_RGB(0x00, 0x00, 0x00), // 3
+};
+
+PALETTE_INIT( b2m )
+{
+ palette_set_colors(machine, 0, b2m_palette, ARRAY_LENGTH(b2m_palette));
+}
diff --git a/src/mess/video/bbc.c b/src/mess/video/bbc.c
new file mode 100644
index 00000000000..e113a04c4be
--- /dev/null
+++ b/src/mess/video/bbc.c
@@ -0,0 +1,694 @@
+/******************************************************************************
+ BBC Model B
+
+ MESS Driver By:
+
+ Gordon Jefferyes
+ mess_bbc@romvault.com
+
+ This is the first go around at converting the BBC code over to using
+ mames built in mc6845, there are a number of features now incorrect
+ or missing in this build:
+
+ Cursors are missing.
+ Mode 7 is shifted to the right by a couple of character.
+ BBC split modes no longer work (Like is used in Elite.)
+
+******************************************************************************/
+
+#include "emu.h"
+#include "includes/bbc.h"
+#include "saa505x.h"
+#include "video/mc6845.h"
+
+/************************************************************************
+ * C0 and C1 along with MA12 output from the 6845 drive 4 NAND gates in ICs 27,36 and 40
+ * the outputs from these NAND gates (B1 to B4) along with MA8 to MA11 from the 6845 (A1 to B4) are added together
+ * in IC39 74LS283 4 bit adder to form (S1 to S4) the logic is used to loop the screen memory for hardware scrolling.
+ * when MA13 from the 6845 is low the latches IC8 and IC9 are enabled
+ * they control the memory addressing for the Hi-Res modes.
+ * when MA13 from the 6845 is high the latches IC10 and IC11 are enabled
+ * they control the memory addressing for the Teletext mode.
+ * IC 8 or IC10 drives the row select in the memory (the lower 7 bits in the memory address) and
+ * IC 9 or IC11 drives the column select in the memory (the next 7 bits in the memory address) this
+ * gives control of the bottom 14 bits of the memory, in a 32K model B 15 bits are needed to access
+ * all the RAM, so S4 for the adder drives the CAS0 and CAS1 to access the top bit, in a 16K model A
+ * the output of S4 is linked out to a 0v supply by link S25 to just access the 16K memory area.
+ ************************************************************************/
+
+unsigned int calculate_video_address(bbc_state *state,int ma,int ra)
+{
+ // ma = output from IC2 6845 MA address
+
+ int c0=state->m_b4_video0; // output from IC32 74LS259 bits 4 and 5
+ int c1=state->m_b5_video1;
+
+ /* the 4 bit input port b on IC39 are produced by 4 NAND gates.
+ these NAND gates take their
+ inputs from c0 and c1 (from IC32) and ma12 (from the 6845) */
+
+ /* get bit m12 from the 6845 */
+ int ma12=(ma>>12)&1;
+
+ // 4 bit input B on IC39 74LS283 (4 bit adder)
+ /* 3 input NAND part of IC 36 */
+ int b1=(~(c1 & c0 & ma12)) & 1;
+ /* 2 input NAND part of IC40 (b3 is calculated before b2 and b4 because b3 feed back into b2 and b4) */
+ int b3=(~(c0 & ma12)) & 1;
+ /* 3 input NAND part of IC 36 */
+ int b2=(~(c1 & b3 & ma12)) & 1;
+ /* 2 input NAND part of IC 27 */
+ int b4=(~(b3 & ma12)) & 1;
+
+ /* inputs port b to IC39 are taken from the NAND gates b1 to b4 */
+ int b=(b1<<0)|(b2<<1)|(b3<<2)|(b4<<3);
+
+ /* inputs port a to IC39 are MA8 to MA11 from the 6845 */
+ int a=(ma>>8)&0xf;
+
+ /* IC39 performs the 4 bit add with the carry input set high */
+ int s=(a+b+1)&0xf;
+
+ /* if MA13 (TTXVDU) is low then IC8 and IC9 are used to calculate
+ the memory location required for the hi res video.
+ if MA13 is hight then IC10 and IC11 are used to calculate the memory location for the teletext chip*/
+ unsigned int m;
+ if ((ma>>13)&1)
+ {
+ // IC 10 and IC 11
+ m=((ma&0x3ff)|0x3c00)|((s&0x8)<<11);
+ } else {
+ // IC 8 and IC 9
+ m=((ma&0xff)<<3)|(s<<11)|(ra&0x7);
+ }
+ if (state->m_memorySize==16)
+ return m & 0x3fff;
+
+ return m;
+}
+
+/************************************************************************
+ * VideoULA
+ ************************************************************************/
+
+static const int pixels_per_byte_set[8]={ 2,4,8,16,1,2,4,8 };
+
+static const int width_of_cursor_set[8]={ 0,0,1,2,1,0,2,4 };
+
+/* this is a quick lookup array that puts bits 0,2,4,6 into bits 0,1,2,3
+ this is used by the pallette lookup in the video ULA */
+static void set_pixel_lookup(bbc_state *state)
+{
+ int i;
+ for (i=0; i<256; i++)
+ {
+ state->m_pixel_bits[i] = (((i>>7)&1)<<3) | (((i>>5)&1)<<2) | (((i>>3)&1)<<1) | (((i>>1)&1)<<0);
+ }
+}
+
+
+WRITE8_MEMBER(bbc_state::bbc_videoULA_w)
+{
+
+ // Make sure vpos is never <0 2008-10-11 PHS.
+ int vpos=machine().primary_screen->vpos();
+ if(vpos==0)
+ machine().primary_screen->update_partial(vpos);
+ else
+ machine().primary_screen->update_partial(vpos -1 );
+
+ logerror("setting videoULA %.4x to:%.4x at :%d \n",data,offset,machine().primary_screen->vpos() );
+
+
+ switch (offset&0x01)
+ {
+ // Set the control register in the Video ULA
+ case 0:
+ {
+ m_videoULA_Reg=data;
+ m_videoULA_master_cursor_size= (m_videoULA_Reg>>7)&0x01;
+ m_videoULA_width_of_cursor= (m_videoULA_Reg>>5)&0x03;
+ m_videoULA_6845_clock_rate= (m_videoULA_Reg>>4)&0x01;
+ m_videoULA_characters_per_line= (m_videoULA_Reg>>2)&0x03;
+ m_videoULA_teletext_normal_select=(m_videoULA_Reg>>1)&0x01;
+ m_videoULA_flash_colour_select= m_videoULA_Reg &0x01;
+
+ m_videoULA_pallet_lookup=m_videoULA_flash_colour_select?m_videoULA_pallet0:m_videoULA_pallet1;
+
+ m_emulation_cursor_size=width_of_cursor_set[m_videoULA_width_of_cursor|(m_videoULA_master_cursor_size<<2)];
+
+ // this is the number of BBC pixels held in each byte
+ if (m_videoULA_teletext_normal_select)
+ {
+ m_pixels_per_byte=6;
+ } else {
+ m_pixels_per_byte=pixels_per_byte_set[m_videoULA_characters_per_line|(m_videoULA_6845_clock_rate<<2)];
+ }
+ mc6845_device *mc6845 = machine().device<mc6845_device>("mc6845");
+ mc6845->set_hpixels_per_column(m_pixels_per_byte);
+ if (m_videoULA_6845_clock_rate)
+ mc6845->set_clock(2000000);
+ else
+ mc6845->set_clock(1000000);
+ }
+ break;
+ // Set a pallet register in the Video ULA
+ case 1:
+ int tpal=(data>>4)&0x0f;
+ int tcol=data&0x0f;
+ m_videoULA_pallet0[tpal]=tcol;
+ m_videoULA_pallet1[tpal]=tcol<8?tcol:tcol^7;
+ break;
+ }
+}
+
+// VideoULA Internal Cursor controls
+
+/*
+static void set_cursor(bbc_state *state)
+{
+ state->m_cursor_state=state->m_VideoULA_CR?0:7;
+}
+
+static void BBC_Clock_CR(bbc_state *state)
+{
+ if (state->m_VideoULA_CR)
+ {
+ state->m_VideoULA_CR_counter-=1;
+ if (state->m_VideoULA_CR_counter<=0) {
+ state->m_VideoULA_CR=0;
+ set_cursor(state);
+ }
+ }
+}
+*/
+/************************************************************************
+ * BBC circuits controlled by 6845 Outputs
+ ************************************************************************/
+
+int returned_pixel_count;
+int returned_pixels[6];
+
+static MC6845_UPDATE_ROW( vid_update_row )
+{
+
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ logerror("MC6845_UPDATE_ROW: ma=%d, ra=%d, y=%d, x_count=%d\n",ma,ra,y,x_count);
+
+ if (state->m_videoULA_teletext_normal_select)
+ {
+
+ teletext_LOSE_w(state->m_saa505x, 0,0);
+ teletext_LOSE_w(state->m_saa505x, 0,1);
+
+ for(int x_pos=0; x_pos<x_count; x_pos++)
+ {
+ //Teletext Latch bits 0 to 5 go to bits 0 to 5 on the Teletext chip
+ //Teletext Latch bit 6 is only passed onto bits 6 on the Teletext chip if DE is true
+ //Teletext Latch bit 7 goes to LOSE on the Teletext chip
+
+ returned_pixel_count=0;
+
+
+ teletext_F1(state->m_saa505x);
+
+ teletext_data_w(state->m_saa505x, 0, (state->m_Teletext_Latch&0x3f)|(state->m_Teletext_Latch&0x40));
+
+ if (((ma>>13)&1)==0)
+ {
+ state->m_Teletext_Latch=0;
+ } else {
+ state->m_Teletext_Latch=(state->m_BBC_Video_RAM[calculate_video_address(state,ma+x_pos,ra)]&0x7f);
+ }
+ for(int pixelno=0;pixelno<6;pixelno++)
+ {
+ int col=returned_pixels[pixelno];
+
+ bitmap.pix32(y, (x_pos*state->m_pixels_per_byte)+pixelno)=palette[col];
+ }
+
+
+ }
+ }
+ else
+ {
+ // this is IC38 and IC41 takes 6845 DisplayEnabled and 6845 RA3
+ int DE= !(ra>=8);
+
+ if (DE)
+ {
+ for(int x_pos=0; x_pos<x_count; x_pos++)
+ {
+ int vmem=calculate_video_address(state,ma+x_pos,ra);
+ unsigned char i=state->m_BBC_Video_RAM[vmem];
+
+ for(int pixelno=0;pixelno<state->m_pixels_per_byte;pixelno++)
+ {
+ int col=state->m_videoULA_pallet_lookup[state->m_pixel_bits[i]];
+ bitmap.pix32(y, (x_pos*state->m_pixels_per_byte)+pixelno)=palette[col];
+ i=(i<<1)|1;
+ }
+ }
+ }
+ else
+ {
+ for(int x_pos=0; x_pos<x_count; x_pos++)
+ {
+ for(int pixelno=0;pixelno<state->m_pixels_per_byte;pixelno++)
+ {
+ bitmap.pix32(y, (x_pos*state->m_pixels_per_byte)+pixelno)=palette[7];
+ }
+ }
+ }
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( bbc_vsync )
+{
+ bbc_state *bstate = device->machine().driver_data<bbc_state>();
+ teletext_DEW(bstate->m_saa505x);
+}
+
+
+const mc6845_interface bbc_mc6845_intf =
+{
+ "screen", /* screen number */
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ vid_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_NULL, /* on_hsync_changed */
+ DEVCB_LINE(bbc_vsync), /* on_vsync_changed */
+ NULL
+};
+
+
+void bbc_draw_RGB_in(device_t *device, int offset,int data)
+{
+ if (returned_pixel_count<6)
+ returned_pixels[returned_pixel_count++]=7-data;
+
+}
+
+
+
+
+/************************************************************************
+ * memory interface to BBC's 6845
+ ************************************************************************/
+
+WRITE8_MEMBER(bbc_state::bbc_6845_w)
+{
+ mc6845_device *mc6845 = machine().device<mc6845_device>("mc6845");
+ switch(offset & 1)
+ {
+ case 0 :
+ mc6845->address_w(space,0,data);
+ break;
+ case 1 :
+ mc6845->register_w(space,0,data);
+ break;
+ }
+ return;
+}
+
+READ8_MEMBER(bbc_state::bbc_6845_r)
+{
+
+ mc6845_device *mc6845 = machine().device<mc6845_device>("mc6845");
+
+ switch (offset&1)
+ {
+ case 0: return mc6845->status_r(space,0); break;
+ case 1: return mc6845->register_r(space,0); break;
+ }
+ return 0;
+}
+
+
+
+
+
+/**** BBC B+ Shadow Ram change ****/
+
+void bbcbp_setvideoshadow(running_machine &machine, int vdusel)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ if (vdusel)
+ {
+ state->m_BBC_Video_RAM= state->memregion("maincpu")->base()+0x8000;
+ } else {
+ state->m_BBC_Video_RAM= machine.root_device().memregion("maincpu")->base();
+ }
+}
+
+/************************************************************************
+ * bbc_vh_start
+ * Initialize the BBC video emulation
+ ************************************************************************/
+
+static void common_init(running_machine &machine, int memorySize)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ state->m_emulation_cursor_size = 1;
+
+ state->m_VideoULA_CR = 7;
+ state->m_VideoULA_CR_counter = 0;
+
+ set_pixel_lookup(state);
+ state->m_saa505x = machine.device("saa505x");
+
+ state->m_BBC_Video_RAM = state->memregion("maincpu")->base();
+ state->m_memorySize=memorySize;
+
+}
+
+VIDEO_START( bbca )
+{
+ common_init(machine,16);
+}
+
+VIDEO_START( bbcb )
+{
+ common_init(machine,32);
+}
+
+VIDEO_START( bbcbp )
+{
+ common_init(machine,32);
+}
+
+VIDEO_START( bbcm )
+{
+ common_init(machine,32);
+}
+
+
+/*
+
+Old removed BBC mc6845 video code.
+This has now all been replaced by MAMEs mc6845 code.
+
+
+
+static void BBC_draw_hi_res(running_machine &machine);
+static void BBC_draw_teletext(running_machine &machine);
+
+
+
+
+static void BBC_draw_teletext(running_machine &machine)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+
+ //Teletext Latch bits 0 to 5 go to bits 0 to 5 on the Teletext chip
+ //Teletext Latch bit 6 is only passed onto bits 6 on the Teletext chip if DE is true
+ //Teletext Latch bit 7 goes to LOSE on the Teletext chip
+
+ teletext_LOSE_w(state->m_saa505x, 0, (state->m_Teletext_Latch>>7)&1);
+
+ teletext_F1(state->m_saa505x);
+
+ teletext_data_w(state->m_saa505x, 0, (state->m_Teletext_Latch&0x3f)|((state->m_Teletext_Latch&0x40)|(m6845_display_enabled_r(0)?0:0x40)));
+
+ int meml=m6845_memory_address_r(0);
+
+ if (((meml>>13)&1)==0)
+ {
+ state->m_Teletext_Latch=0;
+ } else {
+ state->m_Teletext_Latch=(state->m_BBC_Video_RAM[calculate_video_address(state,meml)]&0x7f)|(m6845_display_enabled_r(0)?0x80:0);
+ }
+
+}
+
+
+
+
+
+// This is the actual output of the Video ULA this fuction does all the output to the screen in the BBC emulator
+
+static void BBC_ula_drawpixel(bbc_state *state, int col, int number_of_pixels)
+{
+ int pixel_count;
+ int pixel_temp;
+ if ((state->m_BBC_display>=state->m_BBC_display_left) && ((state->m_BBC_display+number_of_pixels)<state->m_BBC_display_right))
+ {
+
+ pixel_temp=col^state->m_cursor_state;
+ for(pixel_count=0;pixel_count<number_of_pixels;pixel_count++)
+ {
+ *(state->m_BBC_display++) = pixel_temp;
+ }
+ } else {
+ state->m_BBC_display += number_of_pixels;
+ }
+}
+
+
+// the Video ULA hi-res shift registers, pallette lookup and display enabled circuits
+
+
+
+
+
+static const struct m6845_interface BBC6845 =
+{
+ 0,// Memory Address register
+ 0,// Row Address register
+ BBC_Set_HSync,// Horizontal status
+ BBC_Set_VSync,// Vertical status
+ 0,// Display Enabled status
+ 0,// Cursor status
+ BBC_Set_CRE, // Cursor status Emulation
+};
+
+
+
+static void BBC_draw_hi_res(running_machine &machine)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ int meml;
+ unsigned char i=0;
+ int sc1;
+
+ // this is IC38 and IC41 takes 6845 DisplayEnabled and 6845 RA3
+ int DE=m6845_display_enabled_r(0) && (!(m6845_row_address_r(0)&8));
+
+ if (DE)
+ {
+ // read the memory location for the next screen location.
+ meml=calculate_video_address(state,m6845_memory_address_r(0));
+
+ i=state->m_BBC_Video_RAM[meml];
+
+ for(sc1=0;sc1<state->m_pixels_per_byte;sc1++)
+ {
+ BBC_ula_drawpixel(state, state->m_videoULA_pallet_lookup[state->m_pixel_bits[i]], state->m_emulation_pixels_per_real_pixel);
+ i=(i<<1)|1;
+ }
+
+ } else {
+ // if the display is not enable, just draw a blank area.
+ BBC_ula_drawpixel(state, 0, state->m_emulation_pixels_per_byte);
+ }
+}
+
+
+// RGB input to the Video ULA from the Teletext IC
+// Just pass on the output at the correct pixel size.
+void bbc_draw_RGB_in(device_t *device, int offset,int data)
+{
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ BBC_ula_drawpixel(state, data, state->m_emulation_pixels_per_real_pixel);
+}
+
+
+
+
+
+
+// called when the 6845 changes the HSync
+static void BBC_Set_HSync(running_machine &machine, int offset, int data)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ // catch the falling edge
+ if((!data)&&(state->m_BBC_HSync))
+ {
+ state->m_y_screen_pos+=1;
+
+ if ((state->m_y_screen_pos>=0) && (state->m_y_screen_pos<300))
+ {
+ state->m_BBC_display_left = &state->m_BBC_bitmap->pix16(state->m_y_screen_pos);
+ state->m_BBC_display_right = state->m_BBC_display_left + 800;
+
+ } else {
+ state->m_BBC_display_left = &state->m_BBC_bitmap->pix16(0);
+ state->m_BBC_display_right = state->m_BBC_display_left;
+ }
+
+ state->m_BBC_display = state->m_BBC_display_left + state->m_x_screen_offset;
+
+ }
+ state->m_BBC_HSync=data;
+}
+
+// called when the 6845 changes the VSync
+static void BBC_Set_VSync(running_machine &machine, int offset, int data)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ // catch the falling edge
+ if ((!data)&&(state->m_BBC_VSync))
+ {
+ state->m_y_screen_pos=state->m_y_screen_offset;
+
+ if ((state->m_y_screen_pos>=0) && (state->m_y_screen_pos<300))
+ {
+ state->m_BBC_display_left = &state->m_BBC_bitmap->pix16(state->m_y_screen_pos);
+ state->m_BBC_display_right = state->m_BBC_display_left + 800;
+
+ } else {
+ state->m_BBC_display_left = &state->m_BBC_bitmap->pix16(0);
+ state->m_BBC_display_right = state->m_BBC_display_left;
+ }
+
+ state->m_BBC_display = state->m_BBC_display_left + state->m_x_screen_offset;
+
+ teletext_DEW(state->m_saa505x);
+ }
+ state->m_BBC_VSync=data;
+
+}
+
+// called when the 6845 changes the Cursor Enabled
+static void BBC_Set_CRE(running_machine &machine, int offset, int data)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ if (data&2) {
+ state->m_VideoULA_CR_counter=state->m_emulation_cursor_size;
+ state->m_VideoULA_CR=1;
+ // set the pallet on
+ if (data&1) set_cursor(state);
+ }
+}
+
+
+
+
+
+WRITE8_MEMBER(bbc_state::bbc_6845_w)
+{
+ mc6845_device *mc6845 = machine().device<mc6845_device>("mc6845");
+ switch(offset & 1)
+ {
+ case 0 :
+ mc6845->address_w(space,0,data);
+ break;
+ case 1 :
+ mc6845->register_w(space,0,data);
+ break;
+ }
+ return;
+
+ switch (offset&1)
+ {
+ case 0:
+ m6845_address_w(0,data);
+ break;
+ case 1:
+ m6845_register_w(0,data);
+ break;
+ }
+
+}
+
+ READ8_HANDLER (bbc_6845_r)
+{
+
+ mc6845_device *mc6845 = space->machine().device<mc6845_device>("mc6845");
+
+ switch (offset&1)
+ {
+ case 0: return mc6845->status_r(*space,0); break;
+ case 1: return mc6845->register_r(*space,0); break;
+ }
+ return 0;
+
+ int retval=0;
+
+ switch (offset&1)
+ {
+ case 0:
+ break;
+ case 1:
+ retval=m6845_register_r(0);
+ break;
+ }
+ return retval;
+}
+
+
+
+
+
+SCREEN_UPDATE_IND16( bbc )
+{
+
+ mc6845_device *mc6845 = screen.machine().device<mc6845_device>("mc6845");
+ mc6845->update( bitmap, cliprect);
+
+ return 0;
+
+
+
+ bbc_state *state = screen.machine().driver_data<bbc_state>();
+ long c;
+
+ //logerror ("Box %d by %d \n",cliprect.min_y,cliprect.max_y);
+
+ c = 0; // this is used to time out the screen redraw, in the case that the 6845 is in some way out state.
+
+
+ state->m_BBC_bitmap=bitmap;
+
+ state->m_BBC_display_left=&state->m_BBC_bitmap->pix16(0);
+ state->m_BBC_display_right=state->m_BBC_display_left;
+ state->m_BBC_display=state->m_BBC_display_left;
+
+ // loop until the end of the Vertical Sync pulse
+ // or until a timeout (this catches the 6845 with silly register values that would not give a VSYNC signal)
+ while((state->m_BBC_VSync)&&(c<60000))
+ {
+ // Clock the 6845
+ m6845_clock(screen.machine());
+ c++;
+ }
+
+
+ // loop until the Vertical Sync pulse goes high
+ // or until a timeout (this catches the 6845 with silly register values that would not give a VSYNC signal)
+ while((!state->m_BBC_VSync)&&(c<60000))
+ {
+ if ((state->m_y_screen_pos>=cliprect.min_y) && (state->m_y_screen_pos<=cliprect.max_y)) (state->m_draw_function)(screen.machine());
+
+ // and check the cursor
+ if (state->m_VideoULA_CR) BBC_Clock_CR(state);
+
+ // Clock the 6845
+ m6845_clock(screen.machine());
+ c++;
+ }
+
+ return 0;
+}
+
+void bbc_frameclock(running_machine &machine)
+{
+ m6845_frameclock();
+}
+
+*/
diff --git a/src/mess/video/bk.c b/src/mess/video/bk.c
new file mode 100644
index 00000000000..4bcef82ada2
--- /dev/null
+++ b/src/mess/video/bk.c
@@ -0,0 +1,39 @@
+/***************************************************************************
+
+ BK video driver by Miodrag Milanovic
+
+ 10/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/bk.h"
+
+
+VIDEO_START( bk0010 )
+{
+}
+
+SCREEN_UPDATE_IND16( bk0010 )
+{
+ bk_state *state = screen.machine().driver_data<bk_state>();
+ UINT16 code;
+ int y, x, b;
+ int nOfs;
+
+ nOfs = (state->m_scrool - 728) % 256;
+
+ for (y = 0; y < 256; y++)
+ {
+ for (x = 0; x < 32; x++)
+ {
+ code = state->m_bk0010_video_ram[((y+nOfs) %256)*32 + x];
+ for (b = 0; b < 16; b++)
+ {
+ bitmap.pix16(y, x*16 + b) = (code >> b) & 0x01;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mess/video/busicom.c b/src/mess/video/busicom.c
new file mode 100644
index 00000000000..eb46431b559
--- /dev/null
+++ b/src/mess/video/busicom.c
@@ -0,0 +1,1859 @@
+/***************************************************************************
+
+ Busicom 141-PF
+
+ 04/08/2009 Initial driver by Miodrag Milanovic
+
+****************************************************************************/
+#include "emu.h"
+#include "includes/busicom.h"
+
+// Printer font 34x44 as provided by MIT Media Lab
+
+
+static const UINT8 printer_font[]= {
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,3,4,5,6,6,5,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,6,7,7,7,7,7,7,7,7,6,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,5,7,7,7,7,7,7,7,7,7,7,7,7,5,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,7,7,5,3,2,1,1,2,3,5,7,7,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,6,7,7,7,6,2,0,0,0,0,0,0,0,0,1,5,7,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,5,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,6,1,0,0,0,0,0,0,
+0,0,0,0,3,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,4,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,0,0,0,0,0,0,
+0,0,0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,
+0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,
+0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,
+0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,
+0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,
+0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,4,0,0,0,0,0,
+0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,5,0,0,0,0,0,
+0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,5,0,0,0,0,0,
+0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,5,0,0,0,0,0,
+0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,5,0,0,0,0,0,
+0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,
+0,0,0,0,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,4,0,0,0,0,0,
+0,0,0,0,6,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,
+0,0,0,0,5,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,
+0,0,0,0,5,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,
+0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,6,0,0,0,0,0,0,
+0,0,0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,5,0,0,0,0,0,0,
+0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,
+0,0,0,0,0,2,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,6,1,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,5,2,0,0,0,0,0,0,0,0,0,3,7,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,7,7,5,2,0,0,0,0,1,4,6,7,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,2,6,7,7,7,7,7,6,6,5,5,7,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,6,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1,5,7,7,7,7,7,7,7,7,7,7,6,3,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,3,6,7,7,7,6,5,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,4,4,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,7,7,7,7,6,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,5,7,7,7,7,6,1,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,7,7,2,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,5,2,0,0,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,3,3,2,0,0,0,1,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,2,1,1,1,1,1,0,4,7,7,7,2,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,3,1,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,2,3,4,4,4,4,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,5,7,7,7,7,7,7,7,7,7,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,6,7,7,7,7,7,5,5,5,6,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1,6,7,7,7,5,2,0,0,0,0,0,1,1,4,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,5,0,0,0,0,0,0,0,0,0,
+0,0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,0,5,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,1,0,0,0,0,0,0,0,
+0,0,1,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,
+0,0,1,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,
+0,0,0,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,2,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,6,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,6,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1,6,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,6,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,6,7,7,5,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,0,0,0,0,0,0,0,0,
+0,0,0,6,7,7,7,7,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,
+0,0,0,1,3,4,4,4,4,4,4,4,3,3,4,4,4,4,4,4,4,5,5,5,5,5,4,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+0,0,0,5,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,
+0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,0,0,0,0,0,
+0,0,0,0,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,1,0,5,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,6,2,0,1,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,5,6,7,7,7,7,7,4,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,7,6,5,5,5,5,4,6,7,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,2,6,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,3,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,6,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,3,6,7,7,7,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,2,5,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,3,5,7,7,7,7,6,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,2,4,6,7,7,7,7,7,6,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,3,7,7,7,7,7,7,7,6,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,3,7,7,7,7,6,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,3,4,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,2,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,6,7,7,7,3,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,7,7,7,6,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,7,7,7,6,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,7,7,7,2,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,6,7,7,7,4,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,2,7,7,7,6,1,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,5,7,7,5,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,6,7,7,4,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,6,7,7,6,4,4,4,3,3,3,2,2,2,3,2,5,7,7,7,4,3,3,3,2,2,2,1,0,0,0,0,
+0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,
+0,0,0,2,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,
+0,0,0,0,0,1,3,4,4,4,4,5,5,5,5,4,4,4,6,7,7,7,4,3,4,4,4,5,4,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,5,2,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,2,4,4,3,3,3,3,3,3,4,3,3,3,3,4,4,4,4,4,4,4,4,2,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,
+0,0,0,0,6,7,7,5,4,4,5,5,5,5,5,5,6,6,6,6,6,6,6,6,5,4,1,0,0,0,0,0,0,0,
+0,0,0,0,6,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,5,0,0,0,1,3,4,6,6,7,6,5,4,3,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,6,2,4,5,7,7,7,7,7,7,7,7,7,7,7,4,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,6,6,6,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,7,7,7,7,5,3,2,1,0,0,0,2,6,7,7,7,6,2,0,0,0,0,0,0,0,0,
+0,0,0,0,2,7,7,7,7,6,4,2,0,0,0,0,0,0,0,0,1,5,7,7,7,6,1,0,0,0,0,0,0,0,
+0,0,0,0,0,1,3,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,6,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,3,6,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,4,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,2,3,5,6,7,7,7,7,7,6,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,3,7,7,7,7,7,7,7,5,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,6,7,7,7,6,4,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,5,5,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,4,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,7,7,7,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,7,7,7,7,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,7,7,7,7,7,7,6,4,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,7,7,5,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,6,4,2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,7,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,6,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1,6,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,5,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,2,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,6,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,5,7,7,7,2,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1,7,7,7,6,0,0,1,3,5,7,7,7,7,6,5,4,2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,2,7,7,7,5,1,5,7,7,7,7,7,7,7,7,7,7,7,4,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,4,7,7,7,7,7,7,7,7,5,2,0,1,1,2,4,6,7,7,7,6,1,0,0,0,0,0,0,0,0,
+0,0,0,0,4,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,4,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,6,1,0,0,0,0,0,
+0,0,0,0,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,3,0,0,0,0,0,
+0,0,0,0,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,5,0,0,0,0,0,
+0,0,0,0,6,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,6,0,0,0,0,0,
+0,0,0,0,5,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,6,0,0,0,0,0,
+0,0,0,0,4,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,6,0,0,0,0,0,
+0,0,0,0,3,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,6,0,0,0,0,0,
+0,0,0,0,2,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,5,0,0,0,0,0,
+0,0,0,0,0,6,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,4,0,0,0,0,0,
+0,0,0,0,0,4,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,
+0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,6,1,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,
+0,0,0,0,0,0,1,5,7,7,7,3,0,0,0,0,0,0,0,0,0,1,4,7,7,7,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,6,7,7,7,5,2,0,0,0,0,0,1,4,6,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1,5,7,7,7,7,5,3,4,5,5,6,7,7,7,7,5,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,4,6,7,7,7,7,7,7,6,4,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,3,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,1,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1,0,0,0,0,0,
+0,0,0,0,1,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,
+0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,
+0,0,0,0,3,7,7,7,7,6,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,6,7,7,2,0,0,0,0,0,
+0,0,0,0,3,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,6,0,0,0,0,0,0,
+0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,4,0,0,0,0,0,0,
+0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,
+0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,6,1,0,0,0,0,0,0,
+0,0,0,0,4,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,3,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,1,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,6,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,1,2,4,5,5,6,6,6,5,5,4,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,3,6,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,5,7,7,7,7,7,6,6,5,5,6,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,7,7,7,7,5,2,0,0,0,0,0,1,4,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,1,4,7,7,7,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,0,0,6,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,6,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,6,1,0,0,0,0,0,0,0,
+0,0,0,0,4,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,4,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,3,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,2,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,4,7,7,6,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,6,2,0,0,0,0,0,0,1,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,7,7,6,5,5,5,5,6,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,6,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,7,7,7,7,5,3,2,1,1,0,1,2,5,7,7,7,7,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,3,7,7,7,6,2,0,0,0,0,0,0,0,0,0,3,7,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,1,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,
+0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,6,1,0,0,0,0,0,0,
+0,0,0,6,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,2,0,0,0,0,0,0,
+0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,
+0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,
+0,0,2,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,5,0,0,0,0,0,0,
+0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,4,0,0,0,0,0,0,
+0,0,2,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,
+0,0,2,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,
+0,0,2,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,
+0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,
+0,0,0,5,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,
+0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,6,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,2,7,7,7,6,3,2,0,0,0,0,0,0,0,0,0,4,7,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,2,7,7,7,7,7,6,4,3,3,2,2,3,4,6,7,7,7,7,6,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1,2,2,3,3,4,4,4,5,4,4,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,2,3,4,5,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,6,7,7,7,7,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,3,6,7,7,7,7,7,7,7,7,7,7,7,7,6,3,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,5,7,7,7,7,7,6,5,4,4,5,7,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,6,7,7,7,6,2,1,0,0,0,0,0,1,2,5,7,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,3,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,3,0,0,0,0,0,0,
+0,0,0,0,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,
+0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,
+0,0,0,4,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,6,0,0,0,0,0,0,
+0,0,0,4,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,6,0,0,0,0,0,0,
+0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,
+0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,
+0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,3,0,0,0,0,0,
+0,0,0,0,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,4,0,0,0,0,0,
+0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,4,0,0,0,0,0,
+0,0,0,0,2,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,4,0,0,0,0,0,
+0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,4,0,0,0,0,0,
+0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,7,7,3,0,0,0,0,0,
+0,0,0,0,0,0,3,7,7,7,6,3,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,1,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,7,7,5,1,0,0,0,0,1,3,6,7,7,6,6,7,7,6,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,6,7,7,7,7,6,6,6,5,7,7,7,7,7,4,5,7,7,5,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,6,7,7,7,7,7,7,7,7,7,7,5,2,6,7,7,5,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,4,2,0,0,7,7,7,4,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,2,2,1,0,0,0,1,7,7,7,3,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,6,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,5,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,2,2,3,5,6,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,7,7,7,7,7,7,7,6,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,6,5,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,3,6,7,7,7,6,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,6,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,6,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,2,4,7,7,7,5,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,5,5,5,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,3,6,7,7,7,7,7,7,6,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1,4,6,7,7,7,7,7,7,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,4,6,6,5,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,2,0,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,2,1,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,6,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,6,0,4,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1,6,7,7,7,6,1,0,1,5,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1,5,7,7,7,7,2,0,0,0,1,6,7,7,7,6,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,7,7,3,0,0,0,0,0,1,6,7,7,7,5,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,7,7,3,0,0,0,0,0,0,0,1,6,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,7,4,0,0,0,0,0,0,0,0,0,2,6,7,7,7,5,1,0,0,0,0,0,0,
+0,0,0,0,0,2,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,5,0,0,0,0,0,0,
+0,0,0,0,3,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,5,0,0,0,0,0,
+0,0,0,2,6,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,4,0,0,0,0,
+0,0,2,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,4,0,0,0,
+0,1,6,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,3,0,0,
+0,4,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,
+0,4,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,
+0,0,5,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,6,1,0,0,
+0,0,1,6,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,1,0,0,0,
+0,0,0,1,5,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,2,0,0,0,0,
+0,0,0,0,1,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,4,0,0,0,0,0,
+0,0,0,0,0,1,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,
+0,0,0,0,0,0,2,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,7,7,7,7,3,0,0,0,0,0,0,0,0,2,7,7,7,6,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,3,7,7,7,7,2,0,0,0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,6,7,7,7,2,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,1,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,1,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,5,3,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,5,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,1,0,1,2,2,2,2,3,4,5,7,7,7,7,7,7,7,7,7,6,5,5,5,4,4,4,4,4,3,0,0,0,
+2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,
+2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,
+0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,
+0,1,2,2,2,3,3,3,3,3,3,4,7,7,7,7,7,7,7,5,3,2,2,2,2,2,2,1,1,2,1,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,5,5,5,5,5,5,4,4,3,0,0,
+4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,
+0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,4,2,0,0,0,
+0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,3,0,0,
+0,6,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,4,0,0,
+0,4,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,2,0,0,
+0,0,4,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,3,0,0,0,
+0,0,0,5,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,3,0,0,0,0,
+0,0,0,0,5,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,4,0,0,0,0,0,
+0,0,0,0,0,4,7,7,7,7,7,4,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,4,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,7,7,3,0,0,0,0,0,0,4,7,7,7,7,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,7,7,7,4,0,0,0,1,5,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,7,7,7,7,7,3,0,0,5,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,4,5,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,7,7,7,7,6,3,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,2,6,7,7,7,7,4,2,6,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,3,7,7,7,7,7,3,0,0,1,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,7,7,7,4,0,0,0,0,3,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,7,7,3,0,0,0,0,0,0,3,7,7,7,7,7,6,1,0,0,0,0,0,0,0,
+0,0,0,0,1,5,7,7,7,7,7,3,0,0,0,0,0,0,0,0,4,7,7,7,7,7,6,1,0,0,0,0,0,0,
+0,0,0,1,6,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,6,1,0,0,0,0,0,
+0,0,1,6,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,6,1,0,0,0,0,
+0,2,6,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,5,0,0,0,0,
+1,6,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,7,7,7,7,7,4,0,0,0,
+1,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,3,0,0,
+0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,7,7,7,7,3,0,0,
+0,0,4,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,7,3,0,0,0,
+0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,6,5,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,5,4,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,3,4,5,5,5,2,0,0,
+2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+0,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,1,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,5,5,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,5,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,4,5,5,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,1,0,0,
+5,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,5,0,0,
+5,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,6,0,0,
+5,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,7,7,7,7,7,7,6,0,0,
+5,7,7,7,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,7,7,7,7,6,0,0,
+5,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,6,0,0,
+5,7,7,7,5,3,5,7,7,7,7,3,0,0,0,0,0,0,0,0,4,7,7,7,7,6,4,6,7,7,7,6,0,0,
+5,7,7,7,3,0,0,4,7,7,7,7,3,0,0,0,0,0,0,3,7,7,7,7,6,1,0,2,7,7,7,6,0,0,
+5,7,7,7,3,0,0,0,2,6,7,7,7,4,1,0,0,0,4,7,7,7,7,5,0,0,0,1,7,7,7,6,0,0,
+5,7,7,7,3,0,0,0,0,1,6,7,7,7,6,3,3,5,7,7,7,7,5,0,0,0,0,0,6,7,7,6,1,0,
+5,7,7,7,3,0,0,0,0,0,1,5,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,4,7,7,7,1,0,
+4,7,7,7,3,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,3,7,7,7,1,0,
+4,7,7,7,3,0,0,0,0,0,0,0,0,3,7,7,7,7,7,3,0,0,0,0,0,0,0,0,3,7,7,7,1,0,
+4,7,7,7,3,0,0,0,0,0,0,0,0,0,3,7,7,6,2,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,
+4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,
+4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,
+3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,
+3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,
+3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,
+2,7,7,7,3,0,0,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,2,7,7,7,2,0,
+2,7,7,7,3,0,0,0,0,0,0,0,0,0,3,7,7,6,1,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,
+1,7,7,7,2,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,2,6,7,4,0,0,
+0,2,4,2,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,4,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,4,4,4,4,4,5,5,5,6,7,7,7,7,7,7,7,7,6,5,5,5,5,5,5,2,0,0,0,0,0,
+0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,
+0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,
+0,0,0,0,2,4,5,5,5,5,5,5,4,5,7,7,7,7,7,6,3,2,2,3,3,3,2,2,1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,5,6,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,5,5,3,0,0,0,
+3,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,3,0,0,
+4,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,7,7,7,7,7,7,4,0,0,
+5,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,5,0,0,
+6,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,5,0,0,
+5,7,7,7,6,6,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,6,7,7,7,7,5,0,0,
+5,7,7,7,4,0,3,6,7,7,7,5,0,0,0,0,0,0,0,1,6,7,7,7,6,2,0,3,7,7,7,5,0,0,
+5,7,7,7,3,0,0,1,5,7,7,7,4,0,0,0,0,0,0,5,7,7,7,6,1,0,0,0,6,7,7,5,0,0,
+5,7,7,7,2,0,0,0,0,4,7,7,7,4,0,0,0,1,6,7,7,7,4,1,0,0,0,0,5,7,7,5,0,0,
+5,7,7,7,2,0,0,0,0,0,4,7,7,7,3,0,1,5,7,7,7,4,0,0,0,0,0,0,5,7,7,6,0,0,
+5,7,7,7,2,0,0,0,0,0,0,3,7,7,7,6,6,7,7,7,3,0,0,0,0,0,0,0,4,7,7,6,0,0,
+5,7,7,7,2,0,0,0,0,0,0,0,3,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,4,7,7,6,0,0,
+5,7,7,7,2,0,0,0,0,0,0,0,0,2,6,7,7,7,3,0,0,0,0,0,0,0,0,0,3,7,7,7,0,0,
+5,7,7,7,2,0,0,0,0,0,0,0,0,0,2,5,5,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,
+5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,
+5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,
+5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,
+4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,0,0,
+4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,6,1,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,6,0,0,
+4,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,6,0,0,
+2,6,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,4,0,0,
+0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,0,
+0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,0,0,0,0,
+0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,
+0,0,0,0,1,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,5,7,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,4,5,6,7,7,7,7,7,5,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,6,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,
+0,0,0,0,0,0,0,0,0,1,3,4,5,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,0,
+0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,6,4,4,6,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1,4,7,7,7,7,3,0,0,0,0,3,7,7,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,6,7,7,7,7,2,0,0,0,0,0,0,5,7,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,7,6,1,0,0,0,0,0,0,0,1,6,7,7,3,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1,5,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,3,7,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,2,6,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,3,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+3,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,3,5,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,4,4,4,4,3,0,0,
+4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+1,3,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,4,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,5,5,5,5,5,6,6,6,6,6,6,4,0,0,
+6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,
+7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+1,3,4,4,4,4,4,4,4,4,4,4,5,5,5,5,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,2,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,3,3,3,3,3,3,3,3,4,4,4,3,4,5,5,3,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,6,6,6,6,6,6,5,5,5,5,5,5,5,2,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,3,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,2,3,0,0,0,0,1,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,3,0,0,0,3,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,6,0,0,0,5,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,7,1,0,1,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,7,1,0,3,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,7,2,1,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,7,6,6,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,7,7,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+3,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+3,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+3,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,6,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,3,4,4,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1,4,7,7,7,7,7,6,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,1,0,0,
+0,0,2,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,4,0,0,
+0,1,6,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,4,0,0,
+0,5,7,7,7,6,3,1,1,3,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,
+2,7,7,7,6,1,0,0,0,0,1,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,
+2,7,7,7,1,0,0,0,0,0,0,0,6,7,7,4,0,0,0,0,0,0,0,0,0,2,7,7,7,4,0,0,0,0,
+3,7,7,7,1,0,0,0,0,0,0,0,6,7,7,6,0,0,0,0,0,0,0,0,1,6,7,7,6,1,0,0,0,0,
+4,7,7,7,3,0,0,0,0,0,0,1,7,7,7,6,0,0,0,0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,
+3,7,7,7,4,0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,0,0,
+1,6,7,7,6,2,0,0,0,0,0,5,7,7,6,1,0,0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,0,0,
+0,4,7,7,7,7,4,1,2,2,5,7,7,7,4,0,0,0,0,0,0,3,7,7,7,6,1,0,0,0,0,0,0,0,
+0,0,6,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,3,7,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,2,6,7,7,7,7,7,7,7,7,5,1,0,0,0,0,0,2,7,7,7,7,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,2,5,7,7,7,7,7,5,0,0,0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,5,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,2,7,7,7,7,1,0,0,0,0,0,0,1,3,6,7,7,5,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,6,7,7,7,2,0,0,0,0,0,2,6,7,7,7,7,7,7,7,5,2,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,0,2,6,7,7,7,7,7,7,7,7,7,6,1,0,0,0,
+0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,1,6,7,7,7,7,6,4,5,7,7,7,7,4,0,0,0,
+0,0,0,0,0,0,3,7,7,7,6,1,0,0,0,0,0,4,7,7,7,6,2,0,0,0,2,5,7,7,7,1,0,0,
+0,0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,2,7,7,7,4,0,0,
+0,0,0,0,1,5,7,7,7,4,0,0,0,0,0,0,0,5,7,7,5,0,0,0,0,0,0,0,6,7,7,4,0,0,
+0,0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,6,7,7,4,0,0,0,0,0,0,0,3,7,7,4,0,0,
+0,0,0,2,7,7,7,7,1,0,0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,5,7,7,3,0,0,
+0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,6,7,7,5,0,0,0,0,0,0,1,7,7,7,3,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,3,7,7,7,2,0,0,
+0,3,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,6,3,1,0,1,5,7,7,7,5,0,0,0,
+0,4,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,6,6,7,7,7,6,1,0,0,0,
+0,2,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,1,0,0,0,0,
+0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,5,5,6,7,5,4,3,1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,5,5,5,4,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,2,5,7,7,7,7,7,7,7,7,7,7,5,2,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,4,7,7,7,7,7,7,7,6,5,5,6,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,7,7,4,1,0,0,0,0,0,1,2,5,7,7,7,7,5,1,0,0,0,0,0,0,
+0,0,0,0,0,4,7,7,7,7,4,1,0,0,0,0,0,0,0,0,0,1,3,6,7,7,7,5,1,0,0,0,0,0,
+0,0,0,0,3,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,6,0,0,0,0,0,
+0,0,0,1,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,3,0,0,0,0,
+0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,0,0,0,0,
+0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,4,0,0,0,0,
+0,0,3,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
+0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,3,1,0,0,0,
+0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,5,0,0,0,
+0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,3,0,0,0,
+0,0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,3,0,0,0,0,
+0,0,0,0,2,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,5,0,0,0,0,0,
+0,0,0,0,0,4,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,2,6,7,7,7,7,5,1,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,7,7,4,2,1,0,0,0,0,1,3,7,7,7,7,7,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,6,6,7,7,7,7,7,7,6,2,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,3,6,7,7,7,7,7,7,7,7,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,5,6,7,7,7,7,7,7,7,6,5,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,2,4,5,5,5,4,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,3,2,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,3,1,0,0,0,0,0,0,0,0,
+0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,
+0,0,4,7,7,7,7,6,6,6,6,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,4,0,0,0,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,4,6,7,7,7,4,0,0,0,0,0,
+0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,2,0,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,6,1,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,4,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,6,0,0,0,
+0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,6,0,0,0,
+0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,5,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,4,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,6,1,0,0,0,
+0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,
+0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,
+0,0,4,7,7,7,7,4,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,5,7,7,7,5,1,0,0,0,0,0,
+0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,
+0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,3,0,0,0,0,0,0,0,0,
+0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,0,
+0,0,3,7,7,7,7,4,1,1,1,1,1,2,2,1,1,2,6,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,3,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,1,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,3,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,6,1,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,1,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,4,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,1,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,0,
+0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,
+0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,
+0,0,2,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,1,0,0,0,0,0,
+0,0,2,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,
+0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,6,1,0,0,0,0,
+0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,
+0,0,0,6,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,7,4,0,0,0,0,
+0,0,0,1,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,5,6,1,0,0,0,0,0,0,0,0,0,0,0,1,6,7,5,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,6,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,2,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,7,7,7,1,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,3,1,1,1,0,0,0,0,
+0,0,0,0,0,2,7,7,7,7,5,0,0,0,0,0,0,0,0,1,4,7,7,7,7,7,7,7,7,7,6,1,0,0,
+0,0,1,2,4,6,7,7,7,7,7,6,5,4,3,3,3,4,5,6,7,7,7,7,7,7,7,7,7,7,7,2,0,0,
+0,2,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,
+1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,3,2,1,0,0,0,0,
+2,7,7,7,7,7,7,7,7,7,7,7,6,5,5,4,4,3,3,3,4,7,7,7,7,7,2,0,0,0,0,0,0,0,
+0,5,7,7,7,7,7,7,7,7,7,3,1,0,0,0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,1,1,4,6,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,1,7,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,5,2,2,1,1,0,0,0,
+0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,4,0,0,
+0,0,0,0,0,0,4,7,7,7,7,5,3,3,3,4,5,5,5,6,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+0,0,0,0,1,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,3,1,0,0,
+1,3,5,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,2,1,0,0,0,0,0,
+2,7,7,7,7,7,7,7,7,7,7,7,7,4,3,2,2,2,3,2,2,6,7,7,7,6,0,0,0,0,0,0,0,0,
+1,5,7,7,7,7,7,7,7,7,7,4,1,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,1,2,3,4,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,6,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,5,7,7,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,2,7,7,3,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,3,3,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,3,4,2,0,0,0,0,0,0,0,0,0,0,0,0,2,5,3,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,7,7,3,0,0,0,0,0,0,0,0,0,0,0,6,7,7,2,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,1,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,4,0,0,0,0,0,0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,2,7,7,7,2,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,6,1,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,7,7,7,4,0,0,0,0,0,6,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1,6,7,7,6,1,0,0,5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,2,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,2,6,7,5,0,4,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,5,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,4,4,3,4,5,5,5,6,5,3,2,3,6,7,7,7,7,4,3,4,5,5,5,5,5,5,5,5,6,5,2,0,0,
+4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,
+3,7,7,7,7,7,7,7,7,7,6,6,7,7,7,7,7,7,4,4,5,6,7,7,7,7,7,7,7,7,7,3,0,0,
+0,0,1,1,1,2,2,2,1,0,0,0,4,7,7,5,7,7,1,0,0,0,1,1,1,2,2,2,2,1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,7,4,0,6,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,3,7,7,1,0,2,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,2,7,7,6,0,0,0,5,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1,6,7,7,5,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,1,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,7,7,7,7,2,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,6,7,7,7,6,0,0,0,0,0,0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,3,7,7,7,7,3,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,5,7,7,2,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,1,5,6,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,4,5,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,1,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,6,5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,1,4,7,7,7,7,6,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,3,5,5,6,7,7,7,7,7,7,7,6,6,6,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,2,4,4,4,4,4,4,4,4,4,4,4,4,4,2,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,1,0,0,0,0,
+0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,
+0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,
+0,0,0,1,2,4,6,7,7,7,7,5,3,3,3,3,3,3,3,3,5,7,7,7,7,7,4,3,2,0,0,0,0,0,
+0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,1,1,1,2,5,7,7,7,7,5,2,1,1,0,0,0,0,1,3,7,7,7,7,6,2,2,2,0,0,0,0,0,
+0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,
+0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,
+0,0,1,2,3,3,3,4,4,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,4,1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,3,0,0,0,0,
+0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,0,0,
+0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,
+0,0,0,2,4,4,7,7,7,7,6,2,2,4,7,7,7,7,7,4,3,5,7,7,7,7,6,4,2,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,3,0,0,0,6,7,7,7,3,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,2,0,0,0,5,7,7,7,2,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,2,0,0,0,4,7,7,7,2,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,2,0,0,0,4,7,7,7,2,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,2,0,0,0,3,7,7,7,2,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,2,0,0,0,3,7,7,7,2,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,2,0,0,0,3,7,7,7,2,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,3,7,7,7,2,0,0,0,3,7,7,7,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,1,7,7,7,3,0,0,0,3,7,7,7,2,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,7,7,3,0,0,0,3,7,7,7,2,0,0,0,2,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,7,7,3,0,0,0,3,7,7,7,3,0,0,0,2,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,7,7,3,0,0,0,2,7,7,7,3,0,0,0,2,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,7,7,3,0,0,0,2,7,7,7,3,0,0,0,2,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,7,7,3,0,0,0,2,7,7,7,3,0,0,0,2,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,7,7,3,0,0,0,2,7,7,7,3,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,7,7,3,0,0,0,2,7,7,7,4,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,3,0,0,0,2,7,7,7,4,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,3,0,0,0,2,7,7,7,4,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,3,0,0,0,2,7,7,7,4,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,3,0,0,0,1,7,7,7,4,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,3,0,0,0,1,7,7,7,5,0,0,0,1,6,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,3,0,0,0,1,7,7,7,5,0,0,0,0,6,7,7,2,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,4,0,0,0,1,7,7,7,5,0,0,0,0,6,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,4,0,0,0,1,7,7,7,6,0,0,0,0,6,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,4,0,0,0,1,7,7,7,6,0,0,0,0,6,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,4,0,0,0,1,7,7,7,6,1,0,0,0,5,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,4,0,0,0,1,7,7,7,7,1,0,0,0,5,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,3,7,7,4,0,0,0,0,6,7,7,7,1,0,0,0,5,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,3,7,7,4,0,0,0,0,6,7,7,7,1,0,0,0,5,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,3,7,7,4,0,0,0,0,6,7,7,7,1,0,0,0,5,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,3,7,7,5,0,0,0,0,7,7,7,7,1,0,0,0,5,7,7,3,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,7,7,6,1,0,0,2,7,7,7,7,3,0,0,0,6,7,7,4,0,0,0,0,0,0,0,
+0,0,0,0,0,1,4,7,7,7,7,6,4,5,6,7,7,7,7,6,3,3,4,7,7,7,7,5,3,1,0,0,0,0,
+0,0,1,5,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,
+0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,
+0,0,1,4,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,5,4,0,0,0,0,
+0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+2,6,7,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,5,5,1,0,0,
+5,7,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,7,7,7,7,4,0,0,
+5,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,7,7,5,0,0,
+5,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,5,0,0,
+5,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,7,7,7,7,6,0,0,
+5,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,1,0,
+5,7,7,7,5,3,6,7,7,7,7,5,1,0,0,0,0,0,0,0,4,7,7,7,7,6,3,5,7,7,7,7,2,0,
+6,7,7,7,1,0,0,3,7,7,7,7,6,2,0,0,0,0,0,4,7,7,7,7,5,1,0,1,7,7,7,7,1,0,
+6,7,7,6,0,0,0,0,2,6,7,7,7,7,3,0,0,0,4,7,7,7,7,5,0,0,0,0,5,7,7,7,1,0,
+5,7,7,6,0,0,0,0,0,1,5,7,7,7,7,6,5,6,7,7,7,7,4,0,0,0,0,0,3,7,7,7,1,0,
+5,7,7,7,1,0,0,0,0,0,1,5,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,3,7,7,7,1,0,
+5,7,7,7,1,0,0,0,0,0,0,0,4,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,2,7,7,7,1,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,3,7,7,7,7,7,3,0,0,0,0,0,0,0,0,2,7,7,7,1,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,2,6,7,6,1,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,2,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,2,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,2,0,
+3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,2,0,
+3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,2,0,
+2,7,7,7,1,0,0,0,0,0,0,0,0,0,3,7,7,4,0,0,0,0,0,0,0,0,0,0,1,6,7,7,1,0,
+2,7,7,7,1,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,4,7,4,0,0,
+1,4,5,3,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,3,4,4,5,5,5,5,5,5,6,7,7,7,7,7,6,6,5,5,5,5,5,5,5,3,0,0,0,0,0,
+0,0,0,1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,0,0,0,
+0,0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,5,3,0,0,0,0,0,
+0,0,0,0,0,1,4,4,4,4,4,5,5,6,7,7,7,7,7,6,3,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,4,5,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,
+4,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,7,7,4,0,0,
+5,7,7,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,5,0,0,
+5,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,5,0,0,
+6,7,7,7,7,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,7,7,7,7,6,0,0,
+6,7,7,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,6,0,0,
+6,7,7,7,6,4,5,7,7,7,6,1,0,0,0,0,0,0,0,0,3,7,7,7,7,5,2,5,7,7,7,6,0,0,
+6,7,7,7,2,0,1,4,7,7,7,6,1,0,0,0,0,0,0,3,7,7,7,7,4,0,0,2,7,7,7,6,0,0,
+6,7,7,7,1,0,0,0,3,6,7,7,6,1,0,0,0,0,4,7,7,7,7,4,0,0,0,0,5,7,7,6,0,0,
+6,7,7,7,1,0,0,0,0,1,6,7,7,7,3,1,2,5,7,7,7,7,3,0,0,0,0,0,3,7,7,6,0,0,
+6,7,7,7,1,0,0,0,0,0,1,5,7,7,7,7,7,7,7,7,5,2,0,0,0,0,0,0,4,7,7,6,0,0,
+5,7,7,7,1,0,0,0,0,0,0,1,6,7,7,7,7,7,7,6,1,0,0,0,0,0,0,0,4,7,7,6,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,1,4,7,7,7,7,5,1,0,0,0,0,0,0,0,0,5,7,7,6,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,3,7,6,3,0,0,0,0,0,0,0,0,0,0,5,7,7,6,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,4,7,7,6,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,2,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,2,0,
+4,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,0,
+3,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,6,0,0,
+2,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,5,0,0,
+2,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,2,0,0,
+0,2,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+0,0,0,0,4,5,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,4,1,0,0,0,0,0,
+0,0,0,1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,
+0,0,0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,4,0,0,0,0,0,0,
+0,0,0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,1,1,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,7,7,7,7,7,7,7,7,7,7,7,6,6,6,5,5,5,5,5,5,5,5,5,5,6,6,3,0,0,0,0,
+0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,
+0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,
+0,0,0,1,1,1,1,1,2,2,2,2,3,7,7,7,7,7,6,3,2,2,1,1,1,1,1,1,1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,2,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,1,0,0,0,0,0,0,
+0,0,1,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,4,0,0,0,0,0,0,0,
+0,0,1,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,6,1,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,0,3,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,0,3,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,4,0,0,0,0,0,0,0,0,2,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,4,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,3,0,0,0,0,0,0,1,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,3,0,0,0,0,0,1,6,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,4,0,0,0,0,0,5,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,1,5,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,1,5,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,7,2,2,6,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,7,7,7,7,7,7,6,2,5,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,7,7,7,7,6,1,0,1,5,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,7,7,7,6,1,0,0,0,1,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,7,7,6,2,0,0,0,0,0,2,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,7,6,1,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,7,2,0,0,0,0,0,0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,6,1,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,6,1,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,6,0,0,0,0,0,0,0,0,
+0,0,1,6,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,0,0,0,0,
+0,0,0,6,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,5,0,0,0,0,0,0,0,
+0,0,0,6,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,2,0,0,0,0,0,0,
+0,0,0,6,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,6,1,0,0,0,0,0,
+0,0,0,6,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,0,0,0,
+0,0,0,5,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,3,0,0,0,0,
+0,0,0,5,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,5,0,0,0,0,
+0,0,0,4,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,5,0,0,0,0,
+0,0,0,3,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,2,0,0,0,0,
+0,0,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,2,2,1,0,0,0,0,
+0,0,1,3,4,4,4,5,5,5,5,5,5,5,5,5,5,5,4,4,3,4,5,6,6,7,7,7,7,7,2,0,0,0,
+0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,
+0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,
+0,3,7,7,7,7,6,4,3,3,3,3,3,3,4,4,4,4,4,4,4,5,5,5,5,5,6,5,5,3,1,0,0,0,
+0,3,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,2,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,2,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,2,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,6,7,7,7,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,6,7,7,7,7,7,6,6,6,5,5,5,6,6,6,6,6,6,6,6,6,3,0,0,0,0,0,0,0,0,0,0,
+0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,0,0,0,0,0,0,0,
+0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,
+0,0,6,7,7,7,6,4,3,4,4,4,4,5,6,5,5,4,4,4,4,4,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,5,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,2,0,0,0,
+0,0,4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,
+0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,0,
+0,0,0,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,2,0,0,0,
+0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,3,3,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+2,5,5,5,5,5,5,4,4,4,4,4,4,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,5,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,5,1,0,0,0,0,0,0,0,2,2,0,0,0,
+3,7,7,7,5,1,0,1,1,1,1,1,0,0,0,0,0,0,4,7,7,6,1,0,0,0,0,1,5,7,6,1,0,0,
+3,7,7,7,7,7,6,7,7,7,7,7,4,1,0,0,0,0,4,7,7,7,3,0,0,0,0,3,7,7,7,1,0,0,
+3,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,0,0,1,6,7,7,6,1,0,0,1,6,7,7,5,0,0,0,
+2,7,7,7,7,6,5,5,5,6,6,7,6,3,0,0,0,0,0,3,7,7,7,3,0,0,4,7,7,7,2,0,0,0,
+2,7,7,7,4,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,5,7,7,5,0,1,6,7,7,4,0,0,0,0,
+2,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,1,2,7,7,7,2,0,0,0,0,
+3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,5,6,7,7,4,0,0,0,0,0,
+3,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,7,6,0,0,0,0,0,0,
+3,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,3,0,0,0,0,0,0,
+3,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,1,0,0,0,0,0,0,
+3,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,2,0,0,0,0,0,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,4,0,0,0,0,0,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,6,1,0,0,0,0,0,
+4,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,7,5,0,0,0,0,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,4,7,7,7,2,0,0,0,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,1,0,5,7,7,5,0,0,0,0,
+4,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,5,0,0,1,6,7,7,3,0,0,0,
+4,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,3,7,7,6,1,0,0,
+4,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,4,0,0,0,0,0,5,7,7,3,0,0,
+4,7,7,7,6,4,3,2,2,1,1,1,1,0,0,0,0,0,2,7,7,7,2,0,0,0,0,0,1,7,7,5,0,0,
+3,7,7,7,7,7,7,7,7,7,7,7,7,6,4,1,0,0,5,7,7,7,1,0,0,0,0,0,0,4,7,5,0,0,
+1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,0,0,4,7,7,4,0,0,0,0,0,0,0,1,5,3,0,0,
+0,3,6,7,7,7,7,7,7,7,7,7,7,7,7,4,0,0,1,4,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,3,3,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1,3,5,6,7,7,7,7,7,7,7,7,4,1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,2,6,7,7,7,7,7,7,7,7,7,7,7,7,6,3,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,5,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2,7,7,7,7,7,6,3,2,2,2,2,2,4,5,6,7,7,7,7,6,2,0,0,0,0,0,0,
+0,0,0,0,0,1,6,7,7,7,6,3,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,6,0,0,0,0,0,0,
+0,0,0,0,1,5,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,7,4,0,0,0,0,0,
+0,0,0,0,4,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,7,2,0,0,0,0,
+0,0,0,2,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,7,7,3,0,0,0,0,
+0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,7,2,0,0,0,0,
+0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,
+0,0,0,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,5,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,7,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,2,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,1,0,0,0,
+0,0,0,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,7,7,4,0,0,0,
+0,0,0,0,3,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,7,7,7,2,0,0,0,
+0,0,0,0,0,6,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,4,0,0,0,0,
+0,0,0,0,0,1,6,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,5,0,0,0,0,0,
+0,0,0,0,0,0,4,7,7,7,6,2,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,6,1,0,0,0,0,0,
+0,0,0,0,0,0,0,4,7,7,7,7,5,2,0,0,0,0,0,0,1,2,5,7,7,7,6,2,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,7,7,7,7,7,5,4,3,2,2,4,6,7,7,7,7,5,1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,2,4,6,7,7,7,7,7,7,7,7,5,4,2,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,4,4,4,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,3,5,5,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,
+0,0,6,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,3,0,0,0,0,
+0,0,6,7,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,4,0,0,0,0,
+0,1,7,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,7,7,5,0,0,0,0,
+0,1,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,6,0,0,0,0,
+0,1,7,7,7,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,7,6,0,0,0,0,
+0,1,7,7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,7,7,6,0,0,0,0,
+0,1,7,7,7,7,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,1,6,7,7,7,7,7,6,0,0,0,0,
+0,1,7,7,7,7,7,7,7,7,3,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,6,1,0,0,0,
+0,1,7,7,7,6,5,7,7,7,5,0,0,0,0,0,0,0,0,0,0,1,7,7,7,7,7,7,7,7,1,0,0,0,
+0,1,7,7,7,4,0,5,7,7,7,3,0,0,0,0,0,0,0,0,0,4,7,7,7,5,5,7,7,7,1,0,0,0,
+0,1,7,7,7,5,0,2,7,7,7,5,0,0,0,0,0,0,0,0,1,6,7,7,7,1,3,7,7,7,1,0,0,0,
+0,1,7,7,7,5,0,0,6,7,7,7,2,0,0,0,0,0,0,0,5,7,7,7,4,0,4,7,7,7,1,0,0,0,
+0,1,7,7,7,5,0,0,4,7,7,7,3,0,0,0,0,0,0,1,7,7,7,7,1,0,4,7,7,7,1,0,0,0,
+0,1,7,7,7,5,0,0,1,7,7,7,5,0,0,0,0,0,0,3,7,7,7,5,0,0,4,7,7,7,2,0,0,0,
+0,1,7,7,7,5,0,0,0,5,7,7,7,1,0,0,0,0,0,6,7,7,7,2,0,0,4,7,7,7,2,0,0,0,
+0,1,7,7,7,6,0,0,0,2,7,7,7,4,0,0,0,0,3,7,7,7,5,0,0,0,4,7,7,7,3,0,0,0,
+0,1,7,7,7,6,0,0,0,0,6,7,7,6,0,0,0,0,6,7,7,7,2,0,0,0,4,7,7,7,3,0,0,0,
+0,1,7,7,7,6,0,0,0,0,3,7,7,7,1,0,0,2,7,7,7,5,0,0,0,0,4,7,7,7,3,0,0,0,
+0,1,7,7,7,6,1,0,0,0,1,7,7,7,3,0,0,4,7,7,7,3,0,0,0,0,4,7,7,7,3,0,0,0,
+0,1,7,7,7,7,1,0,0,0,0,4,7,7,5,0,0,6,7,7,6,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,1,7,7,7,7,1,0,0,0,0,2,7,7,7,2,1,7,7,7,2,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,1,6,7,7,7,1,0,0,0,0,0,6,7,7,5,5,7,7,6,0,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,0,6,7,7,6,1,0,0,0,0,0,4,7,7,7,7,7,7,4,0,0,0,0,0,0,4,7,7,7,2,0,0,0,
+0,0,6,7,7,6,1,0,0,0,0,0,2,7,7,7,7,7,7,2,0,0,0,0,0,0,4,7,7,7,2,0,0,0,
+0,0,6,7,7,6,0,0,0,0,0,0,0,5,7,7,7,7,5,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,
+0,0,6,7,7,6,0,0,0,0,0,0,0,1,6,7,7,7,1,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,
+0,0,6,7,7,6,0,0,0,0,0,0,0,0,2,6,7,4,0,0,0,0,0,0,0,0,4,7,7,7,1,0,0,0,
+0,0,6,7,7,6,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,
+0,0,6,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,
+0,1,6,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,1,7,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,4,0,0,0,
+0,1,7,7,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,1,7,7,7,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,1,6,7,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,3,0,0,0,
+0,0,6,7,7,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,7,2,0,0,0,
+0,0,5,7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,7,7,0,0,0,0,
+0,0,4,7,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,5,0,0,0,0,
+0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+VIDEO_START( busicom )
+{
+}
+
+SCREEN_UPDATE_IND16( busicom )
+{
+ busicom_state *state = screen.machine().driver_data<busicom_state>();
+ int y, x, b, j;
+ //34x44
+ for (y = 0; y < 11; y++)
+ {
+ UINT8 col = 8 * state->m_printer_line_color[y];
+ for (x = 0; x < 17; x++)
+ {
+ UINT8 chr = state->m_printer_line[y][x];
+ for (j = 0; j < 44; j++) {
+ for (b = 0; b < 34; b++)
+ {
+ bitmap.pix16((y*44)+j, x*40+b) = printer_font[44*34 * chr + j*34 + b] + col ;
+ }
+ for (b = 34; b < 40; b++)
+ {
+ bitmap.pix16((y*44)+j, x*40+b) = 0;
+ }
+
+ }
+ }
+ }
+ return 0;
+}
+static const UINT8 color[] = { 0xFF,0xDB,0xB7,0x92,0x6E,0x49,0x25,0x00 };
+
+static const UINT8 color_red[] = { 0xb0,0xb5,0xc0,0xc5,0xd0,0xd5,0xdf };
+
+PALETTE_INIT( busicom )
+{
+ int i;
+ for(i=0;i<8;i++) {
+ palette_set_color( machine, i, MAKE_RGB(color[i],color[i],color[i]) );
+ }
+ palette_set_color( machine, 8, MAKE_RGB(0xff,0xff,0xff) );
+ for(i=0;i<7;i++) {
+ palette_set_color( machine, i+9, MAKE_RGB(color_red[i],0x00,0x00) );
+ }
+}
diff --git a/src/mess/video/cbmb.c b/src/mess/video/cbmb.c
new file mode 100644
index 00000000000..908cc923398
--- /dev/null
+++ b/src/mess/video/cbmb.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+
+ PeT mess@utanet.at
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/cbmb.h"
+#include "video/mc6845.h"
+
+
+
+VIDEO_START( cbmb_crtc )
+{
+}
+
+void cbm600_vh_init(running_machine &machine)
+{
+ UINT8 *gfx = machine.root_device().memregion("gfx1")->base();
+ int i;
+
+ /* inversion logic on board */
+ for (i=0; i<0x800; i++) {
+ gfx[0x1000+i]=gfx[0x800+i];
+ gfx[0x1800+i]=gfx[0x1000+i]^0xff;
+ gfx[0x800+i]=gfx[i]^0xff;
+ }
+}
+
+void cbm700_vh_init(running_machine &machine)
+{
+ UINT8 *gfx = machine.root_device().memregion("gfx1")->base();
+ int i;
+ for (i=0; i<0x800; i++) {
+ gfx[0x1000+i]=gfx[0x800+i];
+ gfx[0x1800+i]=gfx[0x1000+i]^0xff;
+ gfx[0x800+i]=gfx[i]^0xff;
+ }
+}
+
+VIDEO_START( cbm700 )
+{
+ int i;
+
+ /* remove pixel column 9 for character codes 0 - 175 and 224 - 255 */
+ for( i = 0; i < 256; i++)
+ {
+// if( i < 176 || i > 223 )
+ {
+ int y;
+ for( y = 0; y < machine.gfx[0]->height; y++ ) {
+ machine.gfx[0]->gfxdata[(i * machine.gfx[0]->height + y) * machine.gfx[0]->width + 8] = 0;
+ machine.gfx[1]->gfxdata[(i * machine.gfx[1]->height + y) * machine.gfx[1]->width + 8] = 0;
+ }
+ }
+ }
+}
+
+void cbmb_vh_set_font(running_machine &machine, int font)
+{
+ cbmb_state *state = machine.driver_data<cbmb_state>();
+ state->m_font=font;
+}
+
+MC6845_UPDATE_ROW( cbm600_update_row )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 *videoram = state->m_videoram;
+ int i;
+
+ for( i = 0; i < x_count; i++ ) {
+ if ( i == cursor_x ) {
+ bitmap.plot_box( device->machine().gfx[state->m_font]->width * i, y, device->machine().gfx[state->m_font]->width, 1, palette[1] );
+ } else {
+ drawgfx_opaque( bitmap, cliprect, device->machine().gfx[state->m_font], videoram[(ma+i )& 0x7ff], 0, 0, 0, device->machine().gfx[state->m_font]->width * i, y-ra );
+ }
+ }
+}
+
+MC6845_UPDATE_ROW( cbm700_update_row )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 *videoram = state->m_videoram;
+ int i;
+
+ for( i = 0; i < x_count; i++ ) {
+ if ( i == cursor_x ) {
+ bitmap.plot_box( device->machine().gfx[state->m_font]->width * i, y, device->machine().gfx[state->m_font]->width, 1, palette[1] );
+ } else {
+ drawgfx_opaque( bitmap, cliprect, device->machine().gfx[state->m_font], videoram[(ma+i) & 0x7ff], 0, 0, 0, device->machine().gfx[state->m_font]->width * i, y-ra );
+ }
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER( cbmb_display_enable_changed )
+{
+}
+
diff --git a/src/mess/video/cgc7900.c b/src/mess/video/cgc7900.c
new file mode 100644
index 00000000000..db253e1ab69
--- /dev/null
+++ b/src/mess/video/cgc7900.c
@@ -0,0 +1,255 @@
+#include "emu.h"
+#include "includes/cgc7900.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define OVERLAY_CUR BIT(cell, 31) /* places a cursor in the cell if SET */
+#define OVERLAY_BLK BIT(cell, 30) /* blinks the foreground character in the cell if SET */
+#define OVERLAY_VF BIT(cell, 28) /* makes the foreground visible if SET (else transparent) */
+#define OVERLAY_VB BIT(cell, 27) /* makes the background visible if SET (else transparent) */
+#define OVERLAY_PL BIT(cell, 24) /* uses bits 0-7 as PLOT DOT descriptor if SET (else ASCII) */
+#define OVERLAY_BR BIT(cell, 18) /* turns on Red in background if SET */
+#define OVERLAY_BG BIT(cell, 17) /* turns on Green in background if SET */
+#define OVERLAY_BB BIT(cell, 16) /* turns on Blue in background if SET */
+#define OVERLAY_FR BIT(cell, 10) /* turns on Red in foreground if SET */
+#define OVERLAY_FG BIT(cell, 9) /* turns on Green in foreground if SET */
+#define OVERLAY_FB BIT(cell, 8) /* turns on Blue in background if SET */
+#define OVERLAY_DATA (cell & 0xff) /* ASCII or Plot Dot character */
+
+#define IMAGE_SELECT BIT(m_roll_overlay[0], 13)
+#define OVERLAY_CURSOR_BLINK BIT(m_roll_overlay[0], 12)
+#define OVERLAY_CHARACTER_BLINK BIT(m_roll_overlay[0], 11)
+
+/***************************************************************************
+ READ/WRITE HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ cgc7900_z_mode_r - Z mode read
+-------------------------------------------------*/
+
+READ16_MEMBER( cgc7900_state::z_mode_r )
+{
+ return 0;
+}
+
+/*-------------------------------------------------
+ cgc7900_z_mode_w - Z mode write
+-------------------------------------------------*/
+
+WRITE16_MEMBER( cgc7900_state::z_mode_w )
+{
+}
+
+/*-------------------------------------------------
+ cgc7900_color_status_w - color status write
+-------------------------------------------------*/
+
+WRITE16_MEMBER( cgc7900_state::color_status_w )
+{
+}
+
+/*-------------------------------------------------
+ cgc7900_sync_r - sync information read
+-------------------------------------------------*/
+
+READ16_MEMBER( cgc7900_state::sync_r )
+{
+ /*
+
+ bit signal description
+
+ 0 _VERT vertical retrace (0=vblank)
+ 1 interlace (1=first field, 0=second field)
+ 2 _HG horizontal retrace (0=hblank)
+ 3 1
+ 4 1
+ 5 1
+ 6 1
+ 7 1
+ 8 1
+ 9 1
+ 10 1
+ 11 1
+ 12 1
+ 13 1
+ 14 1
+ 15 1
+
+ */
+
+ return 0xffff;
+}
+
+/***************************************************************************
+ VIDEO
+***************************************************************************/
+
+/*-------------------------------------------------
+ update_clut - update color lookup table
+-------------------------------------------------*/
+
+void cgc7900_state::update_clut()
+{
+ for (int i = 0; i < 256; i++)
+ {
+ UINT16 addr = i * 2;
+ UINT32 data = (m_clut_ram[addr + 1] << 16) | m_clut_ram[addr];
+ UINT8 b = data & 0xff;
+ UINT8 g = (data >> 8) & 0xff;
+ UINT8 r = (data >> 16) & 0xff;
+
+ palette_set_color_rgb(machine(), i + 8, r, g, b);
+ }
+}
+
+/*-------------------------------------------------
+ draw_bitmap - draw bitmap image
+-------------------------------------------------*/
+
+void cgc7900_state::draw_bitmap(screen_device *screen, bitmap_ind16 &bitmap)
+{
+}
+
+/*-------------------------------------------------
+ draw_overlay - draw text overlay
+-------------------------------------------------*/
+
+void cgc7900_state::draw_overlay(screen_device *screen, bitmap_ind16 &bitmap)
+{
+ for (int y = 0; y < 768; y++)
+ {
+ int sy = y / 8;
+ int line = y % 8;
+
+ for (int sx = 0; sx < 85; sx++)
+ {
+ UINT16 addr = (sy * 170) + (sx * 2);
+ UINT32 cell = (m_overlay_ram[addr] << 16) | m_overlay_ram[addr + 1];
+ UINT8 data = m_char_rom[(OVERLAY_DATA << 3) | line];
+ int fg = (cell >> 8) & 0x07;
+ int bg = (cell >> 16) & 0x07;
+
+ for (int x = 0; x < 8; x++)
+ {
+ if (OVERLAY_CUR)
+ {
+ if (!OVERLAY_CURSOR_BLINK || m_blink)
+ {
+ bitmap.pix16(y, (sx * 8) + x) = 7;
+ }
+ }
+ else
+ {
+ if (BIT(data, x) && (!OVERLAY_CHARACTER_BLINK || m_blink))
+ {
+ if (OVERLAY_VF) bitmap.pix16(y, (sx * 8) + x) = fg;
+ }
+ else
+ {
+ if (OVERLAY_VB) bitmap.pix16(y, (sx * 8) + x) = bg;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+ TIMER_DEVICE_CALLBACK( blink_tick )
+-------------------------------------------------*/
+
+static TIMER_DEVICE_CALLBACK( blink_tick )
+{
+ cgc7900_state *state = timer.machine().driver_data<cgc7900_state>();
+
+ state->m_blink = !state->m_blink;
+}
+
+/*-------------------------------------------------
+ PALETTE_INIT( cgc7900 )
+-------------------------------------------------*/
+
+static PALETTE_INIT( cgc7900 )
+{
+ palette_set_color_rgb(machine, 0, 0x00, 0x00, 0x00 );
+ palette_set_color_rgb(machine, 1, 0x00, 0x00, 0xff );
+ palette_set_color_rgb(machine, 2, 0x00, 0xff, 0x00 );
+ palette_set_color_rgb(machine, 3, 0x00, 0xff, 0xff );
+ palette_set_color_rgb(machine, 4, 0xff, 0x00, 0x00 );
+ palette_set_color_rgb(machine, 5, 0xff, 0x00, 0xff );
+ palette_set_color_rgb(machine, 6, 0xff, 0xff, 0x00 );
+ palette_set_color_rgb(machine, 7, 0xff, 0xff, 0xff );
+}
+
+/*-------------------------------------------------
+ VIDEO_START( cgc7900 )
+-------------------------------------------------*/
+
+void cgc7900_state::video_start()
+{
+ /* find memory regions */
+ m_char_rom = memregion("gfx1")->base();
+}
+
+/*-------------------------------------------------
+ SCREEN_UPDATE_IND16( cgc7900 )
+-------------------------------------------------*/
+
+UINT32 cgc7900_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ update_clut();
+ draw_bitmap(&screen, bitmap);
+ draw_overlay(&screen, bitmap);
+
+ return 0;
+}
+
+/*-------------------------------------------------
+ gfx_layout cgc7900_charlayout
+-------------------------------------------------*/
+
+static const gfx_layout cgc7900_charlayout =
+{
+ 8,8,
+ RGN_FRAC(1,1),
+ 1,
+ { RGN_FRAC(0,1) },
+ { STEP8(7,-1) },
+ { STEP8(0,8) },
+ 8*8
+};
+
+/*-------------------------------------------------
+ GFXDECODE( cgc7900 )
+-------------------------------------------------*/
+
+static GFXDECODE_START( cgc7900 )
+ GFXDECODE_ENTRY( "gfx1", 0x0000, cgc7900_charlayout, 0, 1 )
+GFXDECODE_END
+
+/***************************************************************************
+ MACHINE DRIVERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ MACHINE_DRIVER( cgc7900_video )
+-------------------------------------------------*/
+
+MACHINE_CONFIG_FRAGMENT( cgc7900_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
+ MCFG_SCREEN_UPDATE_DRIVER(cgc7900_state, screen_update)
+ MCFG_SCREEN_SIZE(1024, 768)
+ MCFG_SCREEN_VISIBLE_AREA(0, 1024-1, 0, 768-1)
+
+ MCFG_GFXDECODE(cgc7900)
+
+ MCFG_PALETTE_LENGTH(8+256) /* 8 overlay colors + 256 bitmap colors */
+ MCFG_PALETTE_INIT(cgc7900)
+
+ MCFG_TIMER_ADD_PERIODIC("blink", blink_tick, attotime::from_hz(XTAL_28_48MHz/7500000))
+MACHINE_CONFIG_END
diff --git a/src/mess/video/cgenie.c b/src/mess/video/cgenie.c
new file mode 100644
index 00000000000..ba40c4f5cc3
--- /dev/null
+++ b/src/mess/video/cgenie.c
@@ -0,0 +1,422 @@
+/***************************************************************************
+
+ cgenie.c
+
+ Functions to emulate the video controller 6845.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/cgenie.h"
+
+
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+VIDEO_START( cgenie )
+{
+ cgenie_state *state = machine.driver_data<cgenie_state>();
+ screen_device *screen = machine.first_screen();
+
+ screen->register_screen_bitmap(state->m_dlybitmap);
+ screen->register_screen_bitmap(state->m_bitmap);
+}
+
+/***************************************************************************
+
+ Calculate the horizontal and vertical offset for the
+ current register settings of the 6845 CRTC
+
+***************************************************************************/
+static void cgenie_offset_xy(cgenie_state *state)
+{
+ if( state->m_crt.horizontal_sync_pos )
+ state->m_off_x = state->m_crt.horizontal_total - state->m_crt.horizontal_sync_pos - 14;
+ else
+ state->m_off_x = -15;
+
+ state->m_off_y = (state->m_crt.vertical_total - state->m_crt.vertical_sync_pos) *
+ (state->m_crt.scan_lines + 1) + state->m_crt.vertical_adjust
+ - 32;
+
+ if( state->m_off_y < 0 )
+ state->m_off_y = 0;
+
+ if( state->m_off_y > 128 )
+ state->m_off_y = 128;
+
+// logerror("cgenie offset x:%d y:%d\n", state->m_off_x, state->m_off_y);
+}
+
+
+/***************************************************************************
+ Write to an indexed register of the 6845 CRTC
+***************************************************************************/
+WRITE8_HANDLER ( cgenie_register_w )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ //int addr;
+
+ switch (state->m_crt.idx)
+ {
+ case 0:
+ if( state->m_crt.horizontal_total == data )
+ break;
+ state->m_crt.horizontal_total = data;
+ cgenie_offset_xy(state);
+ break;
+ case 1:
+ if( state->m_crt.horizontal_displayed == data )
+ break;
+ state->m_crt.horizontal_displayed = data;
+ break;
+ case 2:
+ if( state->m_crt.horizontal_sync_pos == data )
+ break;
+ state->m_crt.horizontal_sync_pos = data;
+ cgenie_offset_xy(state);
+ break;
+ case 3:
+ state->m_crt.horizontal_length = data;
+ break;
+ case 4:
+ if( state->m_crt.vertical_total == data )
+ break;
+ state->m_crt.vertical_total = data;
+ cgenie_offset_xy(state);
+ break;
+ case 5:
+ if( state->m_crt.vertical_adjust == data )
+ break;
+ state->m_crt.vertical_adjust = data;
+ cgenie_offset_xy(state);
+ break;
+ case 6:
+ if( state->m_crt.vertical_displayed == data )
+ break;
+ state->m_crt.vertical_displayed = data;
+ break;
+ case 7:
+ if( state->m_crt.vertical_sync_pos == data )
+ break;
+ state->m_crt.vertical_sync_pos = data;
+ cgenie_offset_xy(state);
+ break;
+ case 8:
+ state->m_crt.crt_mode = data;
+ break;
+ case 9:
+ data &= 15;
+ if( state->m_crt.scan_lines == data )
+ break;
+ state->m_crt.scan_lines = data;
+ cgenie_offset_xy(state);
+ break;
+ case 10:
+ if( state->m_crt.cursor_top == data )
+ break;
+ state->m_crt.cursor_top = data;
+ //addr = 256 * state->m_crt.cursor_address_hi + state->m_crt.cursor_address_lo;
+ break;
+ case 11:
+ if( state->m_crt.cursor_bottom == data )
+ break;
+ state->m_crt.cursor_bottom = data;
+ //addr = 256 * state->m_crt.cursor_address_hi + state->m_crt.cursor_address_lo;
+ break;
+ case 12:
+ data &= 63;
+ if( state->m_crt.screen_address_hi == data )
+ break;
+ state->m_crt.screen_address_hi = data;
+ break;
+ case 13:
+ if( state->m_crt.screen_address_lo == data )
+ break;
+ state->m_crt.screen_address_lo = data;
+ break;
+ case 14:
+ data &= 63;
+ if( state->m_crt.cursor_address_hi == data )
+ break;
+ state->m_crt.cursor_address_hi = data;
+ //addr = 256 * state->m_crt.cursor_address_hi + state->m_crt.cursor_address_lo;
+ break;
+ case 15:
+ if( state->m_crt.cursor_address_lo == data )
+ break;
+ state->m_crt.cursor_address_lo = data;
+ //addr = 256 * state->m_crt.cursor_address_hi + state->m_crt.cursor_address_lo;
+ break;
+ }
+}
+
+/***************************************************************************
+ Write to the index register of the 6845 CRTC
+***************************************************************************/
+WRITE8_HANDLER ( cgenie_index_w )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ state->m_crt.idx = data & 15;
+}
+
+/***************************************************************************
+ Read from an indexed register of the 6845 CRTC
+***************************************************************************/
+ READ8_HANDLER ( cgenie_register_r )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ return cgenie_get_register(space->machine(), state->m_crt.idx);
+}
+
+/***************************************************************************
+ Read from a register of the 6845 CRTC
+***************************************************************************/
+int cgenie_get_register(running_machine &machine, int indx)
+{
+ cgenie_state *state = machine.driver_data<cgenie_state>();
+ switch (indx)
+ {
+ case 0:
+ return state->m_crt.horizontal_total;
+ case 1:
+ return state->m_crt.horizontal_displayed;
+ case 2:
+ return state->m_crt.horizontal_sync_pos;
+ case 3:
+ return state->m_crt.horizontal_length;
+ case 4:
+ return state->m_crt.vertical_total;
+ case 5:
+ return state->m_crt.vertical_adjust;
+ case 6:
+ return state->m_crt.vertical_displayed;
+ case 7:
+ return state->m_crt.vertical_sync_pos;
+ case 8:
+ return state->m_crt.crt_mode;
+ case 9:
+ return state->m_crt.scan_lines;
+ case 10:
+ return state->m_crt.cursor_top;
+ case 11:
+ return state->m_crt.cursor_bottom;
+ case 12:
+ return state->m_crt.screen_address_hi;
+ case 13:
+ return state->m_crt.screen_address_lo;
+ case 14:
+ return state->m_crt.cursor_address_hi;
+ case 15:
+ return state->m_crt.cursor_address_lo;
+ }
+ return 0;
+}
+
+/***************************************************************************
+ Read the index register of the 6845 CRTC
+***************************************************************************/
+ READ8_HANDLER ( cgenie_index_r )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ return state->m_crt.idx;
+}
+
+/***************************************************************************
+ Switch mode between character generator and graphics
+***************************************************************************/
+void cgenie_mode_select(running_machine &machine, int mode)
+{
+ cgenie_state *state = machine.driver_data<cgenie_state>();
+ state->m_graphics = (mode) ? 1 : 0;
+}
+
+
+static void cgenie_refresh_monitor(running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ cgenie_state *state = machine.driver_data<cgenie_state>();
+ UINT8 *videoram = state->m_videoram;
+ int i, address, offset, cursor, size, code, x, y;
+ rectangle r;
+
+ bitmap.fill(get_black_pen(machine), cliprect);
+
+ if(state->m_crt.vertical_displayed || state->m_crt.horizontal_displayed)
+ {
+ offset = 256 * state->m_crt.screen_address_hi + state->m_crt.screen_address_lo;
+ size = state->m_crt.horizontal_displayed * state->m_crt.vertical_displayed;
+ cursor = 256 * state->m_crt.cursor_address_hi + state->m_crt.cursor_address_lo;
+
+ /*
+ * for every character in the Video RAM, check if it has been modified since
+ * last time and update it accordingly.
+ */
+ for( address = 0; address < size; address++ )
+ {
+ i = (offset + address) & 0x3fff;
+ x = address % state->m_crt.horizontal_displayed + state->m_off_x;
+ y = address / state->m_crt.horizontal_displayed;
+
+ r.min_x = x * 8;
+ r.max_x = r.min_x + 7;
+ r.min_y = y * (state->m_crt.scan_lines + 1) + state->m_off_y;
+ r.max_y = r.min_y + state->m_crt.scan_lines;
+
+ if( state->m_graphics )
+ {
+ /* get graphics code */
+ code = videoram[i];
+ drawgfx_opaque(bitmap, r, machine.gfx[1], code, 0,
+ 0, 0, r.min_x, r.min_y);
+ }
+ else
+ {
+ /* get character code */
+ code = videoram[i];
+
+ /* translate defined character sets */
+ code += state->m_font_offset[(code >> 6) & 3];
+ drawgfx_opaque(bitmap, r, machine.gfx[0], code, state->m_colorram[i&0x3ff],
+ 0, 0, r.min_x, r.min_y);
+ }
+
+ if( i == cursor )
+ {
+ rectangle rc;
+
+ /* check if cursor turned off */
+ if( (state->m_crt.cursor_top & 0x60) == 0x20 )
+ continue;
+
+ if( (state->m_crt.cursor_top & 0x60) == 0x60 )
+ {
+ state->m_crt.cursor_visible = 1;
+ }
+ else
+ {
+ state->m_crt.cursor_phase++;
+ state->m_crt.cursor_visible = (state->m_crt.cursor_phase >> 3) & 1;
+ }
+
+ if( !state->m_crt.cursor_visible )
+ continue;
+
+ rc.min_x = r.min_x;
+ rc.max_x = r.max_x;
+ rc.min_y = r.min_y + (state->m_crt.cursor_top & 15);
+ rc.max_y = r.min_y + (state->m_crt.cursor_bottom & 15);
+ drawgfx_opaque(bitmap, rc, machine.gfx[0], 0x7f, state->m_colorram[i&0x3ff],
+ 0, 0, rc.min_x, rc.min_y);
+ }
+ }
+ }
+}
+
+static void cgenie_refresh_tv_set(running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ cgenie_state *state = machine.driver_data<cgenie_state>();
+ UINT8 *videoram = state->m_videoram;
+ int i, address, offset, cursor, size, code, x, y;
+ rectangle r;
+
+ state->m_bitmap.fill(get_black_pen(machine), cliprect);
+ state->m_dlybitmap.fill(get_black_pen(machine), cliprect);
+
+ if(state->m_crt.vertical_displayed || state->m_crt.horizontal_displayed)
+ {
+ offset = 256 * state->m_crt.screen_address_hi + state->m_crt.screen_address_lo;
+ size = state->m_crt.horizontal_displayed * state->m_crt.vertical_displayed;
+ cursor = 256 * state->m_crt.cursor_address_hi + state->m_crt.cursor_address_lo;
+
+ /*
+ * for every character in the Video RAM, check if it has been modified since
+ * last time and update it accordingly.
+ */
+ for( address = 0; address < size; address++ )
+ {
+ i = (offset + address) & 0x3fff;
+ x = address % state->m_crt.horizontal_displayed + state->m_off_x;
+ y = address / state->m_crt.horizontal_displayed;
+
+ r.min_x = x * 8;
+ r.max_x = r.min_x + 7;
+ r.min_y = y * (state->m_crt.scan_lines + 1) + state->m_off_y;
+ r.max_y = r.min_y + state->m_crt.scan_lines;
+
+ if( state->m_graphics )
+ {
+ /* get graphics code */
+ code = videoram[i];
+ drawgfx_opaque(state->m_bitmap, r, machine.gfx[1], code, 1,
+ 0, 0, r.min_x, r.min_y);
+ drawgfx_opaque(state->m_dlybitmap, r, machine.gfx[1], code, 2,
+ 0, 0, r.min_x, r.min_y);
+ }
+ else
+ {
+ /* get character code */
+ code = videoram[i];
+
+ /* translate defined character sets */
+ code += state->m_font_offset[(code >> 6) & 3];
+ drawgfx_opaque(state->m_bitmap, r, machine.gfx[0], code, state->m_colorram[i&0x3ff] + 16,
+ 0, 0, r.min_x, r.min_y);
+ drawgfx_opaque(state->m_dlybitmap, r, machine.gfx[0], code, state->m_colorram[i&0x3ff] + 32,
+ 0, 0, r.min_x, r.min_y);
+ }
+
+ if( i == cursor )
+ {
+ rectangle rc;
+
+ /* check if cursor turned off */
+ if( (state->m_crt.cursor_top & 0x60) == 0x20 )
+ continue;
+
+ if( (state->m_crt.cursor_top & 0x60) == 0x60 )
+ {
+ state->m_crt.cursor_visible = 1;
+ }
+ else
+ {
+ state->m_crt.cursor_phase++;
+ state->m_crt.cursor_visible = (state->m_crt.cursor_phase >> 3) & 1;
+ }
+
+ if( !state->m_crt.cursor_visible )
+ continue;
+
+ rc.min_x = r.min_x;
+ rc.max_x = r.max_x;
+ rc.min_y = r.min_y + (state->m_crt.cursor_top & 15);
+ rc.max_y = r.min_y + (state->m_crt.cursor_bottom & 15);
+
+ drawgfx_opaque(state->m_bitmap, rc, machine.gfx[0], 0x7f, state->m_colorram[i&0x3ff] + 16,
+ 0, 0, rc.min_x, rc.min_y);
+ drawgfx_opaque(state->m_dlybitmap, rc, machine.gfx[0], 0x7f, state->m_colorram[i&0x3ff] + 32,
+ 0, 0, rc.min_x, rc.min_y);
+ }
+ }
+ }
+
+ copybitmap(bitmap, state->m_bitmap, 0, 0, 0, 0, cliprect);
+ copybitmap_trans(bitmap, state->m_dlybitmap, 0, 0, 1, 0, cliprect, 0);
+}
+
+/***************************************************************************
+ Draw the game screen in the given bitmap_ind16.
+***************************************************************************/
+SCREEN_UPDATE_IND16( cgenie )
+{
+ cgenie_state *state = screen.machine().driver_data<cgenie_state>();
+ if( state->m_tv_mode )
+ cgenie_refresh_tv_set(screen.machine(), bitmap, cliprect);
+ else
+ cgenie_refresh_monitor(screen.machine(), bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mess/video/channelf.c b/src/mess/video/channelf.c
new file mode 100644
index 00000000000..32ae62ffc2e
--- /dev/null
+++ b/src/mess/video/channelf.c
@@ -0,0 +1,71 @@
+#include "includes/channelf.h"
+
+static const rgb_t channelf_palette[] =
+{
+ MAKE_RGB(0x10, 0x10, 0x10), /* black */
+ MAKE_RGB(0xfd, 0xfd, 0xfd), /* white */
+ MAKE_RGB(0xff, 0x31, 0x53), /* red */
+ MAKE_RGB(0x02, 0xcc, 0x5d), /* green */
+ MAKE_RGB(0x4b, 0x3f, 0xf3), /* blue */
+ MAKE_RGB(0xe0, 0xe0, 0xe0), /* ltgray */
+ MAKE_RGB(0x91, 0xff, 0xa6), /* ltgreen */
+ MAKE_RGB(0xce, 0xd0, 0xff) /* ltblue */
+};
+
+#define BLACK 0
+#define WHITE 1
+#define RED 2
+#define GREEN 3
+#define BLUE 4
+#define LTGRAY 5
+#define LTGREEN 6
+#define LTBLUE 7
+
+static const UINT16 colormap[] = {
+ BLACK, WHITE, WHITE, WHITE,
+ LTBLUE, BLUE, RED, GREEN,
+ LTGRAY, BLUE, RED, GREEN,
+ LTGREEN, BLUE, RED, GREEN,
+};
+
+/* Initialise the palette */
+PALETTE_INIT( channelf )
+{
+ palette_set_colors(machine, 0, channelf_palette, ARRAY_LENGTH(channelf_palette));
+}
+
+VIDEO_START( channelf )
+{
+ channelf_state *state = machine.driver_data<channelf_state>();
+ state->m_p_videoram = state->memregion("vram")->base();
+}
+
+static int recalc_palette_offset(int reg1, int reg2)
+{
+ /* Note: This is based on the decoding they used to */
+ /* determine which palette this line is using */
+
+ return ((reg2&0x2)|(reg1>>1)) << 2;
+}
+
+SCREEN_UPDATE_IND16( channelf )
+{
+ channelf_state *state = screen.machine().driver_data<channelf_state>();
+ UINT8 y,col;
+ UINT16 ma=0,x;
+ int palette_offset;
+
+ for(y = 0; y < 64; y++ )
+ {
+ UINT16 *p = &bitmap.pix16(y);
+ palette_offset = recalc_palette_offset(state->m_p_videoram[y*128+125]&3, state->m_p_videoram[y*128+126]&3);
+
+ for (x = ma; x < ma + 128; x++)
+ {
+ col = palette_offset+(state->m_p_videoram[x|(y<<7)]&3);
+ *p++ = colormap[col];
+ }
+ ma+=128;
+ }
+ return 0;
+}
diff --git a/src/mess/video/cirrus.c b/src/mess/video/cirrus.c
new file mode 100644
index 00000000000..9a1c9b3a778
--- /dev/null
+++ b/src/mess/video/cirrus.c
@@ -0,0 +1,233 @@
+/***************************************************************************
+
+ video/cirrus.c
+
+ Cirrus SVGA card emulation (preliminary)
+
+ Cirrus has the following additional registers that are not present in
+ conventional VGA:
+
+ SEQ 06h: Unlock Cirrus registers; write 12h to unlock registers,
+ and read 12h back to confirm Cirrus presence.
+ SEQ 07h
+ bit 3-1: Pixel depth
+ 0x00 8 bpp
+ 0x02 16 bpp (double vert clock)
+ 0x04 24 bpp
+ 0x06 16 bpp
+ 0x08 32 bpp
+ bit 0: VGA/SVGA (0=VGA, 1=SVGA)
+ SEQ 0Fh
+ bit 7: Bankswitch enable
+ bits 4-3: Memory size
+ 0x00 256K
+ 0x08 512K
+ 0x10 1M
+ 0x18 2M
+ SEQ 12h: Hardware Cursor
+
+
+
+
+ GC 09h: Set 64k bank (bits 3-0 only)
+ GC 20h: Blit Width (bits 7-0)
+ GC 21h: Blit Width (bits 12-8)
+ GC 22h: Blit Height (bits 7-0)
+ GC 23h: Blit Height (bits 12-8)
+ GC 24h: Blit Destination Pitch (bits 7-0)
+ GC 25h: Blit Destination Pitch (bits 12-8)
+ GC 26h: Blit Source Pitch (bits 7-0)
+ GC 27h: Blit Source Pitch (bits 12-8)
+ GC 28h: Blit Destination Address (bits 7-0)
+ GC 29h: Blit Destination Address (bits 15-8)
+ GC 2Ah: Blit Destination Address (bits 21-16)
+ GC 2Ch: Blit Source Address (bits 7-0)
+ GC 2Dh: Blit Source Address (bits 15-8)
+ GC 2Eh: Blit Source Address (bits 21-16)
+ GC 2Fh: Blit Write Mask
+ GC 30h: Blit Mode
+ GC 31h: Blit Status
+ bit 7 - Autostart
+ bit 4 - FIFO Used
+ bit 2 - Blit Reset
+ bit 1 - Blit Started
+ bit 0 - Blit Busy
+ GC 32h: Raster Operation
+ GC 33h: Blit Mode Extension
+ GC 34h: Blit Transparent Color (bits 7-0)
+ GC 35h: Blit Transparent Color (bits 15-8)
+ GC 38h: Blit Transparent Color Mask (bits 7-0)
+ GC 39h: Blit Transparent Color Mask (bits 15-8)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cirrus.h"
+#include "video/pc_vga.h"
+
+#define LOG_PCIACCESS 0
+
+static void cirrus_update_8bpp(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ UINT32 *line;
+ const UINT8 *vram;
+ int y, x;
+
+ vram = (const UINT8 *) pc_vga_memory();
+
+ for (y = 0; y < 480; y++)
+ {
+ line = &bitmap.pix32(y);
+
+ for (x = 0; x < 640; x++)
+ *line++ = machine.pens[*vram++];
+ }
+}
+
+
+
+static void cirrus_update_16bpp(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ fatalerror("NYI");
+}
+
+
+
+static void cirrus_update_24bpp(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ fatalerror("NYI");
+}
+
+
+
+static void cirrus_update_32bpp(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ fatalerror("NYI");
+}
+
+
+
+static void cirrus_choosevideomode(running_machine &machine, bitmap_rgb32 &bitmap, const rectangle &cliprect, const UINT8 *sequencer,
+ const UINT8 *crtc, int *width, int *height)
+{
+ if ((sequencer[0x06] == 0x12) && (sequencer[0x07] & 0x01))
+ {
+ *width = 640;
+ *height = 480;
+
+ switch(sequencer[0x07] & 0x0E)
+ {
+ case 0x00: cirrus_update_8bpp(machine, bitmap, cliprect); break;
+ case 0x02: cirrus_update_16bpp(machine, bitmap, cliprect); break;
+ case 0x04: cirrus_update_24bpp(machine, bitmap, cliprect); break;
+ case 0x06: cirrus_update_16bpp(machine, bitmap, cliprect); break;
+ case 0x08: cirrus_update_32bpp(machine, bitmap, cliprect); break;
+ }
+ }
+}
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type CIRRUS = &device_creator<cirrus_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// cirrus_device - constructor
+//-------------------------------------------------
+
+cirrus_device::cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, CIRRUS, "CIRRUS", tag, owner, clock),
+ pci_device_interface( mconfig, *this )
+{
+}
+
+const struct pc_svga_interface cirrus_svga_interface =
+{
+ 2 * 1024 * 1024, /* 2 megs vram */
+ 8, /* 8 sequencer registers */
+ 10, /* 10 gc registers */
+ 25, /* 25 crtc registers */
+ cirrus_choosevideomode
+};
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cirrus_device::device_start()
+{
+ pc_vga_init(machine(), NULL, &cirrus_svga_interface);
+ pc_vga_io_init(machine(), machine().device("ppc1")->memory().space(AS_PROGRAM), 0xC00A0000, machine().device("ppc1")->memory().space(AS_PROGRAM), 0x80000000);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void cirrus_device::device_reset()
+{
+}
+
+//-------------------------------------------------
+// pci_read - implementation of PCI read
+//-------------------------------------------------
+
+UINT32 cirrus_device::pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask)
+{
+ UINT32 result = 0;
+
+ if (function == 0)
+ {
+ switch(offset)
+ {
+ case 0x00: /* vendor/device ID */
+ result = 0x00A01013;
+ break;
+
+ case 0x08:
+ result = 0x03000000;
+ break;
+
+ case 0x10:
+ result = 0xD0000000;
+ break;
+
+ default:
+ result = 0;
+ break;
+ }
+ }
+
+ if (LOG_PCIACCESS)
+ logerror("cirrus5430_pci_read(): function=%d offset=0x%02X result=0x%04X\n", function, offset, result);
+ return result;
+}
+
+
+//-------------------------------------------------
+// pci_write - implementation of PCI write
+//-------------------------------------------------
+
+void cirrus_device::pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask)
+{
+ if (LOG_PCIACCESS)
+ logerror("cirrus5430_pci_write(): function=%d offset=0x%02X data=0x%04X\n", function, offset, data);
+}
+
+/*************************************
+ *
+ * Ports
+ *
+ *************************************/
+
+WRITE8_DEVICE_HANDLER( cirrus_42E8_w )
+{
+ if (data & 0x80)
+ pc_vga_reset(device->machine());
+}
diff --git a/src/mess/video/cirrus.h b/src/mess/video/cirrus.h
new file mode 100644
index 00000000000..c45d73a468a
--- /dev/null
+++ b/src/mess/video/cirrus.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+
+ video/cirrus.h
+
+ Cirrus SVGA card emulation (preliminary)
+
+***************************************************************************/
+
+#ifndef CIRRUS_H
+#define CIRRUS_H
+
+#include "machine/pci.h"
+
+// ======================> cirrus_device
+
+class cirrus_device : public device_t,
+ public pci_device_interface
+{
+public:
+ // construction/destruction
+ cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual UINT32 pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask);
+ virtual void pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "cirrus"; }
+private:
+};
+
+
+// device type definition
+extern const device_type CIRRUS;
+
+#endif /* CIRRUS_H */
diff --git a/src/mess/video/comquest.c b/src/mess/video/comquest.c
new file mode 100644
index 00000000000..be3daff283c
--- /dev/null
+++ b/src/mess/video/comquest.c
@@ -0,0 +1,22 @@
+#include "emu.h"
+
+#include "includes/comquest.h"
+
+VIDEO_START( comquest )
+{
+}
+
+SCREEN_UPDATE_IND16( comquest )
+{
+ int x, y, j;
+
+ for (y=0; y<128;y++) {
+ for (x=0, j=0; j<8;j++,x+=8*4) {
+#if 0
+ drawgfx_opaque(bitmap, 0, machine.gfx[0], state->m_data[y][j],0,
+ 0,0,x,y);
+#endif
+ }
+ }
+ return 0;
+}
diff --git a/src/mess/video/comx35.c b/src/mess/video/comx35.c
new file mode 100644
index 00000000000..4b8cd7a4525
--- /dev/null
+++ b/src/mess/video/comx35.c
@@ -0,0 +1,152 @@
+#include "emu.h"
+#include "rendlay.h"
+#include "includes/comx35.h"
+#include "cpu/cosmac/cosmac.h"
+#include "sound/cdp1869.h"
+#include "sound/wave.h"
+#include "video/mc6845.h"
+
+WRITE8_MEMBER( comx35_state::cdp1869_w )
+{
+ UINT16 ma = m_maincpu->get_memory_address();
+
+ switch (offset)
+ {
+ case 3:
+ m_vis->out3_w(space, ma, data);
+ break;
+
+ case 4:
+ m_vis->out4_w(space, ma, data);
+ break;
+
+ case 5:
+ m_vis->out5_w(space, ma, data);
+ break;
+
+ case 6:
+ m_vis->out6_w(space, ma, data);
+ break;
+
+ case 7:
+ m_vis->out7_w(space, ma, data);
+ break;
+ }
+}
+
+/* CDP1869 */
+
+static ADDRESS_MAP_START( cdp1869_page_ram, AS_0, 8, driver_device )
+ AM_RANGE(0x000, 0x7ff) AM_RAM
+ADDRESS_MAP_END
+
+static CDP1869_CHAR_RAM_READ( comx35_charram_r )
+{
+ comx35_state *state = device->machine().driver_data<comx35_state>();
+
+ UINT8 column = pmd & 0x7f;
+ UINT16 charaddr = (column << 4) | cma;
+
+ return state->m_charram[charaddr];
+}
+
+static CDP1869_CHAR_RAM_WRITE( comx35_charram_w )
+{
+ comx35_state *state = device->machine().driver_data<comx35_state>();
+
+ UINT8 column = pmd & 0x7f;
+ UINT16 charaddr = (column << 4) | cma;
+
+ state->m_charram[charaddr] = data;
+}
+
+static CDP1869_PCB_READ( comx35_pcb_r )
+{
+ return BIT(pmd, 7);
+}
+
+WRITE_LINE_MEMBER( comx35_state::prd_w )
+{
+ if ((m_prd == CLEAR_LINE) && (state == ASSERT_LINE))
+ {
+ m_cr1 = m_iden ? CLEAR_LINE : ASSERT_LINE;
+ check_interrupt();
+ }
+
+ m_prd = state;
+
+ m_maincpu->set_input_line(COSMAC_INPUT_LINE_EF1, state);
+}
+
+static CDP1869_INTERFACE( pal_cdp1869_intf )
+{
+ SCREEN_TAG,
+ CDP1869_COLOR_CLK_PAL,
+ CDP1869_PAL,
+ comx35_pcb_r,
+ comx35_charram_r,
+ comx35_charram_w,
+ DEVCB_DRIVER_LINE_MEMBER(comx35_state, prd_w)
+};
+
+static CDP1869_INTERFACE( ntsc_cdp1869_intf )
+{
+ SCREEN_TAG,
+ CDP1869_COLOR_CLK_NTSC,
+ CDP1869_NTSC,
+ comx35_pcb_r,
+ comx35_charram_r,
+ comx35_charram_w,
+ DEVCB_DRIVER_LINE_MEMBER(comx35_state, prd_w)
+};
+
+void comx35_state::video_start()
+{
+ // allocate memory
+ m_charram = auto_alloc_array(machine(), UINT8, COMX35_CHARRAM_SIZE);
+
+ // register for save state
+ save_pointer(NAME(m_charram), COMX35_CHARRAM_SIZE);
+}
+
+UINT32 comx35_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ if (screen.width() == CDP1869_SCREEN_WIDTH)
+ {
+ m_vis->screen_update(screen, bitmap, cliprect);
+ }
+ else
+ {
+ m_expansion->screen_update(screen, bitmap, cliprect);
+ }
+
+ return 0;
+}
+
+/* Machine Drivers */
+
+MACHINE_CONFIG_FRAGMENT( comx35_pal_video )
+ MCFG_CDP1869_SCREEN_PAL_ADD(CDP1869_TAG, SCREEN_TAG, CDP1869_DOT_CLK_PAL)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_CDP1869_ADD(CDP1869_TAG, CDP1869_DOT_CLK_PAL, pal_cdp1869_intf, cdp1869_page_ram)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_SOUND_WAVE_ADD(WAVE_TAG, CASSETTE_TAG)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( comx35_ntsc_video )
+ MCFG_CDP1869_SCREEN_NTSC_ADD(CDP1869_TAG, SCREEN_TAG, CDP1869_DOT_CLK_NTSC)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_CDP1869_ADD(CDP1869_TAG, CDP1869_DOT_CLK_NTSC, ntsc_cdp1869_intf, cdp1869_page_ram)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_SOUND_WAVE_ADD(WAVE_TAG, CASSETTE_TAG)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/crt.c b/src/mess/video/crt.c
new file mode 100644
index 00000000000..2618d0d1ed0
--- /dev/null
+++ b/src/mess/video/crt.c
@@ -0,0 +1,223 @@
+/*
+ video/crt.c
+
+ CRT video emulation for TX-0 and PDP-1.
+
+
+Theory of operation:
+
+ What makes such CRT devices so odd is that there is no video processor, no
+ scan logic, no refresh logic. The beam position and intensity is
+ controlled by the program completely: in order to draw an object, the
+ program must direct the beam to each point of the object, and in order to
+ refresh it, the program must redraw the object periodically.
+
+ Since the refresh rates are highly variable (completely controlled by the
+ program), I need to simulate CRT remanence: the intensity of each pixel on
+ display decreases regularly. In order to keep this efficient, I keep a
+ list of non-black pixels, and only process these pixels on each refresh.
+ In order to improve efficiency further, I keep a distinct list for each
+ line of the display: I have found that it improves drawing speed slightly
+ (probably because it improves the cache hit rate).
+
+
+ Raphael Nabet 2002-2004
+ Based on earlier work by Chris Salomon
+*/
+
+#include <math.h>
+
+#include "emu.h"
+
+#include "video/crt.h"
+
+
+typedef struct
+{
+ int intensity; /* current intensity of the pixel */
+ /* a node is not in the list when (intensity == -1) */
+ int next; /* index of next pixel in list */
+} point;
+
+enum
+{
+ intensity_pixel_not_in_list = -1 /* special value that tells that the node is not in list */
+};
+
+typedef struct
+{
+ point *list; /* array of (crt_window_width*crt_window_height) point */
+ int *list_head; /* head of the list of lit pixels (index in the array) */
+ /* keep a separate list for each display line (makes the video code slightly faster) */
+
+ int decay_counter; /* incremented each frame (tells for how many frames the CRT has decayed between two screen refresh) */
+
+ /* CRT window */
+ int num_intensity_levels;
+ int window_offset_x, window_offset_y;
+ int window_width, window_height;
+} crt_t;
+
+
+INLINE crt_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == CRT);
+
+ return (crt_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+static DEVICE_START( crt )
+{
+ crt_t *crt = get_safe_token(device);
+ const crt_interface *intf = (const crt_interface *)device->static_config();
+ int width = intf->width;
+ int height = intf->height;
+ int i;
+
+ crt->num_intensity_levels = intf->num_levels;
+ crt->window_offset_x = intf->offset_x;
+ crt->window_offset_y = intf->offset_y;
+ crt->window_width = width;
+ crt->window_height = height;
+
+ /* alloc the arrays */
+ crt->list = auto_alloc_array(device->machine(), point, width * height);
+
+ crt->list_head = auto_alloc_array(device->machine(), int, height);
+
+ /* fill with black and set up list as empty */
+ for (i=0; i<(width * height); i++)
+ {
+ crt->list[i].intensity = intensity_pixel_not_in_list;
+ }
+
+ for (i=0; i<height; i++)
+ crt->list_head[i] = -1;
+
+ crt->decay_counter = 0;
+}
+
+
+DEVICE_GET_INFO( crt )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(crt_t); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(crt); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "CRT Video"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "CRT Video"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(CRT, crt);
+
+/*
+ crt_plot
+
+ schedule a pixel to be plotted
+*/
+void crt_plot(device_t *device, int x, int y)
+{
+ crt_t *crt = get_safe_token(device);
+ point *node;
+ int list_index;
+
+ /* compute pixel coordinates */
+ if (x<0) x=0;
+ if (y<0) y=0;
+ if ((x>(crt->window_width-1)) || ((y>crt->window_height-1)))
+ return;
+ y = (crt->window_height-1) - y;
+
+ /* find entry in list */
+ list_index = x + y*crt->window_width;
+
+ node = &crt->list[list_index];
+
+ if (node->intensity == intensity_pixel_not_in_list)
+ { /* insert node in list if it is not in it */
+ node->next = crt->list_head[y];
+ crt->list_head[y] = list_index;
+ }
+ /* set intensity */
+ node->intensity = crt->num_intensity_levels;
+}
+
+
+/*
+ crt_eof
+
+ keep track of time
+*/
+void crt_eof(device_t *device)
+{
+ crt_t *crt = get_safe_token(device);
+ crt->decay_counter++;
+}
+
+
+/*
+ crt_update
+
+ update the bitmap
+*/
+void crt_update(device_t *device, bitmap_ind16 &bitmap)
+{
+ crt_t *crt = get_safe_token(device);
+ int i, p_i;
+ int y;
+
+ //if (crt->decay_counter)
+ {
+ /* some time has elapsed: let's update the screen */
+ for (y=0; y<crt->window_height; y++)
+ {
+ UINT16 *line = &bitmap.pix16(y+crt->window_offset_y);
+
+ p_i = -1;
+
+ for (i=crt->list_head[y]; (i != -1); i=crt->list[i].next)
+ {
+ point *node = &crt->list[i];
+ int x = (i % crt->window_width) + crt->window_offset_x;
+
+ if (node->intensity == crt->num_intensity_levels)
+ /* new pixel: set to max intensity */
+ node->intensity = crt->num_intensity_levels-1;
+ else
+ {
+ /* otherwise, apply intensity decay */
+ node->intensity -= crt->decay_counter;
+ if (node->intensity < 0)
+ node->intensity = 0;
+ }
+
+ /* draw pixel on screen */
+ //plot_pixel(bitmap, x, y+crt->window_offset_y, node->intensity);
+ line[x] = node->intensity;
+
+ if (node->intensity != 0)
+ p_i = i; /* current node will be next iteration's previous node */
+ else
+ { /* delete current node */
+ node->intensity = intensity_pixel_not_in_list;
+ if (p_i != -1)
+ crt->list[p_i].next = node->next;
+ else
+ crt->list_head[y] = node->next;
+ }
+ }
+ }
+
+ crt->decay_counter = 0;
+ }
+}
diff --git a/src/mess/video/crt.h b/src/mess/video/crt.h
new file mode 100644
index 00000000000..fab211c9865
--- /dev/null
+++ b/src/mess/video/crt.h
@@ -0,0 +1,33 @@
+/*************************************************************************
+
+ video/crt.h
+
+ CRT video emulation for TX-0 and PDP-1
+
+*************************************************************************/
+
+#ifndef CRT_H_
+#define CRT_H_
+
+
+/*----------- defined in video/crt.c -----------*/
+
+typedef struct _crt_interface crt_interface;
+struct _crt_interface
+{
+ int num_levels;
+ int offset_x, offset_y;
+ int width, height;
+};
+
+void crt_plot(device_t *device, int x, int y);
+void crt_eof(device_t *device);
+void crt_update(device_t *device, bitmap_ind16 &bitmap);
+
+DECLARE_LEGACY_DEVICE(CRT, crt);
+
+#define MCFG_CRT_ADD(_tag, _interface) \
+ MCFG_DEVICE_ADD(_tag, CRT, 0) \
+ MCFG_DEVICE_CONFIG(_interface)
+
+#endif /* CRT_H_ */
diff --git a/src/mess/video/crtc_ega.c b/src/mess/video/crtc_ega.c
new file mode 100644
index 00000000000..478335fa408
--- /dev/null
+++ b/src/mess/video/crtc_ega.c
@@ -0,0 +1,695 @@
+/**********************************************************************
+
+ IBM EGA CRT Controller emulation
+
+ This controller is very loosely based on the mc6845.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "crtc_ega.h"
+
+
+#define LOG (1)
+
+
+const device_type CRTC_EGA = &device_creator<crtc_ega_device>;
+
+
+void crtc_ega_device::device_config_complete()
+{
+ const crtc_ega_interface *intf = reinterpret_cast<const crtc_ega_interface *>(static_config());
+
+ if ( intf != NULL )
+ {
+ *static_cast<crtc_ega_interface *>(this) = *intf;
+ }
+ else
+ {
+ m_screen_tag = NULL;
+ m_hpixels_per_column = 0;
+ m_begin_update = NULL;
+ m_update_row = NULL;
+ m_end_update = NULL;
+ memset(&m_out_de_func, 0, sizeof(m_out_de_func));
+ memset(&m_out_hsync_func, 0, sizeof(m_out_hsync_func));
+ memset(&m_out_vsync_func, 0, sizeof(m_out_vsync_func));
+ memset(&m_out_vblank_func, 0, sizeof(m_out_vblank_func));
+ }
+}
+
+
+crtc_ega_device::crtc_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, CRTC_EGA, "crtc_EGA", tag, owner, clock)
+{
+}
+
+
+void crtc_ega_device::device_post_load()
+{
+ recompute_parameters(true);
+}
+
+
+WRITE8_MEMBER( crtc_ega_device::address_w )
+{
+ m_register_address_latch = data & 0x1f;
+}
+
+
+READ8_MEMBER( crtc_ega_device::register_r )
+{
+ UINT8 ret = 0;
+
+ switch (m_register_address_latch)
+ {
+ case 0x0c: ret = (m_disp_start_addr >> 8) & 0xff; break;
+ case 0x0d: ret = (m_disp_start_addr >> 0) & 0xff; break;
+ case 0x0e: ret = (m_cursor_addr >> 8) & 0xff; break;
+ case 0x0f: ret = (m_cursor_addr >> 0) & 0xff; break;
+ case 0x10: ret = (m_light_pen_addr >> 8) & 0xff; m_light_pen_latched = FALSE; break;
+ case 0x11: ret = (m_light_pen_addr >> 0) & 0xff; m_light_pen_latched = FALSE; break;
+
+ /* all other registers are write only and return 0 */
+ default: break;
+ }
+
+ return ret;
+}
+
+
+WRITE8_MEMBER( crtc_ega_device::register_w )
+{
+ if (LOG) logerror("CRTC_EGA PC %04x: reg 0x%02x = 0x%02x\n", cpu_get_pc(machine().firstcpu), m_register_address_latch, data);
+
+ switch (m_register_address_latch)
+ {
+ case 0x00: m_horiz_char_total = data & 0xff; break;
+ case 0x01: m_horiz_disp = data & 0xff; break;
+ case 0x02: m_horiz_blank_start = data & 0xff; break;
+ case 0x03: m_horiz_blank_end = ((data & 0x1f) << 0) | (m_horiz_blank_end & 0x20);
+ m_de_skew = ((data & 0x60) >> 5);
+ m_ena_vert_access = data & 0x80;
+ break;
+ case 0x04: m_horiz_retr_start = data & 0xff; break;
+ case 0x05: m_horiz_retr_end = data & 0x1f;
+ m_horiz_retr_skew = ((data & 0x60) >> 5);
+ m_horiz_blank_end = ((data & 0x80) >> 2) | (m_horiz_blank_end & 0x1f);
+ break;
+ case 0x06: m_vert_total = ((data & 0xff) << 0) | (m_vert_total & 0x0300); break;
+ case 0x07: m_vert_total = ((data & 0x01) << 8) | (m_vert_total & 0x02ff);
+ m_vert_disp_end = ((data & 0x02) << 7) | (m_vert_disp_end & 0x02ff);
+ m_vert_retr_start = ((data & 0x04) << 6) | (m_vert_retr_start & 0x02ff);
+ m_vert_blank_start = ((data & 0x08) << 5) | (m_vert_blank_start & 0x02ff);
+ m_line_compare = ((data & 0x10) << 4) | (m_line_compare & 0x02ff);
+ m_vert_total = ((data & 0x20) << 4) | (m_vert_total & 0x01ff);
+ m_vert_disp_end = ((data & 0x40) << 3) | (m_vert_disp_end & 0x1ff);
+ m_vert_retr_start = ((data & 0x80) << 2) | (m_vert_retr_start & 0x01ff);
+ break;
+ case 0x08: m_preset_row_scan = data & 0x1f;
+ m_byte_panning = ((data & 0x60) >> 5);
+ break;
+ case 0x09: m_max_ras_addr = data & 0x1f;
+ m_vert_blank_start = ((data & 0x20) << 4) | (m_vert_blank_start & 0x01ff);
+ m_line_compare = ((data & 0x40) << 3) | (m_line_compare & 0x01ff);
+ m_scan_doubling = data & 0x80;
+ break;
+ case 0x0a: m_cursor_start_ras = data & 0x1f;
+ m_cursor_disable = data & 0x20;
+ break;
+ case 0x0b: m_cursor_end_ras = data & 0x1f;
+ m_cursor_skew = ((data & 0x60) >> 5);
+ break;
+ case 0x0c: m_disp_start_addr = ((data & 0xff) << 8) | (m_disp_start_addr & 0x00ff); break;
+ case 0x0d: m_disp_start_addr = ((data & 0xff) << 0) | (m_disp_start_addr & 0xff00); break;
+ case 0x0e: m_cursor_addr = ((data & 0xff) << 8) | (m_cursor_addr & 0x00ff); break;
+ case 0x0f: m_cursor_addr = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break;
+ case 0x10: m_vert_retr_start = ((data & 0xff) << 0) | (m_vert_retr_start & 0x0300); break;
+ case 0x11: m_vert_retr_end = data & 0x0f;
+ m_bandwidth = data & 0x40;
+ m_protect = data & 0x80;
+ break;
+ case 0x12: m_vert_disp_end = ((data & 0xff) << 0) | (m_vert_disp_end & 0x0300); break;
+ case 0x13: m_offset = data & 0xff; break;
+ case 0x14: m_underline_loc = data & 0x7f; break;
+ case 0x15: m_vert_blank_start = ((data & 0xff) << 0) | (m_vert_blank_start & 0x0300); break;
+ case 0x16: m_vert_blank_end = data & 0x7f; break;
+ case 0x17: m_mode_control = data & 0xff; break;
+ case 0x18: m_line_compare = ((data & 0xff) << 0) | (m_line_compare & 0x0300); break;
+ default: break;
+ }
+
+ recompute_parameters(false);
+}
+
+
+void crtc_ega_device::recompute_parameters(bool postload)
+{
+ UINT16 hsync_on_pos, hsync_off_pos, vsync_on_pos, vsync_off_pos;
+
+ /* compute the screen sizes */
+ UINT16 horiz_pix_total = (m_horiz_char_total + 2) * m_hpixels_per_column;
+ UINT16 vert_pix_total = m_vert_total + 1;
+
+ /* determine the visible area, avoid division by 0 */
+ UINT16 max_visible_x = ( m_horiz_disp + 1 ) * m_hpixels_per_column - 1;
+ UINT16 max_visible_y = m_vert_disp_end;
+
+ /* determine the syncing positions */
+ int horiz_sync_char_width = ( m_horiz_retr_end + 1 ) - ( m_horiz_retr_start & 0x1f );
+ int vert_sync_pix_width = m_vert_retr_end - ( m_vert_retr_start & 0x0f );
+
+ if (horiz_sync_char_width <= 0)
+ horiz_sync_char_width += 0x10;
+
+ if (vert_sync_pix_width <= 0)
+ vert_sync_pix_width += 0x10;
+
+ hsync_on_pos = m_horiz_retr_start * m_hpixels_per_column;
+ hsync_off_pos = hsync_on_pos + (horiz_sync_char_width * m_hpixels_per_column);
+ vsync_on_pos = m_vert_retr_start; /* + 1 ?? */
+ vsync_off_pos = vsync_on_pos + vert_sync_pix_width;
+
+ if (hsync_off_pos > horiz_pix_total)
+ hsync_off_pos = horiz_pix_total;
+
+ if (vsync_off_pos > vert_pix_total)
+ vsync_off_pos = vert_pix_total;
+
+ if ( vsync_on_pos >= vsync_off_pos )
+ {
+ vsync_on_pos = vsync_off_pos - 2;
+ }
+
+ /* update only if screen parameters changed, unless we are coming here after loading the saved state */
+ if (postload ||
+ (horiz_pix_total != m_horiz_pix_total) || (vert_pix_total != m_vert_pix_total) ||
+ (max_visible_x != m_max_visible_x) || (max_visible_y != m_max_visible_y) ||
+ (hsync_on_pos != m_hsync_on_pos) || (vsync_on_pos != m_vsync_on_pos) ||
+ (hsync_off_pos != m_hsync_off_pos) || (vsync_off_pos != m_vsync_off_pos))
+ {
+ /* update the screen if we have valid data */
+ if ((horiz_pix_total > 0) && (max_visible_x < horiz_pix_total) &&
+ (vert_pix_total > 0) && (max_visible_y < vert_pix_total) &&
+ (hsync_on_pos <= horiz_pix_total) && (vsync_on_pos <= vert_pix_total) &&
+ (hsync_on_pos != hsync_off_pos))
+ {
+ attoseconds_t refresh = HZ_TO_ATTOSECONDS(m_clock) * (m_horiz_char_total + 2) * vert_pix_total;
+
+ rectangle visarea(0, max_visible_x, 0, max_visible_y);
+
+ if (LOG) logerror("CRTC_EGA config screen: HTOTAL: 0x%x VTOTAL: 0x%x MAX_X: 0x%x MAX_Y: 0x%x HSYNC: 0x%x-0x%x VSYNC: 0x%x-0x%x Freq: %ffps\n",
+ horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
+
+ if ( m_screen != NULL )
+ m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh);
+
+ m_has_valid_parameters = true;
+ }
+ else
+ {
+ m_has_valid_parameters = false;
+ if (LOG) logerror("CRTC_EGA bad config screen: HTOTAL: 0x%x VTOTAL: 0x%x MAX_X: 0x%x MAX_Y: 0x%x HSYNC: 0x%x-0x%x VSYNC: 0x%x-0x%x\n",
+ horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1);
+
+ }
+
+ m_horiz_pix_total = horiz_pix_total;
+ m_vert_pix_total = vert_pix_total;
+ m_max_visible_x = max_visible_x;
+ m_max_visible_y = max_visible_y;
+ m_hsync_on_pos = hsync_on_pos;
+ m_hsync_off_pos = hsync_off_pos;
+ m_vsync_on_pos = vsync_on_pos;
+ m_vsync_off_pos = vsync_off_pos;
+ }
+}
+
+
+void crtc_ega_device::update_counters()
+{
+ m_character_counter = m_line_timer->elapsed().as_ticks( m_clock );
+
+ if ( m_hsync_off_timer->enabled() )
+ {
+ m_hsync_width_counter = m_hsync_off_timer->elapsed().as_ticks( m_clock );
+ }
+}
+
+
+void crtc_ega_device::set_de(int state)
+{
+ if ( m_de != state )
+ {
+ m_de = state;
+
+ if ( !m_res_out_de_func.isnull() )
+ m_res_out_de_func( m_de );
+ }
+}
+
+
+void crtc_ega_device::set_hsync(int state)
+{
+ if ( m_hsync != state )
+ {
+ m_hsync = state;
+
+ if ( !m_res_out_hsync_func.isnull() )
+ m_res_out_hsync_func( m_hsync );
+ }
+}
+
+
+void crtc_ega_device::set_vsync(int state)
+{
+ if ( m_vsync != state )
+ {
+ m_vsync = state;
+
+ if ( !m_res_out_vsync_func.isnull() )
+ m_res_out_vsync_func( m_vsync );
+ }
+}
+
+
+void crtc_ega_device::set_vblank(int state)
+{
+ if ( m_vblank != state )
+ {
+ m_vblank = state;
+
+ if ( !m_res_out_vblank_func.isnull() )
+ m_res_out_vblank_func( m_vblank );
+ }
+}
+
+
+void crtc_ega_device::set_cur(int state)
+{
+ if ( m_cur != state )
+ {
+ m_cur = state;
+
+// if ( !m_res_out_cur_func.isnull() )
+// m_res_out_cur_func( m_cur );
+ }
+}
+
+
+void crtc_ega_device::handle_line_timer()
+{
+ int new_vsync = m_vsync;
+
+ m_character_counter = 0;
+ m_cursor_x = -1;
+
+ /* Check if VSYNC is active */
+ if ( m_vsync_ff )
+ {
+ m_vsync_width_counter = ( m_vsync_width_counter + 1 ) & 0x0F;
+
+ /* Check if we've reached end of VSYNC */
+ if ( m_vsync_width_counter == m_vert_retr_end )
+ {
+ m_vsync_ff = 0;
+
+ new_vsync = FALSE;
+ }
+ }
+
+ if ( m_raster_counter == m_max_ras_addr )
+ {
+ m_raster_counter = 0;
+ m_line_address = ( m_line_address + m_horiz_disp + 1 ) & 0xffff;
+ }
+ else
+ {
+ m_raster_counter = ( m_raster_counter + 1 ) & 0x1F;
+ }
+
+ m_line_counter = ( m_line_counter + 1 ) & 0x3ff;
+
+ /* Check if we've reached the end of active display */
+ if ( m_line_counter == m_vert_disp_end )
+ {
+ m_line_enable_ff = false;
+ }
+
+ /* Check if VSYNC should be enabled */
+ if ( m_line_counter == m_vert_retr_start )
+ {
+ m_vsync_width_counter = 0;
+ m_vsync_ff = 1;
+
+ new_vsync = TRUE;
+ }
+
+ /* Check if we have reached the end of the vertical area */
+ if ( m_line_counter == m_vert_total )
+ {
+ m_line_counter = 0;
+ m_line_address = m_disp_start_addr;
+ m_line_enable_ff = true;
+ set_vblank( FALSE );
+ /* also update the cursor state now */
+ update_cursor_state();
+
+ if (m_screen != NULL)
+ m_screen->reset_origin();
+ }
+
+ if ( m_line_enable_ff )
+ {
+ /* Schedule DE off signal change */
+ m_de_off_timer->adjust(attotime::from_ticks( m_horiz_disp + 1, m_clock ));
+
+ /* Is cursor visible on this line? */
+ if ( m_cursor_state &&
+ (m_raster_counter >= (m_cursor_start_ras & 0x1f)) &&
+ (m_raster_counter <= m_cursor_end_ras) &&
+ (m_cursor_addr >= m_line_address) &&
+ (m_cursor_addr < (m_line_address + m_horiz_disp + 1)) )
+ {
+ m_cursor_x = m_cursor_addr - m_line_address;
+
+ /* Schedule CURSOR ON signal */
+ m_cur_on_timer->adjust( attotime::from_ticks( m_cursor_x, m_clock ) );
+ }
+ }
+
+ /* Schedule HSYNC on signal */
+ m_hsync_on_timer->adjust( attotime::from_ticks( m_horiz_blank_start, m_clock ) );
+
+ /* Set VBlank signal */
+ if ( m_line_counter == m_vert_disp_end + 1 )
+ {
+ set_vblank( TRUE );
+ }
+
+ /* Schedule our next callback */
+ m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 2, m_clock ) );
+
+ /* Set VSYNC and DE signals */
+ set_vsync( new_vsync );
+ set_de( m_line_enable_ff ? TRUE : FALSE );
+}
+
+
+void crtc_ega_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_LINE:
+ handle_line_timer();
+ break;
+
+ case TIMER_DE_OFF:
+ set_de( FALSE );
+ break;
+
+ case TIMER_CUR_ON:
+ set_cur( TRUE );
+
+ /* Schedule CURSOR off signal */
+ m_cur_off_timer->adjust( attotime::from_ticks( 1, m_clock ) );
+ break;
+
+ case TIMER_CUR_OFF:
+ set_cur( FALSE );
+ break;
+
+ case TIMER_HSYNC_ON:
+ {
+ INT8 hsync_width = ( 0x20 | m_horiz_blank_end ) - ( m_horiz_blank_start & 0x1f );
+
+ if ( hsync_width <= 0 )
+ {
+ hsync_width += 0x20;
+ }
+
+ m_hsync_width_counter = 0;
+ set_hsync( TRUE );
+
+ /* Schedule HSYNC off signal */
+ m_hsync_off_timer->adjust( attotime::from_ticks( hsync_width, m_clock ) );
+ }
+ break;
+
+ case TIMER_HSYNC_OFF:
+ set_hsync( FALSE );
+ break;
+
+ case TIMER_LIGHT_PEN_LATCH:
+ m_light_pen_addr = get_ma();
+ m_light_pen_latched = true;
+ break;
+ }
+}
+
+
+UINT16 crtc_ega_device::get_ma()
+{
+ update_counters();
+
+ return m_line_address + m_character_counter;
+}
+
+
+UINT8 crtc_ega_device::get_ra()
+{
+ return m_raster_counter;
+}
+
+
+void crtc_ega_device::assert_light_pen_input()
+{
+ /* compute the pixel coordinate of the NEXT character -- this is when the light pen latches */
+ /* set the timer that will latch the display address into the light pen registers */
+ m_light_pen_latch_timer->adjust(attotime::from_ticks( 1, m_clock ));
+}
+
+
+void crtc_ega_device::set_clock(int clock)
+{
+ /* validate arguments */
+ assert(clock > 0);
+
+ if (clock != m_clock)
+ {
+ m_clock = clock;
+ recompute_parameters(true);
+ }
+}
+
+
+void crtc_ega_device::set_hpixels_per_column(int hpixels_per_column)
+{
+ /* validate arguments */
+ assert(hpixels_per_column > 0);
+
+ if (hpixels_per_column != m_hpixels_per_column)
+ {
+ m_hpixels_per_column = hpixels_per_column;
+ recompute_parameters(true);
+ }
+}
+
+
+void crtc_ega_device::update_cursor_state()
+{
+ /* save and increment cursor counter */
+ UINT8 last_cursor_blink_count = m_cursor_blink_count;
+ m_cursor_blink_count = m_cursor_blink_count + 1;
+
+ /* switch on cursor blinking mode */
+ switch (m_cursor_start_ras & 0x60)
+ {
+ /* always on */
+ case 0x00: m_cursor_state = true; break;
+
+ /* always off */
+ case 0x20: m_cursor_state = false; break;
+
+ /* fast blink */
+ case 0x40:
+ if ((last_cursor_blink_count & 0x10) != (m_cursor_blink_count & 0x10))
+ {
+ m_cursor_state = !m_cursor_state;
+ }
+ break;
+
+ /* slow blink */
+ case 0x60:
+ if ((last_cursor_blink_count & 0x20) != (m_cursor_blink_count & 0x20))
+ {
+ m_cursor_state = !m_cursor_state;
+ }
+ break;
+ }
+}
+
+
+UINT32 crtc_ega_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ assert(bitmap.valid());
+
+ if (m_has_valid_parameters)
+ {
+ UINT16 y;
+
+ void *param = NULL;
+
+ assert(m_update_row != NULL);
+
+ /* call the set up function if any */
+ if (m_begin_update != NULL)
+ param = m_begin_update(this, bitmap, cliprect);
+
+ if (cliprect.min_y == 0)
+ {
+ /* read the start address at the beginning of the frame */
+ m_current_disp_addr = m_disp_start_addr;
+ }
+
+ /* for each row in the visible region */
+ for (y = cliprect.min_y; y <= cliprect.max_y; y++)
+ {
+ /* compute the current raster line */
+ UINT8 ra = y % (m_max_ras_addr + 1);
+
+ /* check if the cursor is visible and is on this scanline */
+ int cursor_visible = m_cursor_state &&
+ (ra >= (m_cursor_start_ras & 0x1f)) &&
+ ( (ra <= (m_cursor_end_ras & 0x1f)) || ((m_cursor_end_ras & 0x1f) == 0x00 )) &&
+ (m_cursor_addr >= m_current_disp_addr) &&
+ (m_cursor_addr < (m_current_disp_addr + ( m_horiz_disp + 1 )));
+
+ /* compute the cursor X position, or -1 if not visible */
+ INT8 cursor_x = cursor_visible ? (m_cursor_addr - m_current_disp_addr) : -1;
+
+ /* call the external system to draw it */
+ m_update_row(this, bitmap, cliprect, m_current_disp_addr, ra, y, m_horiz_disp + 1, cursor_x, param);
+
+ /* update MA if the last raster address */
+ if (ra == m_max_ras_addr)
+ m_current_disp_addr = (m_current_disp_addr + m_horiz_disp + 1) & 0xffff;
+ }
+
+ /* call the tear down function if any */
+ if (m_end_update != NULL)
+ m_end_update(this, bitmap, cliprect, param);
+ }
+ else
+ logerror("Invalid crtc_ega screen parameters - display disabled!!!\n");
+
+ return 0;
+}
+
+
+/* device interface */
+void crtc_ega_device::device_start()
+{
+ /* validate arguments */
+ assert(m_clock > 0);
+ assert(m_hpixels_per_column > 0);
+
+ /* resolve callbacks */
+ m_res_out_de_func.resolve(m_out_de_func, *this);
+ m_res_out_hsync_func.resolve(m_out_hsync_func, *this);
+ m_res_out_vsync_func.resolve(m_out_vsync_func, *this);
+ m_res_out_vblank_func.resolve(m_out_vblank_func, *this);
+
+ /* get the screen device */
+ if ( m_screen_tag != NULL )
+ {
+ astring tempstring;
+ m_screen = downcast<screen_device *>(machine().device(siblingtag(tempstring,m_screen_tag)));
+ assert(m_screen != NULL);
+ }
+ else
+ m_screen = NULL;
+
+ /* create the timers */
+ m_line_timer = timer_alloc(TIMER_LINE);
+ m_de_off_timer = timer_alloc(TIMER_DE_OFF);
+ m_cur_on_timer = timer_alloc(TIMER_CUR_ON);
+ m_cur_off_timer = timer_alloc(TIMER_CUR_OFF);
+ m_hsync_on_timer = timer_alloc(TIMER_HSYNC_ON);
+ m_hsync_off_timer = timer_alloc(TIMER_HSYNC_OFF);
+ m_light_pen_latch_timer = timer_alloc(TIMER_LIGHT_PEN_LATCH);
+
+ /* Use some large startup values */
+ m_horiz_char_total = 0xff;
+ m_max_ras_addr = 0x1f;
+ m_vert_total = 0x3ff;
+
+ /* register for state saving */
+ save_item(NAME(m_hpixels_per_column));
+ save_item(NAME(m_register_address_latch));
+ save_item(NAME(m_horiz_char_total));
+ save_item(NAME(m_horiz_disp));
+ save_item(NAME(m_horiz_blank_start));
+ save_item(NAME(m_mode_control));
+ save_item(NAME(m_cursor_start_ras));
+ save_item(NAME(m_cursor_end_ras));
+ save_item(NAME(m_disp_start_addr));
+ save_item(NAME(m_cursor_addr));
+ save_item(NAME(m_light_pen_addr));
+ save_item(NAME(m_light_pen_latched));
+ save_item(NAME(m_cursor_state));
+ save_item(NAME(m_cursor_blink_count));
+ save_item(NAME(m_horiz_blank_end));
+ save_item(NAME(m_ena_vert_access));
+ save_item(NAME(m_de_skew));
+ save_item(NAME(m_horiz_retr_start));
+ save_item(NAME(m_horiz_retr_end));
+ save_item(NAME(m_horiz_retr_skew));
+ save_item(NAME(m_vert_total));
+ save_item(NAME(m_preset_row_scan));
+ save_item(NAME(m_byte_panning));
+ save_item(NAME(m_max_ras_addr));
+ save_item(NAME(m_scan_doubling));
+ save_item(NAME(m_cursor_disable));
+ save_item(NAME(m_cursor_skew));
+ save_item(NAME(m_vert_retr_start));
+ save_item(NAME(m_vert_retr_end));
+ save_item(NAME(m_protect));
+ save_item(NAME(m_bandwidth));
+ save_item(NAME(m_vert_disp_end));
+ save_item(NAME(m_offset));
+ save_item(NAME(m_underline_loc));
+ save_item(NAME(m_vert_blank_start));
+ save_item(NAME(m_vert_blank_end));
+ save_item(NAME(m_line_compare));
+}
+
+
+void crtc_ega_device::device_reset()
+{
+ /* internal registers other than status remain unchanged, all outputs go low */
+ if ( !m_res_out_de_func.isnull() )
+ m_res_out_de_func( FALSE );
+
+ if ( !m_res_out_hsync_func.isnull() )
+ m_res_out_hsync_func( FALSE );
+
+ if ( !m_res_out_vsync_func.isnull() )
+ m_res_out_vsync_func( FALSE );
+
+ if ( !m_res_out_vblank_func.isnull() )
+ m_res_out_vblank_func( FALSE );
+
+ if ( ! m_line_timer->enabled( ) )
+ {
+ m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 2, m_clock ) );
+ }
+
+ m_light_pen_latched = false;
+
+ m_cursor_addr = 0;
+ m_line_address = 0;
+ m_horiz_disp = 0;
+ m_cursor_x = 0;
+}
+
diff --git a/src/mess/video/crtc_ega.h b/src/mess/video/crtc_ega.h
new file mode 100644
index 00000000000..3a25b6e1095
--- /dev/null
+++ b/src/mess/video/crtc_ega.h
@@ -0,0 +1,226 @@
+/**********************************************************************
+
+ IBM EGA CRT Controller emulation
+
+**********************************************************************/
+
+#ifndef __CRTC_EGA__
+#define __CRTC_EGA__
+
+#include "emu.h"
+#include "machine/devhelpr.h"
+
+#define CRTC_EGA_INTERFACE(name) \
+ const crtc_ega_interface (name) =
+
+#define MCFG_CRTC_EGA_ADD(_tag, _clock, _intrf) \
+ MCFG_DEVICE_ADD(_tag, CRTC_EGA, _clock) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+
+class crtc_ega_device;
+
+/* callback definitions */
+typedef void * (*crtc_ega_begin_update_func)(crtc_ega_device *device, bitmap_ind16 &bitmap, const rectangle &cliprect);
+#define CRTC_EGA_BEGIN_UPDATE(name) void *name(crtc_ega_device *device, bitmap_ind16 &bitmap, const rectangle &cliprect)
+
+typedef void (*crtc_ega_update_row_func)(crtc_ega_device *device, bitmap_ind16 &bitmap,
+ const rectangle &cliprect, UINT16 ma, UINT8 ra,
+ UINT16 y, UINT8 x_count, INT8 cursor_x, void *param);
+#define CRTC_EGA_UPDATE_ROW(name) void name(crtc_ega_device *device, bitmap_ind16 &bitmap, \
+ const rectangle &cliprect, UINT16 ma, UINT8 ra, \
+ UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+
+typedef void (*crtc_ega_end_update_func)(crtc_ega_device *device, bitmap_ind16 &bitmap, const rectangle &cliprect, void *param);
+#define CRTC_EGA_END_UPDATE(name) void name(crtc_ega_device *device, bitmap_ind16 &bitmap, const rectangle &cliprect, void *param)
+
+
+/* interface */
+typedef struct _crtc_ega_interface crtc_ega_interface;
+struct _crtc_ega_interface
+{
+ const char *m_screen_tag; /* screen we are acting on */
+ int m_hpixels_per_column; /* number of pixels per video memory address */
+
+ /* if specified, this gets called before any pixel update,
+ optionally return a pointer that will be passed to the
+ update and tear down callbacks */
+ crtc_ega_begin_update_func m_begin_update;
+
+ /* this gets called for every row, the driver must output
+ x_count * hpixels_per_column pixels.
+ cursor_x indicates the character position where the cursor is, or -1
+ if there is no cursor on this row */
+ crtc_ega_update_row_func m_update_row;
+
+ /* if specified, this gets called after all row updating is complete */
+ crtc_ega_end_update_func m_end_update;
+
+ /* if specified, this gets called for every change of the disply enable signal */
+ devcb_write_line m_out_de_func;
+
+ /* if specified, this gets called for every change of the HSYNC signal */
+ devcb_write_line m_out_hsync_func;
+
+ /* if specified, this gets called for every change of the VSYNC signal */
+ devcb_write_line m_out_vsync_func;
+
+ devcb_write_line m_out_vblank_func;
+};
+
+
+class crtc_ega_device : public device_t,
+ public crtc_ega_interface
+{
+public:
+ crtc_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ /* select one of the registers for reading or writing */
+ DECLARE_WRITE8_MEMBER( address_w );
+
+ /* read from the currently selected register */
+ DECLARE_READ8_MEMBER( register_r );
+
+ /* write to the currently selected register */
+ DECLARE_WRITE8_MEMBER( register_w );
+
+ /* return the current value on the MA0-MA15 pins */
+ UINT16 get_ma();
+
+ /* return the current value on the RA0-RA4 pins */
+ UINT8 get_ra();
+
+ /* simulates the LO->HI clocking of the light pen pin */
+ void assert_light_pen_input();
+
+ /* set the clock of the chip */
+ void set_clock(int clock);
+
+ /* set number of pixels per video memory address */
+ void set_hpixels_per_column(int hpixels_per_column);
+
+ /* updates the screen -- this will call begin_update(), */
+ /* followed by update_row() reapeatedly and after all row */
+ /* updating is complete, end_update() */
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_post_load();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ screen_device *m_screen;
+
+ devcb_resolved_write_line m_res_out_de_func;
+ devcb_resolved_write_line m_res_out_cur_func;
+ devcb_resolved_write_line m_res_out_hsync_func;
+ devcb_resolved_write_line m_res_out_vsync_func;
+ devcb_resolved_write_line m_res_out_vblank_func;
+
+ /* ega/vga register file */
+ UINT8 m_horiz_char_total; /* 0x00 */
+ UINT8 m_horiz_disp; /* 0x01 */
+ UINT8 m_horiz_blank_start; /* 0x02 */
+ UINT8 m_horiz_blank_end; /* 0x03/0x05 */
+ UINT8 m_ena_vert_access; /* 0x03 */
+ UINT8 m_de_skew; /* 0x03 */
+ UINT8 m_horiz_retr_start; /* 0x04 */
+ UINT8 m_horiz_retr_end; /* 0x05 */
+ UINT8 m_horiz_retr_skew; /* 0x05 */
+ UINT16 m_vert_total; /* 0x06/0x07 */
+ UINT8 m_preset_row_scan; /* 0x08 */
+ UINT8 m_byte_panning; /* 0x08 */
+ UINT8 m_max_ras_addr; /* 0x09 */
+ UINT8 m_scan_doubling; /* 0x09 */
+ UINT8 m_cursor_start_ras; /* 0x0a */
+ UINT8 m_cursor_disable; /* 0x0a */
+ UINT8 m_cursor_end_ras; /* 0x0b */
+ UINT8 m_cursor_skew; /* 0x0b */
+ UINT16 m_disp_start_addr; /* 0x0c/0x0d */
+ UINT16 m_cursor_addr; /* 0x0e/0x0f */
+ UINT16 m_light_pen_addr; /* 0x10/0x11 */
+ UINT16 m_vert_retr_start; /* 0x10/0x07 */
+ UINT8 m_vert_retr_end; /* 0x11 */
+ UINT8 m_protect; /* 0x11 */
+ UINT8 m_bandwidth; /* 0x11 */
+ UINT16 m_vert_disp_end; /* 0x12/0x07 */
+ UINT8 m_offset; /* 0x13 */
+ UINT8 m_underline_loc; /* 0x14 */
+ UINT16 m_vert_blank_start; /* 0x15/0x07/0x09 */
+ UINT8 m_vert_blank_end; /* 0x16 */
+ UINT8 m_mode_control; /* 0x17 */
+ UINT16 m_line_compare; /* 0x18/0x07/0x09 */
+
+ /* other internal state */
+ UINT8 m_register_address_latch;
+ UINT8 m_hpixels_per_column;
+ bool m_cursor_state; /* 0 = off, 1 = on */
+ UINT8 m_cursor_blink_count;
+
+ /* output signals */
+ int m_cur;
+ int m_hsync;
+ int m_vsync;
+ int m_vblank;
+ int m_de;
+
+ /* internal counters */
+ UINT8 m_character_counter;
+ UINT8 m_hsync_width_counter;
+ UINT16 m_line_counter;
+ UINT8 m_raster_counter;
+ UINT8 m_vsync_width_counter;
+ bool m_line_enable_ff; /* Internal flip flop which is set when the line_counter is reset and reset when vert_disp is reached */
+ UINT8 m_vsync_ff;
+ UINT8 m_adjust_active;
+ UINT16 m_line_address;
+ INT16 m_cursor_x;
+
+ /* timers */
+ static const device_timer_id TIMER_LINE = 0;
+ static const device_timer_id TIMER_DE_OFF = 1;
+ static const device_timer_id TIMER_CUR_ON = 2;
+ static const device_timer_id TIMER_CUR_OFF = 3;
+ static const device_timer_id TIMER_HSYNC_ON = 4;
+ static const device_timer_id TIMER_HSYNC_OFF = 5;
+ static const device_timer_id TIMER_LIGHT_PEN_LATCH = 6;
+
+ emu_timer *m_line_timer;
+ emu_timer *m_de_off_timer;
+ emu_timer *m_cur_on_timer;
+ emu_timer *m_cur_off_timer;
+ emu_timer *m_hsync_on_timer;
+ emu_timer *m_hsync_off_timer;
+ emu_timer *m_light_pen_latch_timer;
+
+ /* computed values - do NOT state save these! */
+ UINT16 m_horiz_pix_total;
+ UINT16 m_vert_pix_total;
+ UINT16 m_max_visible_x;
+ UINT16 m_max_visible_y;
+ UINT16 m_hsync_on_pos;
+ UINT16 m_hsync_off_pos;
+ UINT16 m_vsync_on_pos;
+ UINT16 m_vsync_off_pos;
+ UINT16 m_current_disp_addr; /* the display address currently drawn */
+ UINT8 m_light_pen_latched;
+ bool m_has_valid_parameters;
+
+ void recompute_parameters(bool postload);
+ void update_counters();
+ void set_de(int state);
+ void set_hsync(int state);
+ void set_vsync(int state);
+ void set_vblank(int state);
+ void set_cur(int state);
+ void handle_line_timer();
+ void update_cursor_state();
+};
+
+extern const device_type CRTC_EGA;
+
+#endif
diff --git a/src/mess/video/dai.c b/src/mess/video/dai.c
new file mode 100644
index 00000000000..75868ac5224
--- /dev/null
+++ b/src/mess/video/dai.c
@@ -0,0 +1,768 @@
+/***************************************************************************
+
+ dai.c
+
+ Functions to emulate the video hardware of DAI.
+
+ Krzysztof Strzecha
+
+ All video modes are emulated but not fully tested yet.
+ SCREEN_UPDATE_IND16 function needs strong cleanup and optimalisation.
+
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/dai.h"
+
+#define DEBUG_DAI_VIDEO 0
+
+#define LOG_DAI_VIDEO_LINE(_mode, _unit, _resolution, _repeat, _scan) do { if (DEBUG_DAI_VIDEO) logerror ("Mode: %02x, Unit: %02x, Resolution: %02x, Repeat: %d, Current line: %d\n", _mode, _unit, _resolution, _repeat, _scan); } while (0)
+
+const unsigned char dai_palette[16*3] =
+{
+ 0x00, 0x00, 0x00, /* 0 Black */
+ 0x00, 0x00, 0x8b, /* 1 Dark Blue */
+ 0xb1, 0x00, 0x95, /* 2 Purple Red */
+ 0xff, 0x00, 0x00, /* 3 Red */
+ 0x75, 0x2e, 0x50, /* 4 Purple Brown */
+ 0x00, 0xb2, 0x38, /* 5 Emerald Green */
+ 0x98, 0x62, 0x00, /* 6 Kakhi Brown */
+ 0xae, 0x7a, 0x00, /* 7 Mustard Brown */
+ 0x89, 0x89, 0x89, /* 8 Grey */
+ 0xa1, 0x6f, 0xff, /* 9 Middle Blue */
+ 0xff, 0xa5, 0x00, /* 10 Orange */
+ 0xff, 0x99, 0xff, /* 11 Pink */
+ 0x9e, 0xf4, 0xff, /* 12 Light Blue */
+ 0xb3, 0xff, 0xbb, /* 13 Light Green */
+ 0xff, 0xff, 0x28, /* 14 Light Yellow */
+ 0xff, 0xff, 0xff, /* 15 White */
+};
+
+
+PALETTE_INIT( dai )
+{
+ int i;
+
+ for ( i = 0; i < sizeof(dai_palette) / 3; i++ )
+ {
+ palette_set_color_rgb(machine, i, dai_palette[i * 3], dai_palette[i * 3 + 1], dai_palette[i * 3 + 2]);
+ }
+}
+
+
+VIDEO_START( dai )
+{
+}
+
+SCREEN_UPDATE_IND16( dai )
+{
+ dai_state *state = screen.machine().driver_data<dai_state>();
+ address_space *space = screen.machine().device("maincpu")->memory().space(AS_PROGRAM);
+ int i, j, k, l;
+
+ UINT8* char_rom = state->memregion("gfx1")->base();
+
+ UINT16 dai_video_memory_start = 0xbfff;
+ UINT16 dai_scan_lines = 604; /* scan lines of PAL tv */
+
+ UINT16 current_scan_line = 0;
+ UINT16 current_video_memory_address = dai_video_memory_start;
+
+ UINT8 mode; /* mode byte of line
+ bits 0-3 - line repeat count
+ bits 4-5 - resolution control
+ bits 6-7 - display mode control */
+ UINT8 colour; /* colour byte of line
+ bits 0-3 - one of 16 colours
+ bits 4-5 - colour register for update
+ bit 6 - if unset force 'unit colour mode'
+ bit 7 - enable coulor change
+ if unset bits 0-5 are ignored */
+ UINT8 line_repeat_count; /* number of horizontalraster scans
+ for which same data will be displayed
+ 0000 - 2 lines
+ each additional repeat adds 2 scans */
+ UINT8 horizontal_resolution; /* number of blobs per line
+ 00 - 88 (low resolution graphics)
+ 01 - 176 (medium resolution graphics)
+ 10 - 352 (high resolution graphics)
+ 11 - 528 (text with 66 chars per line) */
+ UINT8 display_mode; /* determine how data will be used
+ to generate the picture
+ 00 - four colour graphics
+ 01 - four colour characters
+ 10 - sixteen colour graphics
+ 11 - sixteen colour characters */
+ UINT8 unit_mode;
+
+ UINT8 current_data_1, current_data_2;
+
+ UINT8 current_colour;
+
+ while (current_scan_line < dai_scan_lines)
+ {
+ mode = space->read_byte(current_video_memory_address--);
+ colour = space->read_byte(current_video_memory_address--);
+ line_repeat_count = mode & 0x0f;
+ horizontal_resolution = (mode & 0x30) >> 4;
+ display_mode = (mode & 0xc0) >> 6;
+ unit_mode = (colour & 0x40) >> 6;
+
+ if (colour & 0x80)
+ state->m_4_colours_palette[(colour & 0x30) >> 4] = colour & 0x0f;
+
+ switch (display_mode)
+ {
+
+ case 0x00: /* 4 colour grahics modes */
+ switch (horizontal_resolution)
+ {
+
+ case 0x00: /* 88 pixels */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+
+ for (i=0; i<11; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_1>>(7-k)) & 0x01)<<1) | ((current_data_2>>(7-k)) & 0x01)];
+ for (l=0; l<12; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*12+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ case 1:
+ for (i=0; i<11; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_1>>(7-k)) & 0x01)<<1) | ((current_data_2>>(7-k)) & 0x01)];
+ for (l=0; l<12; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*12+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+
+ case 0x01: /* 176 pixels */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<22; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_1>>(7-k)) & 0x01)<<1) | ((current_data_2>>(7-k)) & 0x01)];
+ for (l=0; l<6; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*6+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ case 1:
+ for (i=0; i<22; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_1>>(7-k)) & 0x01)<<1) | ((current_data_2>>(7-k)) & 0x01)];
+ for (l=0; l<6; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*6+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+
+ case 0x02: /* 352 pixels */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<44; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_1>>(7-k)) & 0x01)<<1) | ((current_data_2>>(7-k)) & 0x01)];
+ for (l=0; l<3; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*3+l) = current_colour;
+ }
+ }
+ }
+ break;
+ case 1:
+ for (i=0; i<44; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_1>>(7-k)) & 0x01)<<1) | ((current_data_2>>(7-k)) & 0x01)];
+ for (l=0; l<3; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*3+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+
+ case 0x03: /* 528 pixels */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<66; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_1>>(7-k)) & 0x01)<<1) | ((current_data_2>>(7-k)) & 0x01)];
+ for (l=0; l<2; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*2+l) = current_colour;
+ }
+ }
+ }
+ break;
+ case 1:
+ for (i=0; i<66; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_1>>(7-k)) & 0x01)<<1) | ((current_data_2>>(7-k)) & 0x01)];
+ for (l=0; l<2; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*2+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 0x01: /* 4 colour characters */
+ switch (horizontal_resolution)
+ {
+
+ case 0x00: /* 11 chars */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address);
+ current_data_2 = space->read_byte(current_video_memory_address-1);
+ current_video_memory_address-=2;
+ for (i=0; i<11; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_2 >> k)&0x01)<<1) | ((char_rom[current_data_1*16+j]>>k) & 0x01)];
+ for (l=0; l<12; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*12+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ case 1:
+ for (i=0; i<11; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address);
+ current_data_2 = space->read_byte(current_video_memory_address-1);
+ current_video_memory_address-=2;
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_2 >> k)&0x01)<<1) | ((char_rom[current_data_1*16+j]>>k) & 0x01)];
+ for (l=0; l<12; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*12+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ }
+ break;
+ case 0x01: /* 22 chars */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address);
+ current_data_2 = space->read_byte(current_video_memory_address-1);
+ current_video_memory_address-=2;
+ for (i=0; i<22; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_2 >> k)&0x01)<<1) | ((char_rom[current_data_1*16+j]>>k) & 0x01)];
+ for (l=0; l<6; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*6+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ case 1:
+ for (i=0; i<22; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address);
+ current_data_2 = space->read_byte(current_video_memory_address-1);
+ current_video_memory_address-=2;
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_2 >> k)&0x01)<<1) | ((char_rom[current_data_1*16+j]>>k) & 0x01)];
+ for (l=0; l<6; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*6+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ }
+ break;
+ case 0x02: /* 44 chars */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address);
+ current_data_2 = space->read_byte(current_video_memory_address-1);
+ current_video_memory_address-=2;
+ for (i=0; i<44; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_2 >> k)&0x01)<<1) | ((char_rom[current_data_1*16+j]>>k) & 0x01)];
+ for (l=0; l<3; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*3+l) = current_colour;
+ }
+ }
+ }
+ break;
+ case 1:
+ for (i=0; i<44; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address);
+ current_data_2 = space->read_byte(current_video_memory_address-1);
+ current_video_memory_address-=2;
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_2 >> k)&0x01)<<1) | ((char_rom[current_data_1*16+j]>>k) & 0x01)];
+ for (l=0; l<3; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*3+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case 0x03: /* 66 chars */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address);
+ current_data_2 = space->read_byte(current_video_memory_address-1);
+ current_video_memory_address-=2;
+ for (i=0; i<66; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_2 >> k)&0x01)<<1) | ((char_rom[current_data_1*16+j]>>k) & 0x01)];
+ for (l=0; l<2; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*2+l) = current_colour;
+ }
+ }
+ }
+ break;
+ case 1:
+ for (i=0; i<66; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address);
+ current_data_2 = space->read_byte(current_video_memory_address-1);
+ current_video_memory_address-=2;
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = state->m_4_colours_palette[(((current_data_2 >> k)&0x01)<<1) | ((char_rom[current_data_1*16+j]>>k) & 0x01)];
+ for (l=0; l<2; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*2+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case 0x02: /* 16 colour graphics */
+ switch (horizontal_resolution)
+ {
+
+ case 0x00: /* 88 pixels */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+
+ for (i=0; i<11; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((current_data_1>>(7-k)) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<12; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*12+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ case 1:
+ for (i=0; i<11; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((current_data_1>>(7-k)) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<12; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*12+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+
+ case 0x01: /* 176 pixels */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<22; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((current_data_1>>(7-k)) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<6; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*6+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ case 1:
+ for (i=0; i<22; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((current_data_1>>(7-k)) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<6; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*6+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+
+ case 0x02: /* 352 pixels */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<44; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((current_data_1>>(7-k)) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<3; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*3+l) = current_colour;
+ }
+ }
+ }
+ break;
+ case 1:
+ for (i=0; i<44; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((current_data_1>>(7-k)) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<3; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*3+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+
+ case 0x03: /* 528 pixels */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<66; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((current_data_1>>(7-k)) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<2; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*2+l) = current_colour;
+ }
+ }
+ }
+ break;
+ case 1:
+ for (i=0; i<66; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((current_data_1>>(7-k)) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<2; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*2+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case 0x03: /* 16 colour characters */
+ switch (horizontal_resolution)
+ {
+
+ case 0x00: /* 11 chars */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<11; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((char_rom[current_data_1*16+j]>>k) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<12; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*12+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ case 1:
+ for (i=0; i<11; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((char_rom[current_data_1*16+j]>>k) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<12; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*12+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ }
+ break;
+ case 0x01: /* 22 chars */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<22; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((char_rom[current_data_1*16+j]>>k) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<6; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*6+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ case 1:
+ for (i=0; i<22; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((char_rom[current_data_1*16+j]>>k) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<6; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*6+l) = current_colour;
+ }
+ }
+ }
+ current_video_memory_address-=2;
+ break;
+ }
+ break;
+ case 0x02: /* 44 chars */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<44; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((char_rom[current_data_1*16+j]>>k) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<3; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*3+l) = current_colour;
+ }
+ }
+ }
+ break;
+ case 1:
+ for (i=0; i<44; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((char_rom[current_data_1*16+j]>>k) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<3; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*3+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case 0x03: /* 66 chars */
+ switch (unit_mode)
+ {
+ case 0:
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (i=0; i<66; i++)
+ {
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((char_rom[current_data_1*16+j]>>k) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<2; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*2+l) = current_colour;
+ }
+ }
+ }
+ break;
+ case 1:
+ for (i=0; i<66; i++)
+ {
+ current_data_1 = space->read_byte(current_video_memory_address--);
+ current_data_2 = space->read_byte(current_video_memory_address--);
+ for (j=0; j<=line_repeat_count; j++)
+ {
+ for (k=0; k<8; k++)
+ {
+ current_colour = ((char_rom[current_data_1*16+j]>>k) & 0x01) ? (current_data_2>>4)&0x0f : current_data_2&0x0f;
+ for (l=0; l<2; l++)
+ bitmap.pix16(current_scan_line/2 + j, (i*8+k)*2+l) = current_colour;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ current_scan_line += line_repeat_count*2+2;
+ LOG_DAI_VIDEO_LINE(display_mode, unit_mode, horizontal_resolution, line_repeat_count, current_scan_line);
+ }
+ return 0;
+}
diff --git a/src/mess/video/dgn_beta.c b/src/mess/video/dgn_beta.c
new file mode 100644
index 00000000000..3881af5e88c
--- /dev/null
+++ b/src/mess/video/dgn_beta.c
@@ -0,0 +1,303 @@
+/*
+ video/dgn_beta.c
+
+The Dragon Beta uses a 68B45 for it's display generation, this is used in the
+conventional wat with a character generator ROM in the two text modes, which are
+standard 40x25 and 80x25. In adition to the 6845 there is some TTL logic which
+provides colour and attributes. In text modes the video ram is organised as pairs
+of character and attribute, in alternate bytes.
+
+The attributes decode as follows :-
+
+ 7-6-5-4-3-2-1-0
+ f-u-F-F-F-B-B-B
+
+ f=flash
+ u=underline
+
+ FFF = foreground colour
+ BBB = bakcground colour
+
+ 000 black
+ 001 red
+ 010 green
+ 011 yellow
+ 100 blue
+ 101 magenta
+ 110 cyan
+ 111 white
+
+ If flash is true, foreground and background colours will be exchanged.
+
+It is interesting to note that the 6845 uses 16 bit wide access to the ram, in contrast
+to the 8 bit accesses from the CPUs, this allows each increment of the MA lines to move
+2 bytes at a time, and therefore feed both the character rom and the attribute decode
+circuit simultaniously.
+
+The RAM addresses are made up of two parts, the MA0..13 from the 6845, plus two output
+lines from the 6821 PIA, I28, the lines are BP6 and PB7, with PB7 being the most
+significant. This effectivly allows the 6845 access to the first 128K of memory, as there
+are 16 address lines, accessing a 16 bit wide memory.
+
+The relationship between how the cpu sees the RAM, and the way the 6845 sees it is simply
+CPU addr=2x6845 addr. So for the default video address of $1F000, the CPU sees this as
+being at $1F000 (after DAT trasnlation). The 6845 is programmed to start it's MA lines
+counting at $3800, plus A14 and A15 being supplied by PB6 and PB7 from I28, gives an address
+of $F800, which is the same as $1F000 / 2.
+
+I am currently at this time not sure of how any of the graphics modes, work, this will need
+further investigation.
+
+However the modes supported are :-
+
+Text Modes
+ width height colours
+ 40 25 8
+ 80 25 8
+Graphics modes
+ 320 256 4
+ 320 256 16
+ 640 512 4
+ 640 256 4**
+ 640 512 2
+
+Looking at the parts of the circuit sheet that I have seen it looks like the graphics modes
+are driven using a combination of the 6845 MA and RA lines to address more than 64K or memory
+which is needed for some of the modes above (specifically, 640x512x4, which needs 80K).
+
+2006-11-30, Text mode is almost completely implemented, in both 40 and 80 column modes.
+I have made a start on implementing the graphics modes of the beta, drawing from technical
+documents, from the project, this is still a work in progress. I have however managed to get
+it to display a distorted graphical image, so I know I am going in the correct direction !
+
+** 2006-12-05, this mode is not documented in any of the printed documentation, however it
+is supported and displayed by the graphics test rom, it is basically the 640x512x4 mode with
+half the number of vertical lines, and in non-interlaced mode.
+
+It seems that the 640x512 modes operate the 6845 in interlaced mode, just how this affects
+the access to the video memory is unclear to me at the moment.
+
+*/
+
+#include "emu.h"
+#include "includes/dgn_beta.h"
+
+/* GCtrl bitmasks, infered from bits of Beta schematic */
+#define GCtrlWI 0x01
+#define GCtrlSWChar 0x02 /* Character set select */
+#define GCtrlHiLo 0x04 /* Hi/Lo res graphics, Hi=1, Lo=0 */
+#define GCtrlChrGfx 0x08 /* Character=1 / Graphics=0 */
+#define GCtrlControl 0x10 /* Control bit, sets direct drive mode */
+#define GCtrlFS 0x20 /* labeled F/S, not yet sure of function Fast or Slow scan ? */
+#define GCtrlAddrLines 0xC0 /* Top two address lines for text mode */
+
+#define IsTextMode (state->m_GCtrl & GCtrlChrGfx) ? 1 : 0 // Is this text mode ?
+#define IsGfx16 ((~state->m_GCtrl & GCtrlChrGfx) && (~state->m_GCtrl & GCtrlControl)) ? 1 : 0 // is this 320x256x16bpp mode
+#define IsGfx2 ((state->m_GCtrl & GCtrlHiLo) && (~state->m_GCtrl & GCtrlFS)) ? 1 : 0 // Is this a 2 colour mode
+#define SWChar (state->m_GCtrl & GCtrlSWChar)>>1 // Swchar bit
+
+static MC6845_UPDATE_ROW( dgnbeta_update_row )
+{
+ dgn_beta_state *state = device->machine().driver_data<dgn_beta_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 *videoram = state->m_videoram;
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+ if(IsTextMode)
+ {
+ UINT8 *chr_gen = state->memregion("gfx1")->base();
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT32 offset = ( ( ma + i ) | ((state->m_GCtrl & GCtrlAddrLines)<<8)) << 1;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+
+ /* Extract non-colour attributes, in character set 1, undeline is used */
+ /* We will extract the colours below, when we have decoded inverse */
+ /* to indicate a double height character */
+ int UnderLine=(attr & 0x40) >> 6; // Underline active
+ int FlashChar=(attr & 0x80) >> 7; // Flashing char
+
+ // underline is active for character set 0, on character row 9
+ int ULActive=(UnderLine && (ra==9) && ~SWChar);
+
+ /* Invert forground and background if flashing char and flash acive */
+ int Invert=(FlashChar & state->m_FlashBit);
+
+ /* Underline inverts flash */
+ if (ULActive)
+ Invert=~Invert;
+
+ /* Cursor on also inverts */
+ if (i == cursor_x)
+ Invert=~Invert;
+
+ UINT16 fg = 0;
+ UINT16 bg = 0;
+
+ /* Invert colours if invert is true */
+ if(!Invert)
+ {
+ fg = (attr & 0x38) >> 3;
+ bg = (attr & 0x07);
+ }
+ else
+ {
+ bg = (attr & 0x38) >> 3;
+ fg = (attr & 0x07);
+ }
+
+
+
+ UINT8 data = chr_gen[ chr * 16 + ra ];
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+
+ }
+ else
+ {
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT32 offset = ((((ma + i ) & 0x1FFF) << 3) | (ra & 0x07)) << 1;
+
+ UINT8 Lo = videoram[ offset ];
+ UINT8 Hi = videoram[ offset +1 ];
+ UINT16 Word = (Hi<<8) | Lo;
+ int Red;
+ int Green;
+ int Blue;
+ int Intense;
+ int Colour;
+ int Dot;
+
+ /* If contol is low then we are plotting 4 bit per pixel, 16 colour mode */
+ /* This directly drives the colour output lines, from the pixel value */
+ /* If Control is high, then we lookup the colour from the LS670 4x4 bit */
+ /* palate register */
+ if (IsGfx16)
+ {
+ Intense =(Lo & 0x0F);
+ Red =(Lo & 0xF0)>>4;
+ Green =(Hi & 0x0F);
+ Blue =(Hi & 0xF0)>>4;
+ Colour=((Intense&0x08) | (Red&0x08)>>1) | ((Green&0x08)>>2) | ((Blue&0x08)>>3);
+
+ for (Dot=0;Dot<4;Dot++)
+ {
+ *p = palette[Colour]; p++;
+ *p = palette[Colour]; p++;
+ *p = palette[Colour]; p++;
+ *p = palette[Colour]; p++;
+
+ Intense =Intense<<1;
+ Red =Red<<1;
+ Green =Green<<1;
+ Blue =Blue<<1;
+ }
+ }
+ else if (IsGfx2)
+ {
+ for (Dot=0;Dot<16;Dot=Dot+1)
+ {
+ Colour=state->m_ColourRAM[((Word&0x8000)>>15)];
+
+ *p = palette[Colour]; p++;
+
+ Hi=(Word&0x8000) >> 15;
+ Word=((Word<<1)&0xFFFE) | Hi;
+ }
+ }
+ else
+ {
+ for (Dot=0;Dot<8;Dot++)
+ {
+ Colour=state->m_ColourRAM[((Word&0x8000)>>14) | ((Word&0x80)>>7)];
+ *p = palette[Colour]; p++;
+ *p = palette[Colour]; p++;
+
+ Hi=(Word&0x8000) >> 15;
+ Word=((Word<<1)&0xFFFE) | Hi;
+ }
+ }
+ }
+ }
+
+}
+
+static WRITE_LINE_DEVICE_HANDLER( dgnbeta_vsync_changed )
+{
+ dgn_beta_state *st = device->machine().driver_data<dgn_beta_state>();
+
+ st->m_beta_VSync=state;
+ if (!st->m_beta_VSync)
+ {
+ st->m_FlashCount++;
+ if(st->m_FlashCount==10)
+ {
+ st->m_FlashCount=0; // Reset counter
+ st->m_FlashBit=(!st->m_FlashBit) & 0x01; // Invert flash bit.
+ }
+ }
+
+ dgn_beta_frame_interrupt(device->machine(), state);
+}
+
+const mc6845_interface dgnbeta_crtc6845_interface =
+{
+ "screen",
+ 16 /*?*/,
+ NULL,
+ dgnbeta_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(dgnbeta_vsync_changed),
+ NULL
+};
+
+
+/* Set video control register from I28 port B, the control register is laid out as */
+/* follows :- */
+/* bit function */
+/* 0 WI, unknown */
+/* 1 Character set select, drives A12 of character rom in text mode */
+/* 2 High (1) or Low(0) resolution if in graphics mode. */
+/* 3 Text (1) or Graphics(0) mode */
+/* 4 Control bit, Selects between colour palate and drirect drive */
+/* 5 F/S bit, 1=80 bytes/line, 0=40bytes/line */
+/* 6 Effective A14, to ram, in text mode */
+/* 7 Effective A15, to ram, in text mode */
+/* the top two address lines for the video ram, are supplied by the BB6 and PB7 on */
+/* 6821-I28, this allows the 6845 to access the full 64K address range, however */
+/* since the ram data is addressed as a 16bit wide unit, this allows the 6845 */
+/* access to the first 128K or ram. */
+void dgnbeta_vid_set_gctrl(running_machine &machine, int data)
+{
+ dgn_beta_state *state = machine.driver_data<dgn_beta_state>();
+ state->m_GCtrl=data;
+}
+
+
+/* Write handler for colour, pallate ram */
+WRITE8_HANDLER(dgnbeta_colour_ram_w)
+{
+ dgn_beta_state *state = space->machine().driver_data<dgn_beta_state>();
+ state->m_ColourRAM[offset]=data&0x0f; /* Colour ram 4 bit and write only to CPU */
+}
diff --git a/src/mess/video/dl1416.c b/src/mess/video/dl1416.c
new file mode 100644
index 00000000000..1243e02d1dc
--- /dev/null
+++ b/src/mess/video/dl1416.c
@@ -0,0 +1,325 @@
+/*****************************************************************************
+ *
+ * video/dl1416.c
+ *
+ * DL1416
+ *
+ * 4-Digit 16-Segment Alphanumeric Intelligent Display
+ * with Memory/Decoder/Driver
+ *
+ * Notes:
+ * - Currently supports the DL1416T and by virtue of it being nearly the same, the DL1414.
+ * - Partial support for DL1416B is available, it just needs the right
+ * character set and MAME core support for its display.
+ * - Cursor support is implemented but not tested, as the AIM65 does not
+ * seem to use it.
+ *
+ * Todo:
+ * - Is the DL1416A identical to the DL1416T? If not, we need to add
+ * support for it.
+ * - Add proper support for DL1414 (pretty much DL1416T without the cursor)
+ *
+ * Changes:
+ * - 2007-07-30: Initial version. [Dirk Best]
+ * - 2008-02-25: Converted to the new device interface. [Dirk Best]
+ * - 2008-12-18: Cleanups. [Dirk Best]
+ * - 2011-10-08: Changed the ram to store character rather than segment data. [Lord Nightmare]
+ *
+ *
+ * We use the following order for the segments:
+ *
+ * 000 111
+ * 7D A E2
+ * 7 D A E 2
+ * 7 DAE 2
+ * 888 999
+ * 6 CBF 3
+ * 6 C B F 3
+ * 6C B F3
+ * 555 444
+ *
+ ****************************************************************************/
+
+#include "emu.h"
+#include "dl1416.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define SEG_UNDEF (-2)
+#define SEG_BLANK (0)
+#define SEG_CURSOR (0xffff)
+#define CURSOR_ON (1)
+#define CURSOR_OFF (0)
+
+/* character set DL1416T */
+static const int dl1416t_segments[128] = {
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ 0x0000, 0x2421, 0x0480, 0x0f3c, /* ! " # */
+ 0x0fbb, 0x5f99, 0xa579, 0x4000, /* $ % & ' */
+ 0xc000, 0x3000, 0xff00, 0x0f00, /* ( ) * + */
+ 0x1000, 0x0300, 0x0020, 0x5000, /* , - . / */
+ 0x0ce1, 0x0c00, 0x0561, 0x0d21, /* 0 1 2 3 */
+ 0x0d80, 0x09a1, 0x09e1, 0x0c01, /* 4 5 6 7 */
+ 0x0de1, 0x0da1, 0x0021, 0x1001, /* 8 9 : ; */
+ 0x5030, 0x0330, 0xa030, 0x0a07, /* < = > ? */
+ 0x097f, 0x03cf, 0x0e3f, 0x00f3, /* @ A B C */
+ 0x0c3f, 0x01f3, 0x01c3, 0x02fb, /* D E F G */
+ 0x03cc, 0x0c33, 0x0c63, 0xc1c0, /* H I J K */
+ 0x00f0, 0x60cc, 0xa0cc, 0x00ff, /* L M N O */
+ 0x03c7, 0x80ff, 0x83c7, 0x03bb, /* P Q R S */
+ 0x0c03, 0x00fc, 0x50c0, 0x90cc, /* T U V W */
+ 0xf000, 0x6800, 0x5033, 0x00e1, /* X Y Z [ */
+ 0xa000, 0x001e, 0x9000, 0x0030, /* \ ] ^ _ */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */
+ SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF /* undefined */
+};
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _dl1416_state dl1416_state;
+struct _dl1416_state
+{
+ int write_enable;
+ int chip_enable;
+ int cursor_enable;
+
+ UINT16 digit_ram[4]; // holds the digit code for each position
+ UINT8 cursor_state[4]; // holds the cursor state for each position, 0=off, 1=on
+};
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE dl1416_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == DL1416);
+
+ return (dl1416_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( dl1416 )
+{
+ dl1416_state *dl1416 = get_safe_token(device);
+
+ /* validate arguments */
+ assert(((const dl1416_interface *)(downcast<const legacy_device_base *>(device)->inline_config()))->type >= DL1416B);
+ assert(((const dl1416_interface *)(downcast<const legacy_device_base *>(device)->inline_config()))->type < MAX_DL1416_TYPES);
+
+ /* register for state saving */
+ state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->chip_enable);
+ state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->cursor_enable);
+ state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->write_enable);
+ state_save_register_item_array(device->machine(), "dl1416", device->tag(), 0, dl1416->digit_ram);
+}
+
+
+static DEVICE_RESET( dl1416 )
+{
+ int i, pattern;
+ dl1416_state *chip = get_safe_token(device);
+ const dl1416_interface *intf = (const dl1416_interface *)downcast<const legacy_device_base *>(device)->inline_config();
+ /* disable all lines */
+ chip->chip_enable = FALSE;
+ chip->write_enable = FALSE;
+ chip->cursor_enable = FALSE;
+
+ /* randomize digit and cursor memory */
+ for (i = 0; i < 4; i++)
+ {
+ chip->digit_ram[i] = device->machine().rand()&0x3F;
+ // TODO: only enable the following line if the device actually has a cursor (DL1416T and DL1416B), if DL1414 then cursor is always 0!
+ //chip->cursor_state[i] = ((device->machine().rand()&0xFF) >= 0x80) ? CURSOR_ON : CURSOR_OFF;
+ chip->cursor_state[i] = CURSOR_OFF;
+ pattern = dl1416t_segments[chip->digit_ram[i]];
+
+ /* If cursor for this digit position is enabled and segment is not */
+ /* undefined, replace digit with cursor */
+ if ((chip->cursor_state[i] == CURSOR_ON) && (pattern != SEG_UNDEF))
+ pattern = SEG_CURSOR;
+
+ /* Undefined characters are replaced by blanks */
+ if (pattern == SEG_UNDEF)
+ pattern = SEG_BLANK;
+
+ /* Call update function */
+ if (intf->update)
+ intf->update(device, i, pattern);
+ }
+}
+
+
+DEVICE_GET_INFO( dl1416 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(dl1416_state); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(dl1416_interface); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( dl1416 ); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( dl1416 ); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "DL1416"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "DL1416"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.1"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+
+/*****************************************************************************
+ IMPLEMENTATION
+*****************************************************************************/
+
+/* write enable, active low */
+WRITE_LINE_DEVICE_HANDLER( dl1416_wr_w )
+{
+ dl1416_state *chip = get_safe_token(device);
+ chip->write_enable = !state;
+}
+
+/* chip enable, active low */
+WRITE_LINE_DEVICE_HANDLER( dl1416_ce_w )
+{
+ dl1416_state *chip = get_safe_token(device);
+ chip->chip_enable = !state;
+}
+
+/* cursor enable, active low */
+WRITE_LINE_DEVICE_HANDLER( dl1416_cu_w )
+{
+ dl1416_state *chip = get_safe_token(device);
+ chip->cursor_enable = !state;
+}
+
+/* data */
+WRITE8_DEVICE_HANDLER( dl1416_data_w )
+{
+ dl1416_state *chip = get_safe_token(device);
+ const dl1416_interface *intf = (const dl1416_interface *)downcast<const legacy_device_base *>(device)->inline_config();
+
+ offset &= 0x03; /* A0-A1 */
+ data &= 0x7f; /* D0-D6 */
+
+ /* Only try to update the data if we are enabled and write is enabled */
+ if (chip->chip_enable && chip->write_enable)
+ {
+ /* fprintf(stderr,"DL1416 Write: Cursor: %d, Offset: %d, Data: %02X\n (%c)", chip->cursor_enable, offset, data, data); */
+ int i, pattern, previous_state;
+
+ if (chip->cursor_enable) /* cursor enable is set */
+ {
+ switch (intf->type)
+ {
+ case DL1416B: /* DL1416B uses offset to decide cursor pos to change and D0 to hold new state */
+
+ /* The cursor will be set if D0 is high and the original */
+ /* character restored otherwise */
+ previous_state = chip->cursor_state[offset];
+ chip->cursor_state[offset] = data & 1 ? CURSOR_ON : CURSOR_OFF;
+
+ if (previous_state != chip->cursor_state[offset])
+ {
+ pattern = dl1416t_segments[chip->digit_ram[offset]];
+
+ /* If cursor for this digit position is enabled and segment is not */
+ /* undefined, replace digit with cursor */
+ if ((chip->cursor_state[offset] == CURSOR_ON) && (pattern != SEG_UNDEF))
+ pattern = SEG_CURSOR;
+
+ /* Undefined characters are replaced by blanks */
+ if (pattern == SEG_UNDEF)
+ pattern = SEG_BLANK;
+
+ /* Call update function */
+ if (intf->update)
+ intf->update(device, offset, pattern);
+ }
+ break;
+
+ case DL1416T: /* DL1416T uses a bitmap of 4 data bits D0,D1,D2,D3 to decide cursor pos to change and new state */
+
+ for (i = 0; i < 4; i++)
+ {
+ /* The cursor will be set if D0-D3 is high and the original */
+ /* character at the appropriate position restored otherwise */
+ previous_state = chip->cursor_state[i];
+ chip->cursor_state[i] = data & (1<<i) ? CURSOR_ON : CURSOR_OFF;
+
+ if (previous_state != chip->cursor_state[i])
+ {
+ pattern = dl1416t_segments[chip->digit_ram[i]];
+
+ /* If cursor for this digit position is enabled and segment is not */
+ /* undefined, replace digit with cursor */
+ if ((chip->cursor_state[i] == CURSOR_ON) && (pattern != SEG_UNDEF))
+ pattern = SEG_CURSOR;
+
+ /* Undefined characters are replaced by blanks */
+ if (pattern == SEG_UNDEF)
+ pattern = SEG_BLANK;
+
+ /* Call update function */
+ if (intf->update)
+ intf->update(device, i, pattern);
+ }
+ }
+ break;
+ }
+ }
+ else /* cursor enable is not set, so standard write */
+ {
+ /* Save written value */
+ chip->digit_ram[offset] = data&0x3f;
+
+ /* Load segment pattern from ROM */
+ pattern = dl1416t_segments[data]; /** TODO: handle DL1416T vs DL1416B vs DL1414 here */
+
+ /* If cursor for this digit position is enabled and segment is not */
+ /* undefined, replace digit with cursor */
+ if ((chip->cursor_state[offset] == CURSOR_ON) && (pattern != SEG_UNDEF))
+ pattern = SEG_CURSOR;
+
+ /* Undefined characters are replaced by blanks */
+ if (pattern == SEG_UNDEF)
+ pattern = SEG_BLANK;
+
+ /* Call update function */
+ if (intf->update)
+ intf->update(device, offset, pattern);
+ }
+ }
+}
+
+DEFINE_LEGACY_DEVICE(DL1416, dl1416);
diff --git a/src/mess/video/dl1416.h b/src/mess/video/dl1416.h
new file mode 100644
index 00000000000..91e91b418e0
--- /dev/null
+++ b/src/mess/video/dl1416.h
@@ -0,0 +1,75 @@
+/*****************************************************************************
+ *
+ * video/dl1416.h
+ *
+ * DL1416
+ *
+ * 4-Digit 16-Segment Alphanumeric Intelligent Display
+ * with Memory/Decoder/Driver
+ *
+ * See video/dl1416.c for more info
+ *
+ ****************************************************************************/
+
+#ifndef DL1416_H_
+#define DL1416_H_
+
+#include "devcb.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+enum
+{
+ DL1416B,
+ DL1416T,
+ MAX_DL1416_TYPES
+};
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef void (*dl1416_update_func)(device_t *device, int digit, int data);
+
+typedef struct _dl1416_interface dl1416_interface;
+struct _dl1416_interface
+{
+ int type;
+ dl1416_update_func update;
+};
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_DL1416_ADD(_tag, _type, _update) \
+ MCFG_DEVICE_ADD(_tag, DL1416, 0) \
+ MCFG_DEVICE_CONFIG_DATA32(dl1416_interface, type, _type) \
+ MCFG_DEVICE_CONFIG_DATAPTR(dl1416_interface, update, _update)
+
+#define MCFG_DL1416B_ADD(_tag, _update) \
+ MCFG_DL1416_ADD(_tag, DL1416B, _update)
+
+#define MCFG_DL1416T_ADD(_tag, _update) \
+ MCFG_DL1416_ADD(_tag, DL1416T, _update)
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* inputs */
+WRITE_LINE_DEVICE_HANDLER( dl1416_wr_w ); /* write enable */
+WRITE_LINE_DEVICE_HANDLER( dl1416_ce_w ); /* chip enable */
+WRITE_LINE_DEVICE_HANDLER( dl1416_cu_w ); /* cursor enable */
+WRITE8_DEVICE_HANDLER( dl1416_data_w );
+
+/* device get info callback */
+DECLARE_LEGACY_DEVICE(DL1416, dl1416);
+
+#endif /* DL1416_H_ */
diff --git a/src/mess/video/ef9345.c b/src/mess/video/ef9345.c
new file mode 100644
index 00000000000..df9686dc96e
--- /dev/null
+++ b/src/mess/video/ef9345.c
@@ -0,0 +1,1038 @@
+/*********************************************************************
+
+ ef9345.c
+
+ Thomson EF9345 video controller emulator code
+
+ This code is based on Daniel Coulom's implementation in DCVG5k
+ and DCAlice released by Daniel Coulom under GPL license
+
+ The implementation below is released under the MAME license for use
+ in MAME, MESS and derivatives by permission of the author.
+
+*********************************************************************/
+
+#include "emu.h"
+#include "ef9345.h"
+
+#define MODE24x40 0
+#define MODEVAR40 1
+#define MODE8x80 2
+#define MODE12x80 3
+#define MODE16x40 4
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type EF9345 = &device_creator<ef9345_device>;
+
+// default address map
+static ADDRESS_MAP_START( ef9345, AS_0, 8, ef9345_device )
+ AM_RANGE(0x0000, 0x3fff) AM_RAM
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *ef9345_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void ef9345_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const ef9345_interface *intf = reinterpret_cast<const ef9345_interface *>(static_config());
+
+ if (intf != NULL)
+ {
+ *static_cast<ef9345_interface *>(this) = *intf;
+ }
+ // or initialize to defaults if none provided
+ else
+ {
+ screen_tag = NULL;
+ }
+}
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+// calculate the internal RAM offset
+inline UINT16 ef9345_device::indexram(UINT8 r)
+{
+ UINT8 x = m_registers[r];
+ UINT8 y = m_registers[r - 1];
+ if (y < 8)
+ y &= 1;
+ return ((x&0x3f) | ((x & 0x40) << 6) | ((x & 0x80) << 4) | ((y & 0x1f) << 6) | ((y & 0x20) << 8));
+}
+
+// calculate the internal ROM offset
+inline UINT16 ef9345_device::indexrom(UINT8 r)
+{
+ UINT8 x = m_registers[r];
+ UINT8 y = m_registers[r - 1];
+ if (y < 8)
+ y &= 1;
+ return((x&0x3f)|((x&0x40)<<6)|((x&0x80)<<4)|((y&0x1f)<<6));
+}
+
+// increment x
+inline void ef9345_device::inc_x(UINT8 r)
+{
+ UINT8 i = (m_registers[r] & 0x3f) + 1;
+ if (i > 39)
+ {
+ i -= 40;
+ m_state |= 0x40;
+ }
+ m_registers[r] = (m_registers[r] & 0xc0) | i;
+}
+
+// increment y
+inline void ef9345_device::inc_y(UINT8 r)
+{
+ UINT8 i = (m_registers[r] & 0x1f) + 1;
+ if (i > 31)
+ i -= 24;
+ m_registers[r] = (m_registers[r] & 0xe0) | i;
+}
+
+
+//**************************************************************************
+// live device
+//**************************************************************************
+
+//-------------------------------------------------
+// ef9345_device - constructor
+//-------------------------------------------------
+
+ef9345_device::ef9345_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, EF9345, "EF9345", tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(ef9345))
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ef9345_device::device_start()
+{
+ m_screen = machine().device<screen_device>(screen_tag);
+
+ assert(m_screen != NULL);
+
+ m_busy_timer = timer_alloc(BUSY_TIMER);
+ m_blink_timer = timer_alloc(BLINKING_TIMER);
+
+ m_videoram = space(0);
+ m_charset = region();
+
+ m_screen_out.allocate(496, m_screen->height());
+ m_screen_out.set_palette(machine().palette);
+
+ m_blink_timer->adjust(attotime::from_msec(500), 0, attotime::from_msec(500));
+
+ init_accented_chars();
+
+ save_item(NAME(m_border));
+ save_item(NAME(m_registers));
+ save_item(NAME(m_last_dial));
+ save_item(NAME(m_ram_base));
+ save_item(NAME(m_bf));
+ save_item(NAME(m_char_mode));
+ save_item(NAME(m_state));
+ save_item(NAME(m_tgs));
+ save_item(NAME(m_mat));
+ save_item(NAME(m_pat));
+ save_item(NAME(m_dor));
+ save_item(NAME(m_ror));
+ save_item(NAME(m_block));
+ save_item(NAME(m_blink));
+ save_item(NAME(m_latchc0));
+ save_item(NAME(m_latchm));
+ save_item(NAME(m_latchi));
+ save_item(NAME(m_latchu));
+
+ save_item(NAME(m_screen_out));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+void ef9345_device::device_reset()
+{
+ m_tgs = m_mat = m_pat = m_dor = m_ror = 0;
+ m_state = 0;
+ m_bf = 0;
+ m_block = 0;
+ m_blink = 0;
+ m_latchc0 = 0;
+ m_latchm = 0;
+ m_latchi = 0;
+ m_latchu = 0;
+ m_char_mode = 0;
+
+ memset(m_last_dial, 0, sizeof(m_last_dial));
+ memset(m_registers, 0, sizeof(m_registers));
+ memset(m_border, 0, sizeof(m_border));
+ memset(m_border, 0, sizeof(m_ram_base));
+
+ m_screen_out.fill(0);
+
+ set_video_mode();
+}
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+void ef9345_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case BUSY_TIMER:
+ m_bf = 0;
+ break;
+
+ case BLINKING_TIMER:
+ m_blink = !m_blink;
+ break;
+ }
+}
+
+
+// set busy flag and timer to clear it
+void ef9345_device::set_busy_flag(int period)
+{
+ m_bf = 1;
+ m_busy_timer->adjust(attotime::from_usec(period));
+}
+
+// draw a char in 40 char line mode
+void ef9345_device::draw_char_40(UINT8 *c, UINT16 x, UINT16 y)
+{
+ //verify size limit
+ if (y * 10 >= m_screen->height() || x * 8 >= m_screen->width())
+ return;
+
+ const rgb_t *palette = palette_entry_list_raw(m_screen_out.palette());
+ for(int i = 0; i < 10; i++)
+ for(int j = 0; j < 8; j++)
+ m_screen_out.pix32(y * 10 + i, x * 8 + j) = palette[c[8 * i + j] & 0x07];
+}
+
+// draw a char in 80 char line mode
+void ef9345_device::draw_char_80(UINT8 *c, UINT16 x, UINT16 y)
+{
+ // verify size limit
+ if (y * 10 >= m_screen->height() || x * 6 >= m_screen->width())
+ return;
+
+ const rgb_t *palette = palette_entry_list_raw(m_screen_out.palette());
+ for(int i = 0; i < 10; i++)
+ for(int j = 0; j < 6; j++)
+ m_screen_out.pix32(y * 10 + i, x * 6 + j) = palette[c[6 * i + j] & 0x07];
+}
+
+
+// set then ef9345 mode
+void ef9345_device::set_video_mode(void)
+{
+ m_char_mode = ((m_pat & 0x80) >> 5) | ((m_tgs & 0xc0) >> 6);
+ UINT16 new_width = (m_char_mode == MODE12x80 || m_char_mode == MODE8x80) ? 492 : 336;
+
+ if (m_screen->width() != new_width)
+ {
+ rectangle visarea = m_screen->visible_area();
+ visarea.max_x = new_width - 1;
+
+ m_screen->configure(new_width, m_screen->height(), visarea, m_screen->frame_period().attoseconds);
+ }
+
+ //border color
+ memset(m_border, m_mat & 0x07, sizeof(m_border));
+
+ //set the base for the m_videoram charset
+ m_ram_base[0] = ((m_dor & 0x07) << 11);
+ m_ram_base[1] = m_ram_base[0];
+ m_ram_base[2] = ((m_dor & 0x30) << 8);
+ m_ram_base[3] = m_ram_base[2] + 0x0800;
+
+ //address of the current memory block
+ m_block = 0x0800 * ((((m_ror & 0xf0) >> 4) | ((m_ror & 0x40) >> 5) | ((m_ror & 0x20) >> 3)) & 0x0c);
+}
+
+// initialize the ef9345 accented chars
+void ef9345_device::init_accented_chars(void)
+{
+ UINT16 i, j;
+ for(j = 0; j < 0x10; j++)
+ for(i = 0; i < 0x200; i++)
+ m_acc_char[(j << 9) + i] = m_charset->u8(0x0600 + i);
+
+ for(j = 0; j < 0x200; j += 0x40)
+ for(i = 0; i < 4; i++)
+ {
+ m_acc_char[0x0200 + j + i + 4] |= 0x1c; //tilde
+ m_acc_char[0x0400 + j + i + 4] |= 0x10; //acute
+ m_acc_char[0x0400 + j + i + 8] |= 0x08; //acute
+ m_acc_char[0x0600 + j + i + 4] |= 0x04; //grave
+ m_acc_char[0x0600 + j + i + 8] |= 0x08; //grave
+
+ m_acc_char[0x0a00 + j + i + 4] |= 0x1c; //tilde
+ m_acc_char[0x0c00 + j + i + 4] |= 0x10; //acute
+ m_acc_char[0x0c00 + j + i + 8] |= 0x08; //acute
+ m_acc_char[0x0e00 + j + i + 4] |= 0x04; //grave
+ m_acc_char[0x0e00 + j + i + 8] |= 0x08; //grave
+
+ m_acc_char[0x1200 + j + i + 4] |= 0x08; //point
+ m_acc_char[0x1400 + j + i + 4] |= 0x14; //trema
+ m_acc_char[0x1600 + j + i + 32] |= 0x08; //cedilla
+ m_acc_char[0x1600 + j + i + 36] |= 0x04; //cedilla
+
+ m_acc_char[0x1a00 + j + i + 4] |= 0x08; //point
+ m_acc_char[0x1c00 + j + i + 4] |= 0x14; //trema
+ m_acc_char[0x1e00 + j + i + 32] |= 0x08; //cedilla
+ m_acc_char[0x1e00 + j + i + 36] |= 0x04; //cedilla
+ }
+}
+
+// read a char in charset or in m_videoram
+UINT8 ef9345_device::read_char(UINT8 index, UINT16 addr)
+{
+ if (index < 0x04)
+ return m_charset->u8(0x0800*index + addr);
+ else if (index < 0x08)
+ return m_acc_char[0x0800*(index&3) + addr];
+ else if (index < 0x0c)
+ return m_videoram->read_byte(m_ram_base[index-8] + addr);
+ else
+ return m_videoram->read_byte(addr);
+}
+
+// calculate the dial position of the char
+UINT8 ef9345_device::get_dial(UINT8 x, UINT8 attrib)
+{
+ if (x > 0 && m_last_dial[x-1] == 1) //top right
+ m_last_dial[x] = 2;
+ else if (x > 0 && m_last_dial[x-1] == 5) //half right
+ m_last_dial[x] = 10;
+ else if (m_last_dial[x] == 1) //bottom left
+ m_last_dial[x] = 4;
+ else if (m_last_dial[x] == 2) //bottom right
+ m_last_dial[x] = 8;
+ else if (m_last_dial[x] == 3) //lower half
+ m_last_dial[x] = 12;
+ else if (attrib == 1) //Left half
+ m_last_dial[x] = 5;
+ else if (attrib == 2) //half high
+ m_last_dial[x] = 3;
+ else if (attrib == 3) //top left
+ m_last_dial[x] = 1;
+ else //none
+ m_last_dial[x] = 0;
+
+ return m_last_dial[x];
+}
+
+// zoom the char
+void ef9345_device::zoom(UINT8 *pix, UINT16 n)
+{
+ UINT8 i, j;
+ if ((n & 0x0a) == 0)
+ for(i = 0; i < 80; i += 8) // 1, 4, 5
+ for(j = 7; j > 0; j--)
+ pix[i + j] = pix[i + j / 2];
+
+ if ((n & 0x05) == 0)
+ for(i = 0; i < 80; i += 8) // 2, 8, 10
+ for(j =0 ; j < 7; j++)
+ pix[i + j] = pix[i + 4 + j / 2];
+
+ if ((n & 0x0c) == 0)
+ for(i = 0; i < 8; i++) // 1, 2, 3
+ for(j = 9; j > 0; j--)
+ pix[i + 8 * j] = pix[i + 8 * (j / 2)];
+
+ if ((n & 0x03) == 0)
+ for(i = 0; i < 8; i++) // 4, 8, 12
+ for(j = 0; j < 9; j++)
+ pix[i + 8 * j] = pix[i + 40 + 8 * (j / 2)];
+}
+
+
+// calculate the address of the char x,y
+UINT16 ef9345_device::indexblock(UINT16 x, UINT16 y)
+{
+ UINT16 i = x, j;
+ j = (y == 0) ? ((m_tgs & 0x20) >> 5) : ((m_ror & 0x1f) + y - 1);
+
+ //right side of a double width character
+ if ((m_tgs & 0x80) == 0 && x > 0)
+ {
+ if (m_last_dial[x - 1] == 1) i--;
+ if (m_last_dial[x - 1] == 4) i--;
+ if (m_last_dial[x - 1] == 5) i--;
+ }
+
+ return 0x40 * j + i;
+}
+
+// draw bichrome character (40 columns)
+void ef9345_device::bichrome40(UINT8 type, UINT16 address, UINT8 dial, UINT16 iblock, UINT16 x, UINT16 y, UINT8 c0, UINT8 c1, UINT8 insert, UINT8 flash, UINT8 hided, UINT8 negative, UINT8 underline)
+{
+ UINT16 i;
+ UINT8 pix[80];
+
+ if (flash && m_pat & 0x40 && m_blink)
+ c1 = c0; //flash
+ if (hided && m_pat & 0x08)
+ c1 = c0; //hided
+ if (negative) //negative
+ {
+ i = c1;
+ c1 = c0;
+ c0 = i;
+ }
+
+ if ((m_pat & 0x30) == 0x30)
+ insert = 0; //active area mark
+ if (insert == 0)
+ c1 += 8; //foreground color
+ if ((m_pat & 0x30) == 0x00)
+ insert = 1; //insert mode
+ if (insert == 0)
+ c0 += 8; //background color
+
+ //draw the cursor
+ i = (m_registers[6] & 0x1f);
+ if (i < 8)
+ i &= 1;
+
+ if (iblock == 0x40 * i + (m_registers[7] & 0x3f)) //cursor position
+ {
+ switch(m_mat & 0x70)
+ {
+ case 0x40: //00 = fixed complemented
+ c0 = (23 - c0) & 15;
+ c1 = (23 - c1) & 15;
+ break;
+ case 0x50: //01 = fixed underlined
+ underline = 1;
+ break;
+ case 0x60: //10 = flash complemented
+ if (m_blink)
+ {
+ c0 = (23 - c0) & 15;
+ c1 = (23 - c1) & 15;
+ }
+ break;
+ case 0x70: //11 = flash underlined
+ if (m_blink)
+ underline = 1;
+ break;
+ }
+ }
+
+ // generate the pixel table
+ for(i = 0; i < 40; i+=4)
+ {
+ UINT8 ch = read_char(type, address + i);
+
+ for (UINT8 b=0; b<8; b++)
+ pix[i*2 + b] = (ch & (1<<b)) ? c1 : c0;
+ }
+
+ //draw the underline
+ if (underline)
+ memset(&pix[72], c1, 8);
+
+ if (dial > 0)
+ zoom(pix, dial);
+
+ //doubles the height of the char
+ if (m_mat & 0x80)
+ zoom(pix, (y & 0x01) ? 0x0c : 0x03);
+
+ draw_char_40(pix, x + 1 , y + 1);
+}
+
+// draw quadrichrome character (40 columns)
+void ef9345_device::quadrichrome40(UINT8 c, UINT8 b, UINT8 a, UINT16 x, UINT16 y)
+{
+ //C0-6= character code
+ //B0= insert not yet implemented !!!
+ //B1= low resolution
+ //B2= subset index (low resolution only)
+ //B3-5 = set number
+ //A0-6 = 4 color palette
+
+ UINT8 i, j, n, col[8], pix[80];
+ UINT8 lowresolution = (b & 0x02) >> 1, ramx, ramy, ramblock;
+ UINT16 ramindex;
+
+ //quadrichrome don't suppor double size
+ m_last_dial[x] = 0;
+
+ //initialize the color table
+ for(j = 1, n = 0, i = 0; i < 8; i++)
+ {
+ col[n++] = (a & j) ? i : 7;
+ j <<= 1;
+ }
+
+ //find block number in ram
+ ramblock = 0;
+ if (b & 0x20) ramblock |= 4; //B5
+ if (b & 0x08) ramblock |= 2; //B3
+ if (b & 0x10) ramblock |= 1; //B4
+
+ //find character address in ram
+ ramx = c & 0x03;
+ ramy =(c & 0x7f) >> 2;
+ ramindex = 0x0800 * ramblock + 0x40 * ramy + ramx;
+ if (lowresolution) ramindex += 5 * (b & 0x04);
+
+ //fill pixel table
+ for(i = 0, j = 0; i < 10; i++)
+ {
+ UINT8 ch = read_char(0x0c, ramindex + 4 * (i >> lowresolution));
+ pix[j] = pix[j + 1] = col[(ch & 0x03) >> 0]; j += 2;
+ pix[j] = pix[j + 1] = col[(ch & 0x0c) >> 2]; j += 2;
+ pix[j] = pix[j + 1] = col[(ch & 0x30) >> 4]; j += 2;
+ pix[j] = pix[j + 1] = col[(ch & 0xc0) >> 6]; j += 2;
+ }
+
+ draw_char_40(pix, x + 1, y + 1);
+}
+
+// draw bichrome character (80 columns)
+void ef9345_device::bichrome80(UINT8 c, UINT8 a, UINT16 x, UINT16 y)
+{
+ UINT8 c0, c1, pix[60];
+ UINT16 i, j, d;
+
+ c1 = (a & 1) ? (m_dor >> 4) & 7 : m_dor & 7; //foreground color = DOR
+ c0 = m_mat & 7; //background color = MAT
+
+ switch(c & 0x80)
+ {
+ case 0: //alphanumeric G0 set
+ //A0: D = color set
+ //A1: U = underline
+ //A2: F = flash
+ //A3: N = negative
+ //C0-6: character code
+
+ if ((a & 4) && (m_pat & 0x40) && (m_blink))
+ c1 = c0; //flash
+ if (a & 8) //negative
+ {
+ i = c1;
+ c1 = c0;
+ c0 = i;
+ }
+
+ d = ((c & 0x7f) >> 2) * 0x40 + (c & 0x03); //char position
+
+ for(i=0, j=0; i < 10; i++)
+ {
+ UINT8 ch = read_char(0, d + 4 * i);
+ for (UINT8 b=0; b<6; b++)
+ pix[j++] = (ch & (1<<b)) ? c1 : c0;
+ }
+
+ //draw the underline
+ if (a & 2)
+ memset(&pix[54], c1, 6);
+
+ break;
+ default: //dedicated mosaic set
+ //A0: D = color set
+ //A1-3: 3 blocks de 6 pixels
+ //C0-6: 7 blocks de 6 pixels
+ pix[ 0] = (c & 0x01) ? c1 : c0;
+ pix[ 3] = (c & 0x02) ? c1 : c0;
+ pix[12] = (c & 0x04) ? c1 : c0;
+ pix[15] = (c & 0x08) ? c1 : c0;
+ pix[24] = (c & 0x10) ? c1 : c0;
+ pix[27] = (c & 0x20) ? c1 : c0;
+ pix[36] = (c & 0x40) ? c1 : c0;
+ pix[39] = (a & 0x02) ? c1 : c0;
+ pix[48] = (a & 0x04) ? c1 : c0;
+ pix[51] = (a & 0x08) ? c1 : c0;
+
+ for(i = 0; i < 60; i += 12)
+ {
+ pix[i + 6] = pix[i];
+ pix[i + 9] = pix[i + 3];
+ }
+
+ for(i = 0; i < 60; i += 3)
+ pix[i + 2] = pix[i + 1] = pix[i];
+
+ break;
+ }
+
+ draw_char_80(pix, x, y);
+}
+
+// generate 16 bits 40 columns char
+void ef9345_device::makechar_16x40(UINT16 x, UINT16 y)
+{
+ UINT8 a, b, c0, c1, i, f, m, n, u, type, dial;
+ UINT16 address, iblock;
+
+ iblock = (m_mat & 0x80 && y > 1) ? indexblock(x, y / 2) : indexblock(x, y);
+ a = m_videoram->read_byte(m_block + iblock);
+ b = m_videoram->read_byte(m_block + iblock + 0x0800);
+
+ dial = get_dial(x, (a & 0x80) ? 0 : (((a & 0x20) >> 5) | ((a & 0x10) >> 3)));
+
+ //type and address of the char
+ type = ((b & 0x80) >> 4) | ((a & 0x80) >> 6);
+ address = ((b & 0x7f) >> 2) * 0x40 + (b & 0x03);
+
+ //negative space
+ if ((b & 0xe0) == 0x80)
+ {
+ address = 0;
+ type = 3;
+ }
+
+ //reset attributes latch
+ if (x == 0)
+ m_latchm = m_latchi = m_latchu = m_latchc0 = 0;
+
+ if (type == 4)
+ {
+ m_latchm = b & 1;
+ m_latchi = (b & 2) >> 1;
+ m_latchu = (b & 4) >> 2;
+ }
+
+ if (a & 0x80)
+ m_latchc0 = (a & 0x70) >> 4;
+
+ //char attributes
+ c0 = m_latchc0; //background
+ c1 = a & 0x07; //foreground
+ i = m_latchi; //insert mode
+ f = (a & 0x08) >> 3; //flash
+ m = m_latchm; //hided
+ n = (a & 0x80) ? 0: ((a & 0x40) >> 6); //negative
+ u = m_latchu; //underline
+
+ bichrome40(type, address, dial, iblock, x, y, c0, c1, i, f, m, n, u);
+}
+
+// generate 24 bits 40 columns char
+void ef9345_device::makechar_24x40(UINT16 x, UINT16 y)
+{
+ UINT8 a, b, c, c0, c1, i, f, m, n, u, type, dial;
+ UINT16 address, iblock;
+
+ iblock = (m_mat & 0x80 && y > 1) ? indexblock(x, y / 2) : indexblock(x, y);
+ c = m_videoram->read_byte(m_block + iblock);
+ b = m_videoram->read_byte(m_block + iblock + 0x0800);
+ a = m_videoram->read_byte(m_block + iblock + 0x1000);
+
+ if ((b & 0xc0) == 0xc0)
+ {
+ quadrichrome40(c, b, a, x, y);
+ return;
+ }
+
+ dial = get_dial(x, (b & 0x02) + ((b & 0x08) >> 3));
+
+ //type and address of the char
+ address = ((c & 0x7f) >> 2) * 0x40 + (c & 0x03);
+ type = (b & 0xf0) >> 4;
+
+ //char attributes
+ c0 = a & 0x07; //background
+ c1 = (a & 0x70) >> 4; //foreground
+ i = b & 0x01; //insert
+ f = (a & 0x08) >> 3; //flash
+ m = (b & 0x04) >> 2; //hided
+ n = ((a & 0x80) >> 7); //negative
+ u = (((b & 0x60) == 0) || ((b & 0xc0) == 0x40)) ? ((b & 0x10) >> 4) : 0; //underline
+
+ bichrome40(type, address, dial, iblock, x, y, c0, c1, i, f, m, n, u);
+}
+
+// generate 12 bits 80 columns char
+void ef9345_device::makechar_12x80(UINT16 x, UINT16 y)
+{
+ UINT16 iblock = indexblock(x, y);
+ bichrome80(m_videoram->read_byte(m_block + iblock), (m_videoram->read_byte(m_block + iblock + 0x1000) >> 4) & 0x0f, 2 * x + 1, y + 1);
+ bichrome80(m_videoram->read_byte(m_block + iblock + 0x0800), m_videoram->read_byte(m_block + iblock + 0x1000) & 0x0f, 2 * x + 2, y + 1);
+}
+
+void ef9345_device::draw_border(UINT16 line)
+{
+ if (m_char_mode == MODE12x80 || m_char_mode == MODE8x80)
+ for(int i = 0; i < 82; i++)
+ draw_char_80(m_border, i, line);
+ else
+ for(int i = 0; i < 42; i++)
+ draw_char_40(m_border, i, line);
+}
+
+void ef9345_device::makechar(UINT16 x, UINT16 y)
+{
+ switch (m_char_mode)
+ {
+ case MODE24x40:
+ makechar_24x40(x, y);
+ break;
+ case MODEVAR40:
+ case MODE8x80:
+ logerror("Unemulated EF9345 mode: %02x\n", m_char_mode);
+ break;
+ case MODE12x80:
+ makechar_12x80(x, y);
+ break;
+ case MODE16x40:
+ makechar_16x40(x, y);
+ break;
+ default:
+ logerror("Unknown EF9345 mode: %02x\n", m_char_mode);
+ break;
+ }
+}
+
+// Execute EF9345 command
+void ef9345_device::ef9345_exec(UINT8 cmd)
+{
+ m_state = 0;
+ if ((m_registers[5] & 0x3f) == 39) m_state |= 0x10; //S4(LXa) set
+ if ((m_registers[7] & 0x3f) == 39) m_state |= 0x20; //S5(LXm) set
+
+ UINT16 a = indexram(7);
+
+ switch(cmd)
+ {
+ case 0x00: //KRF: R1,R2,R3->ram
+ case 0x01: //KRF: R1,R2,R3->ram + increment
+ set_busy_flag(4);
+ m_videoram->write_byte(a, m_registers[1]);
+ m_videoram->write_byte(a + 0x0800, m_registers[2]);
+ m_videoram->write_byte(a + 0x1000, m_registers[3]);
+ if (cmd&1) inc_x(7);
+ break;
+ case 0x02: //KRG: R1,R2->ram
+ case 0x03: //KRG: R1,R2->ram + increment
+ set_busy_flag(5.5);
+ m_videoram->write_byte(a, m_registers[1]);
+ m_videoram->write_byte(a + 0x0800, m_registers[2]);
+ if (cmd&1) inc_x(7);
+ break;
+ case 0x08: //KRF: ram->R1,R2,R3
+ case 0x09: //KRF: ram->R1,R2,R3 + increment
+ set_busy_flag(7.5);
+ m_registers[1] = m_videoram->read_byte(a);
+ m_registers[2] = m_videoram->read_byte(a + 0x0800);
+ m_registers[3] = m_videoram->read_byte(a + 0x1000);
+ if (cmd&1) inc_x(7);
+ break;
+ case 0x0a: //KRG: ram->R1,R2
+ case 0x0b: //KRG: ram->R1,R2 + increment
+ set_busy_flag(7.5);
+ m_registers[1] = m_videoram->read_byte(a);
+ m_registers[2] = m_videoram->read_byte(a + 0x0800);
+ if (cmd&1) inc_x(7);
+ break;
+ case 0x30: //OCT: R1->RAM, main pointer
+ case 0x31: //OCT: R1->RAM, main pointer + inc
+ set_busy_flag(4);
+ m_videoram->write_byte(indexram(7), m_registers[1]);
+
+ if (cmd&1)
+ {
+ inc_x(7);
+ if ((m_registers[7] & 0x3f) == 0)
+ inc_y(6);
+ }
+ break;
+ case 0x34: //OCT: R1->RAM, aux pointer
+ case 0x35: //OCT: R1->RAM, aux pointer + inc
+ set_busy_flag(4);
+ m_videoram->write_byte(indexram(5), m_registers[1]);
+
+ if (cmd&1)
+ inc_x(5);
+ break;
+ case 0x38: //OCT: RAM->R1, main pointer
+ case 0x39: //OCT: RAM->R1, main pointer + inc
+ set_busy_flag(4.5);
+ m_registers[1] = m_videoram->read_byte(indexram(7));
+
+ if (cmd&1)
+ {
+ inc_x(7);
+
+ if ((m_registers[7] & 0x3f) == 0)
+ inc_y(6);
+ }
+ break;
+ case 0x3c: //OCT: RAM->R1, aux pointer
+ case 0x3d: //OCT: RAM->R1, aux pointer + inc
+ set_busy_flag(4.5);
+ m_registers[1] = m_videoram->read_byte(indexram(5));
+
+ if (cmd&1)
+ inc_x(5);
+ break;
+ case 0x50: //KRL: 80 UINT8 - 12 bits write
+ case 0x51: //KRL: 80 UINT8 - 12 bits write + inc
+ set_busy_flag(12.5);
+ m_videoram->write_byte(a, m_registers[1]);
+ switch((a / 0x0800) & 1)
+ {
+ case 0:
+ {
+ UINT8 tmp_data = m_videoram->read_byte(a + 0x1000);
+ m_videoram->write_byte(a + 0x1000, (tmp_data & 0x0f) | (m_registers[3] & 0xf0));
+ break;
+ }
+ case 1:
+ {
+ UINT8 tmp_data = m_videoram->read_byte(a + 0x0800);
+ m_videoram->write_byte(a + 0x0800, (tmp_data & 0xf0) | (m_registers[3] & 0x0f));
+ break;
+ }
+ }
+ if (cmd&1)
+ {
+ if ((m_registers[7] & 0x80) == 0x00) { m_registers[7] |= 0x80; return; }
+ m_registers[7] &= 0x80;
+ inc_x(7);
+ }
+ break;
+ case 0x58: //KRL: 80 UINT8 - 12 bits read
+ case 0x59: //KRL: 80 UINT8 - 12 bits read + inc
+ set_busy_flag(11.5);
+ m_registers[1] = m_videoram->read_byte(a);
+ switch((a / 0x0800) & 1)
+ {
+ case 0:
+ m_registers[3] = m_videoram->read_byte(a + 0x1000);
+ break;
+ case 1:
+ m_registers[3] = m_videoram->read_byte(a + 0x0800);
+ break;
+ }
+ if (cmd&1)
+ {
+ if ((m_registers[7] & 0x80) == 0x00)
+ {
+ m_registers[7] |= 0x80;
+ break;
+ }
+ m_registers[7] &= 0x80;
+ inc_x(7);
+ }
+ break;
+ case 0x80: //IND: R1->ROM (impossible ?)
+ break;
+ case 0x81: //IND: R1->TGS
+ case 0x82: //IND: R1->MAT
+ case 0x83: //IND: R1->PAT
+ case 0x84: //IND: R1->DOR
+ case 0x87: //IND: R1->ROR
+ set_busy_flag(2);
+ switch(cmd&7)
+ {
+ case 1: m_tgs = m_registers[1]; break;
+ case 2: m_mat = m_registers[1]; break;
+ case 3: m_pat = m_registers[1]; break;
+ case 4: m_dor = m_registers[1]; break;
+ case 7: m_ror = m_registers[1]; break;
+ }
+ set_video_mode();
+ m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al)
+ break;
+ case 0x88: //IND: ROM->R1
+ case 0x89: //IND: TGS->R1
+ case 0x8a: //IND: MAT->R1
+ case 0x8b: //IND: PAT->R1
+ case 0x8c: //IND: DOR->R1
+ case 0x8f: //IND: ROR->R1
+ set_busy_flag(3.5);
+ switch(cmd&7)
+ {
+ case 0: m_registers[1] = m_charset->u8(indexrom(7) & 0x1fff);
+ case 1: m_registers[1] = m_tgs; break;
+ case 2: m_registers[1] = m_mat; break;
+ case 3: m_registers[1] = m_pat; break;
+ case 4: m_registers[1] = m_dor; break;
+ case 7: m_registers[1] = m_ror; break;
+ }
+ m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al)
+ break;
+ case 0x90: //NOP: no operation
+ case 0x91: //NOP: no operation
+ case 0x95: //VRM: vertical sync mask reset
+ case 0x99: //VSM: vertical sync mask set
+ break;
+ case 0xb0: //INY: increment Y
+ set_busy_flag(2);
+ inc_y(6);
+ m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al)
+ break;
+ case 0xd5: //MVB: move buffer MP->AP stop
+ case 0xd6: //MVB: move buffer MP->AP nostop
+ case 0xd9: //MVB: move buffer AP->MP stop
+ case 0xda: //MVB: move buffer AP->MP nostop
+ case 0xe5: //MVD: move double buffer MP->AP stop
+ case 0xe6: //MVD: move double buffer MP->AP nostop
+ case 0xe9: //MVD: move double buffer AP->MP stop
+ case 0xea: //MVD: move double buffer AP->MP nostop
+ case 0xf5: //MVT: move triple buffer MP->AP stop
+ case 0xf6: //MVT: move triple buffer MP->AP nostop
+ case 0xf9: //MVT: move triple buffer AP->MP stop
+ case 0xfa: //MVT: move triple buffer AP->MP nostop
+ {
+ UINT16 i, a1, a2;
+ UINT8 n = (cmd>>4) - 0x0c;
+ UINT8 r1 = (cmd&0x04) ? 7 : 5;
+ UINT8 r2 = (cmd&0x04) ? 5 : 7;
+ int busy = 2;
+
+ for(i = 0; i < 1280; i++)
+ {
+ a1 = indexram(r1); a2 = indexram(r2);
+ m_videoram->write_byte(a2, m_videoram->read_byte(a1));
+
+ if (n > 1) m_videoram->write_byte(a2 + 0x0800, m_videoram->read_byte(a1 + 0x0800));
+ if (n > 2) m_videoram->write_byte(a2 + 0x1000, m_videoram->read_byte(a1 + 0x1000));
+
+ inc_x(r1);
+ inc_x(r2);
+ if ((m_registers[5] & 0x3f) == 0 && (cmd&1))
+ break;
+
+ if ((m_registers[7] & 0x3f) == 0)
+ {
+ if (cmd&1)
+ break;
+ else
+ inc_y(6);
+ }
+
+ busy += 4 * n;
+ }
+ m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al)
+ set_busy_flag(busy);
+ }
+ break;
+ case 0x05: //CLF: Clear page 24 bits
+ case 0x07: //CLG: Clear page 16 bits
+ case 0x40: //KRC: R1 -> ram
+ case 0x41: //KRC: R1 -> ram + inc
+ case 0x48: //KRC: 80 characters - 8 bits
+ case 0x49: //KRC: 80 characters - 8 bits
+ default:
+ logerror("Unemulated EF9345 cmd: %02x\n", cmd);
+ }
+}
+
+
+/**************************************************************
+ EF9345 interface
+**************************************************************/
+
+UINT32 ef9345_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_screen_out, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+void ef9345_device::update_scanline(UINT16 scanline)
+{
+ UINT16 i;
+
+ if (scanline == 250)
+ m_state &= 0xfb;
+
+ set_busy_flag(104);
+
+ if (m_char_mode == MODE12x80 || m_char_mode == MODE8x80)
+ {
+ draw_char_80(m_border, 0, (scanline / 10) + 1);
+ draw_char_80(m_border, 81, (scanline / 10) + 1);
+ }
+ else
+ {
+ draw_char_40(m_border, 0, (scanline / 10) + 1);
+ draw_char_40(m_border, 41, (scanline / 10) + 1);
+ }
+
+ if (scanline == 0)
+ {
+ m_state |= 0x04;
+ draw_border(0);
+ if (m_pat & 1)
+ for(i = 0; i < 40; i++)
+ makechar(i, (scanline / 10));
+ else
+ for(i = 0; i < 42; i++)
+ draw_char_40(m_border, i, 1);
+ }
+ else if (scanline < 120)
+ {
+ if (m_pat & 2)
+ for(i = 0; i < 40; i++)
+ makechar(i, (scanline / 10));
+ else
+ draw_border(scanline / 10);
+ }
+ else if (scanline < 250)
+ {
+ if (m_pat & 4)
+ for(i = 0; i < 40; i++)
+ makechar(i, (scanline / 10));
+ else
+ draw_border(scanline / 10);
+
+ if (scanline == 240)
+ draw_border(26);
+ }
+}
+
+READ8_MEMBER( ef9345_device::data_r )
+{
+ if (offset & 7)
+ return m_registers[offset & 7];
+
+ if (m_bf)
+ m_state |= 0x80;
+ else
+ m_state &= 0x7f;
+
+ return m_state;
+}
+
+WRITE8_MEMBER( ef9345_device::data_w )
+{
+ m_registers[offset & 7] = data;
+
+ if (offset & 8)
+ ef9345_exec(m_registers[0] & 0xff);
+}
diff --git a/src/mess/video/ef9345.h b/src/mess/video/ef9345.h
new file mode 100644
index 00000000000..4595b8eceef
--- /dev/null
+++ b/src/mess/video/ef9345.h
@@ -0,0 +1,123 @@
+/*********************************************************************
+
+ ef9345.h
+
+ Thomson EF9345 video controller
+
+*********************************************************************/
+
+
+#pragma once
+
+#ifndef __EF9345_H__
+#define __EF9345_H__
+
+
+#define MCFG_EF9345_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, EF9345, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> ef9345_interface
+
+struct ef9345_interface
+{
+ const char *screen_tag; // screen we are acting on
+};
+
+// ======================> ef9345_device
+
+class ef9345_device : public device_t,
+ public device_memory_interface,
+ public ef9345_interface
+{
+public:
+ // construction/destruction
+ ef9345_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device interface
+ READ8_MEMBER( data_r );
+ WRITE8_MEMBER( data_w );
+ void update_scanline(UINT16 scanline);
+ UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ // device_config overrides
+ virtual void device_config_complete();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+
+ // inline helper
+ inline UINT16 indexram(UINT8 r);
+ inline UINT16 indexrom(UINT8 r);
+ inline void inc_x(UINT8 r);
+ inline void inc_y(UINT8 r);
+
+private:
+
+ void set_busy_flag(int period);
+ void draw_char_40(UINT8 *c, UINT16 x, UINT16 y);
+ void draw_char_80(UINT8 *c, UINT16 x, UINT16 y);
+ void set_video_mode(void);
+ void init_accented_chars(void);
+ UINT8 read_char(UINT8 index, UINT16 addr);
+ UINT8 get_dial(UINT8 x, UINT8 attrib);
+ void zoom(UINT8 *pix, UINT16 n);
+ UINT16 indexblock(UINT16 x, UINT16 y);
+ void bichrome40(UINT8 type, UINT16 address, UINT8 dial, UINT16 iblock, UINT16 x, UINT16 y, UINT8 c0, UINT8 c1, UINT8 insert, UINT8 flash, UINT8 hided, UINT8 negative, UINT8 underline);
+ void quadrichrome40(UINT8 c, UINT8 b, UINT8 a, UINT16 x, UINT16 y);
+ void bichrome80(UINT8 c, UINT8 a, UINT16 x, UINT16 y);
+ void makechar(UINT16 x, UINT16 y);
+ void draw_border(UINT16 line);
+ void makechar_16x40(UINT16 x, UINT16 y);
+ void makechar_24x40(UINT16 x, UINT16 y);
+ void makechar_12x80(UINT16 x, UINT16 y);
+ void ef9345_exec(UINT8 cmd);
+
+ // internal state
+ static const device_timer_id BUSY_TIMER = 0;
+ static const device_timer_id BLINKING_TIMER = 1;
+
+ memory_region *m_charset;
+ address_space *m_videoram;
+
+ screen_device *m_screen; //screen we are acting on
+
+ UINT8 m_bf; //busy flag
+ UINT8 m_char_mode; //40 or 80 chars for line
+ UINT8 m_acc_char[0x2000]; //accented chars
+ UINT8 m_registers[8]; //registers R0-R7
+ UINT8 m_state; //status register
+ UINT8 m_tgs,m_mat,m_pat,m_dor,m_ror; //indirect registers
+ UINT8 m_border[80]; //border color
+ UINT16 m_block; //current memory block
+ UINT16 m_ram_base[4]; //index of ram charset
+ UINT8 m_blink; //cursor status
+ UINT8 m_last_dial[40]; //last chars dial (for determinate the zoom position)
+ UINT8 m_latchc0; //background color latch
+ UINT8 m_latchm; //hided atribute latch
+ UINT8 m_latchi; //insert atribute latch
+ UINT8 m_latchu; //underline atribute latch
+
+ bitmap_rgb32 m_screen_out;
+
+ // timers
+ emu_timer *m_busy_timer;
+ emu_timer *m_blink_timer;
+};
+
+// device type definition
+extern const device_type EF9345;
+
+#endif
diff --git a/src/mess/video/electron.c b/src/mess/video/electron.c
new file mode 100644
index 00000000000..dfe58c69e03
--- /dev/null
+++ b/src/mess/video/electron.c
@@ -0,0 +1,274 @@
+/******************************************************************************
+ Acorn Electron driver
+
+ MESS Driver By:
+
+ Wilbert Pol
+
+******************************************************************************/
+
+#include "emu.h"
+#include "includes/electron.h"
+
+/*
+ From the ElectrEm site:
+
+Timing is somewhat of a thorny issue on the Electron. It is almost certain the Electron could have been a much faster machine if BBC Micro OS level compatibility had not been not a design requirement.
+
+When accessing the ROM regions, the CPU always runs at 2MHz. When accessing the FC (1 MHz bus) or FD (JIM) pages, the CPU always runs at 1MHz.
+
+The timing for RAM accesses varies depending on the graphics mode, and how many bytes are required to be read by the video circuits per scanline. When accessing RAM in modes 4-6, the CPU is simply moved to a 1MHz clock. This occurs for any RAM access at any point during the frame.
+
+In modes 0-3, if the CPU tries to access RAM at any time during which the video circuits are fetching bytes, it is halted by means of receiving a stopped clock until the video circuits next stop fetching bytes.
+
+Each scanline is drawn in exactly 64us, and of that the video circuits fetch bytes for 40us. In modes 0, 1 and 2, 256 scanlines have pixels on, whereas in mode 3 only 250 scanlines are affected as mode 3 is a 'spaced' mode.
+
+As opposed to one clock generator which changes pace, the 1MHz and 2MHz clocks are always available, so the ULA acts to simply change which clock is piped to the CPU. This means in half of all cases, a further 2MHz cycle is lost waiting for the 2MHz and 1MHz clocks to synchronise during a 2MHz to 1MHz step.
+
+The video circuits run from a constant 2MHz clock, and generate 312 scanlines a frame, one scanline every 128 cycles. This actually gives means the Electron is running at 50.08 frames a second.
+
+Creating a scanline numbering scheme where the first scanline with pixels is scanline 0, in all modes the end of display interrupt is generated at the end of scanline 255, and the RTC interrupt is generated upon the end of scanline 99.
+
+From investigating some code for vertical split modes printed in Electron User volume 7, issue 7 it seems that the exact timing of the end of display interrupt is somewhere between 24 and 40 cycles after the end of pixels. This may coincide with HSYNC. I have no similarly accurate timing for the real time clock interrupt at this time.
+
+Mode changes are 'immediate', so any change in RAM access timing occurs exactly after the write cycle of the changing instruction. Similarly palette changes take effect immediately. VSYNC is not signalled in any way.
+
+*/
+
+static TIMER_CALLBACK( electron_scanline_interrupt );
+
+
+VIDEO_START( electron )
+{
+ electron_state *state = machine.driver_data<electron_state>();
+ int i;
+ for( i = 0; i < 256; i++ ) {
+ state->m_map4[i] = ( ( i & 0x10 ) >> 3 ) | ( i & 0x01 );
+ state->m_map16[i] = ( ( i & 0x40 ) >> 3 ) | ( ( i & 0x10 ) >> 2 ) | ( ( i & 0x04 ) >> 1 ) | ( i & 0x01 );
+ }
+ state->m_scanline_timer = machine.scheduler().timer_alloc(FUNC(electron_scanline_interrupt));
+ state->m_scanline_timer->adjust( machine.primary_screen->time_until_pos(0), 0, machine.primary_screen->scan_period() );
+}
+
+INLINE UINT8 read_vram( electron_state *state, UINT16 addr )
+{
+ return state->m_ula.vram[ addr % state->m_ula.screen_size ];
+}
+
+INLINE void electron_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = (UINT16)color;
+}
+
+SCREEN_UPDATE_IND16( electron )
+{
+ electron_state *state = screen.machine().driver_data<electron_state>();
+ int i;
+ int x = 0;
+ int pal[16];
+ int scanline = screen.vpos();
+ rectangle r = cliprect;
+ r.min_y = r.max_y = scanline;
+
+ /* set up palette */
+ switch( state->m_ula.screen_mode )
+ {
+ case 0: case 3: case 4: case 6: case 7: /* 2 colour mode */
+ pal[0] = state->m_ula.current_pal[0];
+ pal[1] = state->m_ula.current_pal[8];
+ break;
+ case 1: case 5: /* 4 colour mode */
+ pal[0] = state->m_ula.current_pal[0];
+ pal[1] = state->m_ula.current_pal[2];
+ pal[2] = state->m_ula.current_pal[8];
+ pal[3] = state->m_ula.current_pal[10];
+ break;
+ case 2: /* 16 colour mode */
+ for( i = 0; i < 16; i++ )
+ pal[i] = state->m_ula.current_pal[i];
+ }
+
+ /* draw line */
+ switch( state->m_ula.screen_mode )
+ {
+ case 0:
+ for( i = 0; i < 80; i++ )
+ {
+ UINT8 pattern = read_vram( state, state->m_ula.screen_addr + (i << 3) );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>7)& 1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>6)& 1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>5)& 1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>4)& 1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>3)& 1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>2)& 1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>1)& 1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>0)& 1] );
+ }
+ state->m_ula.screen_addr++;
+ if ( ( scanline & 0x07 ) == 7 )
+ state->m_ula.screen_addr += 0x278;
+ break;
+
+ case 1:
+ for( i = 0; i < 80; i++ )
+ {
+ UINT8 pattern = read_vram( state, state->m_ula.screen_addr + i * 8 );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>3]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>3]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>2]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>2]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>0]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>0]] );
+ }
+ state->m_ula.screen_addr++;
+ if ( ( scanline & 0x07 ) == 7 )
+ state->m_ula.screen_addr += 0x278;
+ break;
+
+ case 2:
+ for( i = 0; i < 80; i++ )
+ {
+ UINT8 pattern = read_vram( state, state->m_ula.screen_addr + i * 8 );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map16[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map16[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map16[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map16[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map16[pattern>>0]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map16[pattern>>0]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map16[pattern>>0]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map16[pattern>>0]] );
+ }
+ state->m_ula.screen_addr++;
+ if ( ( scanline & 0x07 ) == 7 )
+ state->m_ula.screen_addr += 0x278;
+ break;
+
+ case 3:
+ if ( ( scanline > 249 ) || ( scanline % 10 >= 8 ) )
+ bitmap.fill(7, r );
+ else
+ {
+ for( i = 0; i < 80; i++ )
+ {
+ UINT8 pattern = read_vram( state, state->m_ula.screen_addr + i * 8 );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>7)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>6)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>5)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>4)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>3)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>2)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>1)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>0)&1] );
+ }
+ state->m_ula.screen_addr++;
+ }
+ if ( scanline % 10 == 9 )
+ state->m_ula.screen_addr += 0x278;
+ break;
+
+ case 4:
+ case 7:
+ for( i = 0; i < 40; i++ )
+ {
+ UINT8 pattern = read_vram( state, state->m_ula.screen_addr + i * 8 );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>7)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>7)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>6)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>6)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>5)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>5)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>4)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>4)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>3)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>3)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>2)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>2)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>1)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>1)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>0)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>0)&1] );
+ }
+ state->m_ula.screen_addr++;
+ if ( ( scanline & 0x07 ) == 7 )
+ state->m_ula.screen_addr += 0x138;
+ break;
+
+ case 5:
+ for( i = 0; i < 40; i++ )
+ {
+ UINT8 pattern = read_vram( state, state->m_ula.screen_addr + i * 8 );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>3]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>3]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>3]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>3]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>2]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>2]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>2]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>2]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>1]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>0]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>0]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>0]] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[state->m_map4[pattern>>0]] );
+ }
+ state->m_ula.screen_addr++;
+ if ( ( scanline & 0x07 ) == 7 )
+ state->m_ula.screen_addr += 0x138;
+ break;
+
+ case 6:
+ if ( ( scanline > 249 ) || ( scanline % 10 >= 8 ) )
+ bitmap.fill(7, r );
+ else
+ {
+ for( i = 0; i < 40; i++ )
+ {
+ UINT8 pattern = read_vram( state, state->m_ula.screen_addr + i * 8 );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>7)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>7)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>6)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>6)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>5)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>5)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>4)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>4)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>3)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>3)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>2)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>2)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>1)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>1)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>0)&1] );
+ electron_plot_pixel( bitmap, x++, scanline, pal[(pattern>>0)&1] );
+ }
+ state->m_ula.screen_addr++;
+ if ( ( scanline % 10 ) == 7 )
+ state->m_ula.screen_addr += 0x138;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static TIMER_CALLBACK( electron_scanline_interrupt )
+{
+ electron_state *state = machine.driver_data<electron_state>();
+ switch (machine.primary_screen->vpos())
+ {
+ case 43:
+ electron_interrupt_handler( machine, INT_SET, INT_RTC );
+ break;
+ case 199:
+ electron_interrupt_handler( machine, INT_SET, INT_DISPLAY_END );
+ break;
+ case 0:
+ state->m_ula.screen_addr = state->m_ula.screen_start - state->m_ula.screen_base;
+ break;
+ }
+}
diff --git a/src/mess/video/epnick.c b/src/mess/video/epnick.c
new file mode 100644
index 00000000000..f5b6d7dca7d
--- /dev/null
+++ b/src/mess/video/epnick.c
@@ -0,0 +1,1044 @@
+/*****************************************************************************
+ *
+ * video/epnick.c
+ *
+ * Nick Graphics Chip - found in Enterprise
+ *
+ * this is a display list graphics chip, with bitmap,
+ * character and attribute graphics modes. Each entry in the
+ * display list defines a char line, with variable number of
+ * scanlines. Colour modes are 2,4, 16 and 256 colour.
+ * Nick has 256 colours, 3 bits for R and G, with 2 bits for Blue.
+ * It's a nice and flexible graphics processor..........
+ *
+ ****************************************************************************/
+
+#include "emu.h"
+#include "machine/ram.h"
+#include "includes/enterp.h"
+
+/* given a colour index in range 0..255 gives the Red component */
+#define NICK_GET_RED8(x) \
+ (( \
+ ( ( (x & (1<<0)) >>0) <<2) | \
+ ( ( (x & (1<<3)) >>3) <<1) | \
+ ( ( (x & (1<<6)) >>6) <<0) \
+ )<<5)
+
+/* given a colour index in range 0..255 gives the Red component */
+#define NICK_GET_GREEN8(x) \
+ (( \
+ ( ( (x & (1<<1)) >>1) <<2) | \
+ ( ( (x & (1<<4)) >>4) <<1) | \
+ ( ( (x & (1<<7)) >>7) <<0) \
+ )<<5)
+
+/* given a colour index in range 0..255 gives the Red component */
+#define NICK_GET_BLUE8(x) \
+ (( \
+ ( ( (x & (1<<2)) >>2) <<1) | \
+ ( ( (x & (1<<5)) >>5) <<0) \
+ )<<6)
+
+
+/* Nick executes a Display list, in the form of a list of Line Parameter
+Tables, this is the form of the data */
+typedef struct LPT_ENTRY
+{
+ unsigned char SC; /* scanlines in this modeline (two's complement) */
+ unsigned char MB; /* the MODEBYTE (defines video display mode) */
+ unsigned char LM; /* left margin etc */
+ unsigned char RM; /* right margin etc */
+ unsigned char LD1L; /* (a7..a0) of line data pointer LD1 */
+ unsigned char LD1H; /* (a8..a15) of line data pointer LD1 */
+ unsigned char LD2L; /* (a7..a0) of line data pointer LD2 */
+ unsigned char LD2H; /* (a8..a15) of line data pointer LD2 */
+ unsigned char COL[8]; /* COL0..COL7 */
+} LPT_ENTRY;
+
+typedef struct _NICK_STATE
+{
+ /* horizontal position */
+ unsigned char HorizontalClockCount;
+ /* current scanline within LPT */
+ unsigned char ScanLineCount;
+
+ unsigned char FIXBIAS;
+ unsigned char BORDER;
+ unsigned char LPL;
+ unsigned char LPH;
+
+ unsigned long LD1;
+ unsigned long LD2;
+
+ LPT_ENTRY LPT;
+
+ UINT16 *dest;
+ int dest_pos;
+ int dest_max_pos;
+
+ unsigned char Reg[16];
+
+ /* first clock visible on left hand side */
+ unsigned char FirstVisibleClock;
+ /* first clock visible on right hand side */
+ unsigned char LastVisibleClock;
+
+ /* given a bit pattern, this will get the pen index */
+ unsigned int PenIndexLookup_4Colour[256];
+ /* given a bit pattern, this will get the pen index */
+ unsigned int PenIndexLookup_16Colour[256];
+
+ UINT8 *videoram;
+} NICK_STATE;
+
+/* colour mode types */
+#define NICK_2_COLOUR_MODE 0
+#define NICK_4_COLOUR_MODE 1
+#define NICK_16_COLOUR_MODE 2
+#define NICK_256_COLOUR_MODE 3
+
+/* Display mode types */
+#define NICK_VSYNC_MODE 0
+#define NICK_PIXEL_MODE 1
+#define NICK_ATTR_MODE 2
+#define NICK_CH256_MODE 3
+#define NICK_CH128_MODE 4
+#define NICK_CH64_MODE 5
+#define NICK_UNUSED_MODE 6
+#define NICK_LPIXEL_MODE 7
+
+/* MODEBYTE defines */
+#define NICK_MB_VIRQ (1<<7)
+#define NICK_MB_VRES (1<<4)
+#define NICK_MB_LPT_RELOAD (1<<0)
+
+/* Left margin defines */
+#define NICK_LM_MSBALT (1<<7)
+#define NICK_LM_LSBALT (1<<6)
+
+/* Right margin defines */
+#define NICK_RM_ALTIND1 (1<<7)
+#define NICK_RM_ALTIND0 (1<<6)
+
+/* useful macros */
+#define NICK_GET_LEFT_MARGIN(x) (x & 0x03f)
+#define NICK_GET_RIGHT_MARGIN(x) (x & 0x03f)
+#define NICK_GET_DISPLAY_MODE(x) ((x>>1) & 0x07)
+#define NICK_GET_COLOUR_MODE(x) ((x>>5) & 0x03)
+
+#define NICK_RELOAD_LPT(x) (x & 0x080)
+#define NICK_CLOCK_LPT(x) (x & 0x040)
+
+/* Macros to generate memory address is CHx modes */
+/* x = LD2, y = buf1 */
+#define ADDR_CH256(x,y) (((x & 0x0ff)<<8) | (y & 0x0ff))
+#define ADDR_CH128(x,y) (((x & 0x01ff)<<7) | (y & 0x07f))
+#define ADDR_CH64(x,y) (((x & 0x03ff)<<6) | (y & 0x03f))
+
+
+/*************************************************************/
+/* MESS stuff */
+
+// MESS specific
+/* fetch a byte from "video ram" at Addr specified */
+static char Nick_FetchByte(NICK_STATE *nick, unsigned long Addr)
+{
+ return nick->videoram[Addr & 0x0ffff];
+}
+
+// MESS specific
+/* 8-bit pixel write! */
+static void nick_write_pixel(NICK_STATE *nick, int ci)
+{
+ if (nick->dest_pos < nick->dest_max_pos)
+ {
+ nick->dest[nick->dest_pos++] = ci;
+ }
+}
+
+/*****************************************************/
+
+
+/* Enterprise has 256 colours, all may be on the screen at once!
+the NICK_GET_RED8, NICK_GET_GREEN8, NICK_GET_BLUE8 macros
+return a 8-bit colour value for the index specified. */
+
+/* initial the palette */
+PALETTE_INIT( epnick )
+{
+ int i;
+
+ for (i=0; i<256; i++)
+ {
+ palette_set_color_rgb( machine, i, NICK_GET_RED8(i), NICK_GET_GREEN8(i), NICK_GET_BLUE8(i) );
+ }
+}
+
+/* No of highest resolution pixels per "clock" */
+#define NICK_PIXELS_PER_CLOCK 16
+
+/* "clocks" per line */
+#define NICK_TOTAL_CLOCKS_PER_LINE 64
+
+/* we align based on the clocks */
+static void Nick_CalcVisibleClocks(NICK_STATE *nick, int Width)
+{
+ /* number of clocks we can see */
+ int NoOfVisibleClocks = Width/NICK_PIXELS_PER_CLOCK;
+
+ nick->FirstVisibleClock =
+ (NICK_TOTAL_CLOCKS_PER_LINE - NoOfVisibleClocks)>>1;
+
+ nick->LastVisibleClock = nick->FirstVisibleClock + NoOfVisibleClocks;
+}
+
+
+static void Nick_Init(NICK_STATE *nick)
+{
+ int i;
+
+ for (i=0; i<256; i++)
+ {
+ int PenIndex;
+
+ PenIndex = (
+ (((i & 0x080)>>7)<<0) |
+ (((i & 0x08)>>3)<<1)
+ );
+
+ nick->PenIndexLookup_4Colour[i] = PenIndex;
+
+ PenIndex = (
+ ((((i & 0x080)>>7))<<0) |
+ ((((i & 0x08)>>3))<<1) |
+ ((((i & 0x020)>>5))<<2) |
+ ((((i & 0x02)>>1))<<3)
+ );
+
+ nick->PenIndexLookup_16Colour[i] = PenIndex;
+ }
+
+ Nick_CalcVisibleClocks(nick, ENTERPRISE_SCREEN_WIDTH);
+
+ //nick->BORDER = 0;
+ //nick->FIXBIAS = 0;
+}
+
+/* write border colour */
+static void Nick_WriteBorder(NICK_STATE *nick, int Clocks)
+{
+ int i;
+ int ColIndex = nick->BORDER;
+
+ for (i=0; i<(Clocks<<4); i++)
+ {
+ nick_write_pixel(nick, ColIndex);
+ }
+}
+
+
+static void Nick_DoLeftMargin(NICK_STATE *nick)
+{
+ unsigned char LeftMargin;
+
+ LeftMargin = NICK_GET_LEFT_MARGIN(nick->LPT.LM);
+
+ if (LeftMargin>nick->FirstVisibleClock)
+ {
+ unsigned char LeftMarginVisible;
+
+ /* some of the left margin is visible */
+ LeftMarginVisible = LeftMargin-nick->FirstVisibleClock;
+
+ /* render the border */
+ Nick_WriteBorder(nick, LeftMarginVisible);
+ }
+}
+
+static void Nick_DoRightMargin(NICK_STATE *nick)
+{
+ unsigned char RightMargin;
+
+ RightMargin = NICK_GET_RIGHT_MARGIN(nick->LPT.RM);
+
+ if (RightMargin<nick->LastVisibleClock)
+ {
+ unsigned char RightMarginVisible;
+
+ /* some of the right margin is visible */
+ RightMarginVisible = nick->LastVisibleClock - RightMargin;
+
+ /* render the border */
+ Nick_WriteBorder(nick, RightMarginVisible);
+ }
+}
+
+static int Nick_GetColourIndex(NICK_STATE *nick, int PenIndex)
+{
+ if (PenIndex & 0x08)
+ {
+ return ((nick->FIXBIAS & 0x01f)<<3) | (PenIndex & 0x07);
+ }
+ else
+ {
+ return nick->LPT.COL[PenIndex];
+ }
+}
+
+static void Nick_WritePixels2Colour(NICK_STATE *nick, unsigned char Pen0, unsigned char Pen1, unsigned char DataByte)
+{
+ int i;
+ int ColIndex[2];
+ int PenIndex;
+ unsigned char Data;
+
+ Data = DataByte;
+
+ ColIndex[0] = Nick_GetColourIndex(nick, Pen0);
+ ColIndex[1] = Nick_GetColourIndex(nick, Pen1);
+
+ for (i=0; i<8; i++)
+ {
+ PenIndex = ColIndex[(Data>>7) & 0x01];
+
+ nick_write_pixel(nick, PenIndex);
+
+ Data = Data<<1;
+ }
+}
+
+static void Nick_WritePixels2ColourLPIXEL(NICK_STATE *nick, unsigned char Pen0, unsigned char Pen1, unsigned char DataByte)
+{
+ int i;
+ int ColIndex[2];
+ int PenIndex;
+ unsigned char Data;
+
+ Data = DataByte;
+
+ ColIndex[0] = Nick_GetColourIndex(nick, Pen0);
+ ColIndex[1] = Nick_GetColourIndex(nick, Pen1);
+
+ for (i=0; i<8; i++)
+ {
+ PenIndex = ColIndex[(Data>>7) & 0x01];
+
+ nick_write_pixel(nick, PenIndex);
+ nick_write_pixel(nick, PenIndex);
+
+ Data = Data<<1;
+ }
+}
+
+
+static void Nick_WritePixels(NICK_STATE *nick, unsigned char DataByte, unsigned char CharIndex)
+{
+ int i;
+
+ /* pen index colour 2-C (0,1), 4-C (0..3) 16-C (0..16) */
+ int PenIndex;
+ /* Col index = EP colour value */
+ int PalIndex;
+ unsigned char ColourMode = NICK_GET_COLOUR_MODE(nick->LPT.MB);
+ unsigned char Data = DataByte;
+
+ switch (ColourMode)
+ {
+ case NICK_2_COLOUR_MODE:
+ {
+ int PenOffset = 0;
+
+ /* do before displaying byte */
+
+ /* left margin attributes */
+ if (nick->LPT.LM & NICK_LM_MSBALT)
+ {
+ if (Data & 0x080)
+ {
+ PenOffset |= 2;
+ }
+
+ Data &=~0x080;
+ }
+
+ if (nick->LPT.LM & NICK_LM_LSBALT)
+ {
+ if (Data & 0x001)
+ {
+ PenOffset |= 4;
+ }
+
+ Data &=~0x01;
+ }
+
+ if (nick->LPT.RM & NICK_RM_ALTIND1)
+ {
+ if (CharIndex & 0x080)
+ {
+ PenOffset|=0x02;
+ }
+ }
+
+#if 0
+ if (nick->LPT.RM & NICK_RM_ALTIND0)
+ {
+ if (Data & 0x040)
+ {
+ PenOffset|=0x04;
+ }
+ }
+#endif
+
+
+ Nick_WritePixels2Colour(nick, PenOffset,
+ (PenOffset|0x01), Data);
+ }
+ break;
+
+ case NICK_4_COLOUR_MODE:
+ {
+ //mame_printf_info("4 colour\r\n");
+
+ /* left margin attributes */
+ if (nick->LPT.LM & NICK_LM_MSBALT)
+ {
+ Data &= ~0x080;
+ }
+
+ if (nick->LPT.LM & NICK_LM_LSBALT)
+ {
+ Data &= ~0x01;
+ }
+
+
+ for (i=0; i<4; i++)
+ {
+ PenIndex = nick->PenIndexLookup_4Colour[Data];
+ PalIndex = nick->LPT.COL[PenIndex & 0x03];
+
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+
+ Data = Data<<1;
+ }
+ }
+ break;
+
+ case NICK_16_COLOUR_MODE:
+ {
+ //mame_printf_info("16 colour\r\n");
+
+ /* left margin attributes */
+ if (nick->LPT.LM & NICK_LM_MSBALT)
+ {
+ Data &= ~0x080;
+ }
+
+ if (nick->LPT.LM & NICK_LM_LSBALT)
+ {
+ Data &= ~0x01;
+ }
+
+
+ for (i=0; i<2; i++)
+ {
+ PenIndex = nick->PenIndexLookup_16Colour[Data];
+
+ PalIndex = Nick_GetColourIndex(nick, PenIndex);
+
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+
+ Data = Data<<1;
+ }
+ }
+ break;
+
+ case NICK_256_COLOUR_MODE:
+ {
+ /* left margin attributes */
+ if (nick->LPT.LM & NICK_LM_MSBALT)
+ {
+ Data &= ~0x080;
+ }
+
+ if (nick->LPT.LM & NICK_LM_LSBALT)
+ {
+ Data &= ~0x01;
+ }
+
+
+ PalIndex = Data;
+
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+
+
+ }
+ break;
+ }
+}
+
+static void Nick_WritePixelsLPIXEL(NICK_STATE *nick, unsigned char DataByte, unsigned char CharIndex)
+{
+ int i;
+
+ /* pen index colour 2-C (0,1), 4-C (0..3) 16-C (0..16) */
+ int PenIndex;
+ /* Col index = EP colour value */
+ int PalIndex;
+ unsigned char ColourMode = NICK_GET_COLOUR_MODE(nick->LPT.MB);
+ unsigned char Data = DataByte;
+
+ switch (ColourMode)
+ {
+ case NICK_2_COLOUR_MODE:
+ {
+ int PenOffset = 0;
+
+ /* do before displaying byte */
+
+ /* left margin attributes */
+ if (nick->LPT.LM & NICK_LM_MSBALT)
+ {
+ if (Data & 0x080)
+ {
+ PenOffset |= 2;
+ }
+
+ Data &=~0x080;
+ }
+
+ if (nick->LPT.LM & NICK_LM_LSBALT)
+ {
+ if (Data & 0x001)
+ {
+ PenOffset |= 4;
+ }
+
+ Data &=~0x01;
+ }
+
+ if (nick->LPT.RM & NICK_RM_ALTIND1)
+ {
+ if (CharIndex & 0x080)
+ {
+ PenOffset|=0x02;
+ }
+ }
+
+#if 0
+ if (nick->LPT.RM & NICK_RM_ALTIND0)
+ {
+ if (Data & 0x040)
+ {
+ PenOffset|=0x04;
+ }
+ }
+#endif
+
+
+ Nick_WritePixels2ColourLPIXEL(nick, PenOffset,(PenOffset|0x01), Data);
+ }
+ break;
+
+ case NICK_4_COLOUR_MODE:
+ {
+ //mame_printf_info("4 colour\r\n");
+
+ /* left margin attributes */
+ if (nick->LPT.LM & NICK_LM_MSBALT)
+ {
+ Data &= ~0x080;
+ }
+
+ if (nick->LPT.LM & NICK_LM_LSBALT)
+ {
+ Data &= ~0x01;
+ }
+
+
+ for (i=0; i<4; i++)
+ {
+ PenIndex = nick->PenIndexLookup_4Colour[Data];
+ PalIndex = nick->LPT.COL[PenIndex & 0x03];
+
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+
+ Data = Data<<1;
+ }
+ }
+ break;
+
+ case NICK_16_COLOUR_MODE:
+ {
+ //mame_printf_info("16 colour\r\n");
+
+ /* left margin attributes */
+ if (nick->LPT.LM & NICK_LM_MSBALT)
+ {
+ Data &= ~0x080;
+ }
+
+ if (nick->LPT.LM & NICK_LM_LSBALT)
+ {
+ Data &= ~0x01;
+ }
+
+
+ for (i=0; i<2; i++)
+ {
+ PenIndex = nick->PenIndexLookup_16Colour[Data];
+
+ PalIndex = Nick_GetColourIndex(nick, PenIndex);
+
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+
+ Data = Data<<1;
+ }
+ }
+ break;
+
+ case NICK_256_COLOUR_MODE:
+ {
+ /* left margin attributes */
+ if (nick->LPT.LM & NICK_LM_MSBALT)
+ {
+ Data &= ~0x080;
+ }
+
+ if (nick->LPT.LM & NICK_LM_LSBALT)
+ {
+ Data &= ~0x01;
+ }
+
+
+ PalIndex = Data;
+
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+ nick_write_pixel(nick, PalIndex);
+
+
+ }
+ break;
+ }
+}
+
+
+static void Nick_DoPixel(NICK_STATE *nick, int ClocksVisible)
+{
+ int i;
+ unsigned char Buf1, Buf2;
+
+ for (i=0; i<ClocksVisible; i++)
+ {
+ Buf1 = Nick_FetchByte(nick, nick->LD1);
+ nick->LD1++;
+
+ Buf2 = Nick_FetchByte(nick, nick->LD1);
+ nick->LD1++;
+
+ Nick_WritePixels(nick, Buf1, Buf1);
+
+ Nick_WritePixels(nick, Buf2, Buf1);
+ }
+}
+
+
+static void Nick_DoLPixel(NICK_STATE *nick, int ClocksVisible)
+{
+ int i;
+ unsigned char Buf1;
+
+ for (i=0; i<ClocksVisible; i++)
+ {
+ Buf1 = Nick_FetchByte(nick, nick->LD1);
+ nick->LD1++;
+
+ Nick_WritePixelsLPIXEL(nick, Buf1, Buf1);
+ }
+}
+
+static void Nick_DoAttr(NICK_STATE *nick, int ClocksVisible)
+{
+ int i;
+ unsigned char Buf1, Buf2;
+
+ for (i=0; i<ClocksVisible; i++)
+ {
+ Buf1 = Nick_FetchByte(nick, nick->LD1);
+ nick->LD1++;
+
+ Buf2 = Nick_FetchByte(nick, nick->LD2);
+ nick->LD2++;
+
+ {
+ unsigned char BackgroundColour = ((Buf1>>4) & 0x0f);
+ unsigned char ForegroundColour = (Buf1 & 0x0f);
+
+ Nick_WritePixels2ColourLPIXEL(nick, BackgroundColour, ForegroundColour, Buf2);
+ }
+ }
+}
+
+static void Nick_DoCh256(NICK_STATE *nick, int ClocksVisible)
+{
+ int i;
+ unsigned char Buf1, Buf2;
+
+ for (i=0; i<ClocksVisible; i++)
+ {
+ Buf1 = Nick_FetchByte(nick, nick->LD1);
+ nick->LD1++;
+ Buf2 = Nick_FetchByte(nick, ADDR_CH256(nick->LD2, Buf1));
+
+ Nick_WritePixelsLPIXEL(nick, Buf2, Buf1);
+ }
+}
+
+static void Nick_DoCh128(NICK_STATE *nick, int ClocksVisible)
+{
+ int i;
+ unsigned char Buf1, Buf2;
+
+ for (i=0; i<ClocksVisible; i++)
+ {
+ Buf1 = Nick_FetchByte(nick, nick->LD1);
+ nick->LD1++;
+ Buf2 = Nick_FetchByte(nick, ADDR_CH128(nick->LD2, Buf1));
+
+ Nick_WritePixelsLPIXEL(nick, Buf2, Buf1);
+ }
+}
+
+static void Nick_DoCh64(NICK_STATE *nick, int ClocksVisible)
+{
+ int i;
+ unsigned char Buf1, Buf2;
+
+ for (i=0; i<ClocksVisible; i++)
+ {
+ Buf1 = Nick_FetchByte(nick, nick->LD1);
+ nick->LD1++;
+ Buf2 = Nick_FetchByte(nick, ADDR_CH64(nick->LD2, Buf1));
+
+ Nick_WritePixelsLPIXEL(nick, Buf2, Buf1);
+ }
+}
+
+
+static void Nick_DoDisplay(NICK_STATE *nick)
+{
+ LPT_ENTRY *pLPT = &nick->LPT;
+ unsigned char ClocksVisible;
+ unsigned char RightMargin, LeftMargin;
+
+ LeftMargin = NICK_GET_LEFT_MARGIN(pLPT->LM);
+ RightMargin = NICK_GET_RIGHT_MARGIN(pLPT->RM);
+
+ ClocksVisible = RightMargin - LeftMargin;
+
+ if (ClocksVisible!=0)
+ {
+ unsigned char DisplayMode;
+
+ /* get display mode */
+ DisplayMode = NICK_GET_DISPLAY_MODE(pLPT->MB);
+
+ if (nick->ScanLineCount == 0) // ||
+ //((pLPT->MB & NICK_MB_VRES)==0))
+ {
+ /* doing first line */
+ /* reload LD1, and LD2 (if necessary) regardless of display mode */
+ nick->LD1 = (pLPT->LD1L & 0x0ff) |
+ ((pLPT->LD1H & 0x0ff)<<8);
+
+ if ((DisplayMode != NICK_LPIXEL_MODE) && (DisplayMode != NICK_PIXEL_MODE))
+ {
+ /* lpixel and pixel modes don't use LD2 */
+ nick->LD2 = (pLPT->LD2L & 0x0ff) |
+ ((pLPT->LD2H & 0x0ff)<<8);
+ }
+ }
+ else
+ {
+ /* not first line */
+
+ switch (DisplayMode)
+ {
+ case NICK_ATTR_MODE:
+ {
+ /* reload LD1 */
+ nick->LD1 = (pLPT->LD1L & 0x0ff) |
+ ((pLPT->LD1H & 0x0ff)<<8);
+ }
+ break;
+
+ case NICK_CH256_MODE:
+ case NICK_CH128_MODE:
+ case NICK_CH64_MODE:
+ {
+ /* reload LD1 */
+ nick->LD1 = (pLPT->LD1L & 0x0ff) |
+ ((pLPT->LD1H & 0x0ff)<<8);
+ nick->LD2++;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch (DisplayMode)
+ {
+ case NICK_PIXEL_MODE:
+ {
+ Nick_DoPixel(nick,ClocksVisible);
+ }
+ break;
+
+ case NICK_ATTR_MODE:
+ {
+ //mame_printf_info("attr mode\r\n");
+ Nick_DoAttr( nick,ClocksVisible);
+ }
+ break;
+
+ case NICK_CH256_MODE:
+ {
+ //mame_printf_info("ch256 mode\r\n");
+ Nick_DoCh256(nick,ClocksVisible);
+ }
+ break;
+
+ case NICK_CH128_MODE:
+ {
+ Nick_DoCh128(nick,ClocksVisible);
+ }
+ break;
+
+ case NICK_CH64_MODE:
+ {
+ //mame_printf_info("ch64 mode\r\n");
+ Nick_DoCh64(nick,ClocksVisible);
+ }
+ break;
+
+ case NICK_LPIXEL_MODE:
+ {
+ Nick_DoLPixel(nick,ClocksVisible);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static void Nick_UpdateLPT(NICK_STATE *nick)
+{
+ unsigned long CurLPT;
+
+ CurLPT = (nick->LPL & 0x0ff) | ((nick->LPH & 0x0f)<<8);
+ CurLPT++;
+ nick->LPL = CurLPT & 0x0ff;
+ nick->LPH = (nick->LPH & 0x0f0) | ((CurLPT>>8) & 0x0f);
+}
+
+
+static void Nick_ReloadLPT(NICK_STATE *nick)
+{
+ unsigned long LPT_Addr;
+
+ /* get addr of LPT */
+ LPT_Addr = ((nick->LPL & 0x0ff)<<4) | ((nick->LPH & 0x0f)<<(8+4));
+
+ /* update internal LPT state */
+ nick->LPT.SC = Nick_FetchByte(nick,LPT_Addr);
+ nick->LPT.MB = Nick_FetchByte(nick,LPT_Addr+1);
+ nick->LPT.LM = Nick_FetchByte(nick,LPT_Addr+2);
+ nick->LPT.RM = Nick_FetchByte(nick,LPT_Addr+3);
+ nick->LPT.LD1L = Nick_FetchByte(nick,LPT_Addr+4);
+ nick->LPT.LD1H = Nick_FetchByte(nick,LPT_Addr+5);
+ nick->LPT.LD2L = Nick_FetchByte(nick,LPT_Addr+6);
+ nick->LPT.LD2H = Nick_FetchByte(nick,LPT_Addr+7);
+ nick->LPT.COL[0] = Nick_FetchByte(nick,LPT_Addr+8);
+ nick->LPT.COL[1] = Nick_FetchByte(nick,LPT_Addr+9);
+ nick->LPT.COL[2] = Nick_FetchByte(nick,LPT_Addr+10);
+ nick->LPT.COL[3] = Nick_FetchByte(nick,LPT_Addr+11);
+ nick->LPT.COL[4] = Nick_FetchByte(nick,LPT_Addr+12);
+ nick->LPT.COL[5] = Nick_FetchByte(nick,LPT_Addr+13);
+ nick->LPT.COL[6] = Nick_FetchByte(nick,LPT_Addr+14);
+ nick->LPT.COL[7] = Nick_FetchByte(nick,LPT_Addr+15);
+}
+
+/* call here to render a line of graphics */
+static void Nick_DoLine(NICK_STATE *nick)
+{
+ unsigned char ScanLineCount;
+
+ if ((nick->LPT.MB & NICK_MB_LPT_RELOAD)!=0)
+ {
+ /* reload LPT */
+
+ nick->LPL = nick->Reg[2];
+ nick->LPH = nick->Reg[3];
+
+ Nick_ReloadLPT(nick);
+ }
+
+ /* left border */
+ Nick_DoLeftMargin(nick);
+
+ /* do visible part */
+ Nick_DoDisplay(nick);
+
+ /* right border */
+ Nick_DoRightMargin(nick);
+
+ // 0x0f7 is first!
+ /* scan line count for this LPT */
+ ScanLineCount = ((~nick->LPT.SC)+1) & 0x0ff;
+
+ //printf("ScanLineCount %02x\r\n",ScanLineCount);
+
+ /* update count of scanlines done so far */
+ nick->ScanLineCount++;
+
+ if (((unsigned char)nick->ScanLineCount) ==
+ ((unsigned char)ScanLineCount))
+ {
+ /* done all scanlines of this Line Parameter Table, get next */
+
+
+ nick->ScanLineCount = 0;
+
+ Nick_UpdateLPT(nick);
+ Nick_ReloadLPT(nick);
+
+
+ }
+}
+
+/* MESS specific */
+#ifdef UNUSED_FUNCTION
+READ8_HANDLER( nick_reg_r )
+{
+ /* read from a nick register - return floating bus,
+ because the registers are not readable! */
+ return 0x0ff;
+}
+#endif
+
+WRITE8_HANDLER( epnick_reg_w )
+{
+ ep_state *state = space->machine().driver_data<ep_state>();
+ NICK_STATE *nick = state->nick;
+ //mame_printf_info("Nick write %02x %02x\r\n",offset, data);
+
+ /* write to a nick register */
+ nick->Reg[offset & 0x0f] = data;
+
+ if ((offset == 0x03) || (offset == 0x02))
+ {
+ /* write LPH */
+
+ /* reload LPT base? */
+ //if (NICK_RELOAD_LPT(data))
+ {
+ /* reload LPT base pointer */
+ nick->LPL = nick->Reg[2];
+ nick->LPH = nick->Reg[3];
+
+ Nick_ReloadLPT(nick);
+ }
+ }
+
+ if (offset == 0x01)
+ {
+ nick->BORDER = data;
+ }
+
+ if (offset == 0x00)
+ {
+ nick->FIXBIAS = data;
+ }
+}
+
+static void Nick_DoScreen(NICK_STATE *nick, bitmap_ind16 &bm)
+{
+ int line = 0;
+
+ do
+ {
+
+ /* set write address for line */
+ nick->dest = &bm.pix16(line);
+ nick->dest_pos = 0;
+ nick->dest_max_pos = bm.width();
+
+ /* write line */
+ Nick_DoLine(nick);
+
+ /* next line */
+ line++;
+ }
+ while (((nick->LPT.MB & 0x080)==0) && (line<ENTERPRISE_SCREEN_HEIGHT));
+
+}
+
+
+VIDEO_START( epnick )
+{
+ ep_state *state = machine.driver_data<ep_state>();
+ state->nick = auto_alloc_clear(machine, NICK_STATE);
+
+ state->nick->videoram = machine.device<ram_device>(RAM_TAG)->pointer();
+ Nick_Init(state->nick);
+ machine.primary_screen->register_screen_bitmap(state->m_bitmap);
+}
+
+
+SCREEN_UPDATE_IND16( epnick )
+{
+ ep_state *state = screen.machine().driver_data<ep_state>();
+ Nick_DoScreen(state->nick,state->m_bitmap);
+ copybitmap(bitmap, state->m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
diff --git a/src/mess/video/fm7.c b/src/mess/video/fm7.c
new file mode 100644
index 00000000000..3c3a713a79b
--- /dev/null
+++ b/src/mess/video/fm7.c
@@ -0,0 +1,1613 @@
+/*
+ *
+ * Fujitsu Micro 7 Video functions
+ *
+ */
+
+#include "emu.h"
+#include "cpu/m6809/m6809.h"
+#include "includes/fm7.h"
+
+
+/*
+ * Main CPU: Sub-CPU interface (port 0xfd05)
+ *
+ * Read:
+ * bit 7: Sub-CPU busy (or halted)
+ * bit 0: EXTDET (?)
+ * Write:
+ * bit 7: Sub-CPU halt
+ * bit 6: Sub-CPU cancel IRQ
+ */
+
+READ8_MEMBER(fm7_state::fm7_subintf_r)
+{
+ UINT8 ret = 0x00;
+
+ if(m_video.sub_busy != 0 || m_video.sub_halt != 0)
+ ret |= 0x80;
+
+ ret |= 0x7e;
+ //ret |= 0x01; // EXTDET (not implemented yet)
+
+ return ret;
+}
+
+WRITE8_MEMBER(fm7_state::fm7_subintf_w)
+{
+ m_video.sub_halt = data & 0x80;
+ if(data & 0x80)
+ m_video.sub_busy = data & 0x80;
+
+ cputag_set_input_line(machine(),"sub",INPUT_LINE_HALT,(data & 0x80) ? ASSERT_LINE : CLEAR_LINE);
+ if(data & 0x40)
+ cputag_set_input_line(machine(),"sub",M6809_IRQ_LINE,ASSERT_LINE);
+ //popmessage("Sub CPU Interface write: %02x\n",data);
+}
+
+READ8_MEMBER(fm7_state::fm7_sub_busyflag_r)
+{
+ if(m_video.sub_halt == 0)
+ m_video.sub_busy = 0x00;
+ return 0x00;
+}
+
+WRITE8_MEMBER(fm7_state::fm7_sub_busyflag_w)
+{
+ m_video.sub_busy = 0x80;
+}
+
+/*
+ * Sub-CPU port 0xd402
+ * Read-only: Acknowledge Cancel IRQ
+ */
+READ8_MEMBER(fm7_state::fm7_cancel_ack)
+{
+ cputag_set_input_line(machine(),"sub",M6809_IRQ_LINE,CLEAR_LINE);
+ return 0x00;
+}
+
+/*
+ * Reading from 0xd404 (sub-CPU) causes an "Attention" FIRQ on the main CPU
+ */
+READ8_MEMBER(fm7_state::fm7_attn_irq_r)
+{
+ m_video.attn_irq = 1;
+ cputag_set_input_line(machine(),"maincpu",M6809_FIRQ_LINE,ASSERT_LINE);
+ return 0xff;
+}
+
+/*
+ * Sub CPU: I/O port 0xd409
+ *
+ * On read, enables VRAM access
+ * On write, disables VRAM access
+ */
+READ8_MEMBER(fm7_state::fm7_vram_access_r)
+{
+ m_video.vram_access = 1;
+ return 0xff;
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram_access_w)
+{
+ m_video.vram_access = 0;
+}
+
+static TIMER_CALLBACK( fm77av_alu_task_end )
+{
+ fm7_state *state = machine.driver_data<fm7_state>();
+ state->m_alu.busy = 0;
+}
+
+static void fm7_alu_mask_write(fm7_state *state, UINT32 offset, int bank, UINT8 dat)
+{
+ UINT8 temp;
+ int page = 0;
+
+ if(offset >= 0xc000)
+ page = 1;
+
+ if((state->m_alu.command & 0x40) == 0)
+ { // "always" write mode
+ state->m_video_ram[(offset & 0x3fff) + (bank * 0x4000) + (page * 0xc000)] = dat;
+ return;
+ }
+
+ temp = state->m_video_ram[(offset & 0x3fff) + (bank * 0x4000) + (page * 0xc000)];
+ if(state->m_alu.command & 0x20)
+ { // "not equal" write mode
+ temp &= state->m_alu.compare_data;
+ dat &= ~state->m_alu.compare_data;
+ }
+ else
+ { // "equal" write mode
+ temp &= ~state->m_alu.compare_data;
+ dat &= state->m_alu.compare_data;
+ }
+
+ state->m_video_ram[(offset & 0x3fff) + (bank * 0x4000) + (page * 0xc000)] = temp | dat;
+}
+
+static void fm7_alu_function_compare(fm7_state *state, UINT32 offset)
+{
+ // COMPARE - compares which colors match those in the compare registers
+ // can be used on its own, or when bit 6 of the command register is high.
+
+ UINT8 red,green,blue;
+ UINT8 dat = 0;
+ UINT8 colour;
+ UINT8 banks;
+ int x,y;
+ int match;
+ int page = 0;
+ UINT8 bit = 0x80;
+
+ if(offset >= 0xc000)
+ {
+ page = 1;
+ offset += state->m_video.vram_offset2;
+ }
+ else
+ offset += state->m_video.vram_offset;
+
+ blue = state->m_video_ram[(offset & 0x3fff) + (page * 0xc000)];
+ red = state->m_video_ram[(offset & 0x3fff) + 0x4000 + (page * 0xc000)];
+ green = state->m_video_ram[(offset & 0x3fff) + 0x8000 + (page * 0xc000)];
+
+ banks = (~state->m_alu.bank_disable) & 0x07;
+
+ for(x=0;x<8;x++) // loop through each pixel
+ {
+ colour = 0;
+ if(blue & bit)
+ colour |= 1;
+ if(red & bit)
+ colour |= 2;
+ if(green & bit)
+ colour |= 4;
+
+ match = 0;
+ for(y=0;y<8;y++) // loop through each compare register
+ {
+ if(!(state->m_alu.compare[y] & 0x80)) // don't compare if register is masked
+ {
+ if((state->m_alu.compare[y] & banks) == (colour & banks))
+ match = 1;
+ }
+ }
+ if(match != 0)
+ dat |= bit;
+
+ bit >>= 1;
+ }
+ state->m_alu.compare_data = dat;
+}
+
+static void fm7_alu_function_pset(fm7_state *state, UINT32 offset)
+{
+ // PSET - simply sets the pixels to the selected logical colour
+ int x;
+ UINT8 dat;
+ int page = 0;
+ UINT8 mask;
+
+ if(state->m_alu.command & 0x40)
+ fm7_alu_function_compare(state, offset);
+
+ if(offset >= 0xc000)
+ {
+ page = 1;
+ offset += state->m_video.vram_offset2;
+ }
+ else
+ offset += state->m_video.vram_offset;
+
+ for(x=0;x<3;x++) // cycle through banks
+ {
+ if(!(state->m_alu.bank_disable & (1 << x)))
+ {
+ if(state->m_alu.lcolour & (1 << x))
+ dat = 0xff;
+ else
+ dat = 0;
+
+ mask = (state->m_video_ram[(offset & 0x3fff) + (x * 0x4000) + (page * 0xc000)]) & state->m_alu.mask;
+ dat &= ~state->m_alu.mask;
+ dat |= mask;
+
+ fm7_alu_mask_write(state, offset,x,dat);
+ }
+ }
+}
+
+static void fm7_alu_function_or(fm7_state *state, UINT32 offset)
+{
+ int x;
+ UINT8 dat;
+ int page = 0;
+ UINT8 mask;
+
+ if(state->m_alu.command & 0x40)
+ fm7_alu_function_compare(state, offset);
+
+ if(offset >= 0xc000)
+ {
+ page = 1;
+ offset += state->m_video.vram_offset2;
+ }
+ else
+ offset += state->m_video.vram_offset;
+
+ for(x=0;x<3;x++) // cycle through banks
+ {
+ if(!(state->m_alu.bank_disable & (1 << x)))
+ {
+ if(state->m_alu.lcolour & (1 << x))
+ dat = 0xff;
+ else
+ dat = 0;
+
+ mask = (state->m_video_ram[(offset & 0x3fff) + (x * 0x4000) + (page * 0xc000)]);
+ dat |= mask;
+
+ mask &= state->m_alu.mask;
+ dat &= ~state->m_alu.mask;
+ dat |= mask;
+
+ fm7_alu_mask_write(state, offset,x,dat);
+ }
+ }
+}
+
+static void fm7_alu_function_and(fm7_state *state, UINT32 offset)
+{
+ int x;
+ UINT8 dat;
+ int page = 0;
+ UINT8 mask;
+
+ if(state->m_alu.command & 0x40)
+ fm7_alu_function_compare(state, offset);
+
+ if(offset >= 0xc000)
+ {
+ page = 1;
+ offset += state->m_video.vram_offset2;
+ }
+ else
+ offset += state->m_video.vram_offset;
+
+ for(x=0;x<3;x++) // cycle through banks
+ {
+ if(!(state->m_alu.bank_disable & (1 << x)))
+ {
+ if(state->m_alu.lcolour & (1 << x))
+ dat = 0xff;
+ else
+ dat = 0;
+
+ mask = (state->m_video_ram[(offset & 0x3fff) + (x * 0x4000) + (page * 0xc000)]);
+ dat &= mask;
+
+ mask &= state->m_alu.mask;
+ dat &= ~state->m_alu.mask;
+ dat |= mask;
+
+ fm7_alu_mask_write(state, offset,x,dat);
+ }
+ }
+}
+
+static void fm7_alu_function_xor(fm7_state *state, UINT32 offset)
+{
+ int x;
+ UINT8 dat;
+ int page = 0;
+ UINT8 mask;
+
+ if(state->m_alu.command & 0x40)
+ fm7_alu_function_compare(state, offset);
+
+ if(offset >= 0xc000)
+ {
+ page = 1;
+ offset += state->m_video.vram_offset2;
+ }
+ else
+ offset += state->m_video.vram_offset;
+
+ for(x=0;x<3;x++) // cycle through banks
+ {
+ if(!(state->m_alu.bank_disable & (1 << x)))
+ {
+ if(state->m_alu.lcolour & (1 << x))
+ dat = 0xff;
+ else
+ dat = 0;
+
+ mask = (state->m_video_ram[(offset & 0x3fff) + (x * 0x4000) + (page * 0xc000)]);
+ dat ^= mask;
+
+ mask &= state->m_alu.mask;
+ dat &= ~state->m_alu.mask;
+ dat |= mask;
+
+ fm7_alu_mask_write(state, offset,x,dat);
+ }
+ }
+}
+
+static void fm7_alu_function_not(fm7_state *state, UINT32 offset)
+{
+ int x;
+ UINT8 dat;
+ int page = 0;
+ UINT8 mask;
+
+ if(state->m_alu.command & 0x40)
+ fm7_alu_function_compare(state, offset);
+
+ if(offset >= 0xc000)
+ {
+ page = 1;
+ offset += state->m_video.vram_offset2;
+ }
+ else
+ offset += state->m_video.vram_offset;
+
+ for(x=0;x<3;x++) // cycle through banks
+ {
+ if(!(state->m_alu.bank_disable & (1 << x)))
+ {
+ if(state->m_alu.lcolour & (1 << x))
+ dat = 0xff;
+ else
+ dat = 0;
+
+ mask = (state->m_video_ram[(offset & 0x3fff) + (x * 0x4000) + (page * 0xc000)]);
+ dat = ~mask;
+
+ mask &= state->m_alu.mask;
+ dat &= ~state->m_alu.mask;
+ dat |= mask;
+
+ fm7_alu_mask_write(state, offset,x,dat);
+ }
+ }
+}
+
+static void fm7_alu_function_invalid(fm7_state *state, UINT32 offset)
+{
+ // Invalid function, still does something though (used by Laydock)
+ int x;
+ UINT8 dat;
+ int page = 0;
+ UINT8 mask;
+
+ if(state->m_alu.command & 0x40)
+ fm7_alu_function_compare(state, offset);
+
+ if(offset >= 0xc000)
+ {
+ page = 1;
+ offset += state->m_video.vram_offset2;
+ }
+ else
+ offset += state->m_video.vram_offset;
+
+ for(x=0;x<3;x++) // cycle through banks
+ {
+ if(!(state->m_alu.bank_disable & (1 << x)))
+ {
+ mask = (state->m_video_ram[(offset & 0x3fff) + (x * 0x4000) + (page * 0xc000)]);
+
+ dat = mask & state->m_alu.mask;
+
+ fm7_alu_mask_write(state, offset,x,dat);
+ }
+ }
+}
+
+static void fm7_alu_function_tilepaint(fm7_state *state, UINT32 offset)
+{
+ // TILEPAINT - writes to VRAM based on the tilepaint colour registers
+ int x;
+ UINT8 dat = 0;
+ int page = 0;
+ UINT8 mask;
+
+ if(state->m_alu.command & 0x40)
+ fm7_alu_function_compare(state, offset);
+
+ if(offset >= 0xc000)
+ {
+ page = 1;
+ offset += state->m_video.vram_offset2;
+ }
+ else
+ offset += state->m_video.vram_offset;
+
+ for(x=0;x<3;x++) // cycle through banks
+ {
+ if(!(state->m_alu.bank_disable & (1 << x)))
+ {
+ switch(x)
+ {
+ case 0:
+ dat = state->m_alu.tilepaint_b;
+ break;
+ case 1:
+ dat = state->m_alu.tilepaint_r;
+ break;
+ case 2:
+ dat = state->m_alu.tilepaint_g;
+ break;
+ }
+ dat &= ~state->m_alu.mask;
+ mask = (state->m_video_ram[(offset & 0x3fff) + (x * 0x4000) + (page * 0xc000)]) & state->m_alu.mask;
+ dat |= mask;
+
+ fm7_alu_mask_write(state, offset,x,dat);
+ }
+ }
+}
+
+static void fm7_alu_function(fm7_state *state, UINT32 offset)
+{
+ switch(state->m_alu.command & 0x07)
+ {
+ case 0x00: // PSET
+ fm7_alu_function_pset(state, offset);
+ break;
+ case 0x02: // OR
+ fm7_alu_function_or(state, offset);
+ break;
+ case 0x03: // AND
+ fm7_alu_function_and(state, offset);
+ break;
+ case 0x04: // XOR
+ fm7_alu_function_xor(state, offset);
+ break;
+ case 0x05: // NOT
+ fm7_alu_function_not(state, offset);
+ break;
+ case 0x06: // TILEPAINT
+ fm7_alu_function_tilepaint(state, offset);
+ break;
+ case 0x07: // COMPARE
+ fm7_alu_function_compare(state, offset);
+ break;
+ case 0x01:
+ default:
+ fm7_alu_function_invalid(state, offset);
+ }
+}
+
+static UINT32 fm7_line_set_pixel(fm7_state *state, int x, int y)
+{
+ UINT32 addr;
+ static const UINT8 pixel_mask[8] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
+
+
+ if(state->m_video.modestatus & 0x40) // 320 pixels wide
+ {
+ addr = (x >> 3) + (y * 40);
+ }
+ else // 640 pixels wide
+ {
+ addr = (x >> 3) + (y * 80);
+ }
+ addr += (state->m_alu.addr_offset << 1);
+ addr &= 0x3fff;
+ if(state->m_video.active_video_page != 0)
+ addr += 0xc000;
+
+ if(state->m_alu.command & 0x80) // ALU must be active
+ {
+ state->m_alu.mask = pixel_mask[x & 0x07];
+ fm7_alu_function(state, addr);
+ }
+
+ return addr;
+}
+
+static void fm77av_line_draw(running_machine &machine)
+{
+ fm7_state *state = machine.driver_data<fm7_state>();
+ int x1 = state->m_alu.x0;
+ int x2 = state->m_alu.x1;
+ int y1 = state->m_alu.y0;
+ int y2 = state->m_alu.y1;
+ int horiz,vert;
+ int dirx,diry;
+ int rep;
+ int byte_count = 0;
+ UINT16 old_addr = 0xffff;
+ UINT16 addr;
+
+ state->m_alu.busy = 1;
+
+ horiz = x2 - x1;
+ vert = y2 - y1;
+
+ if(horiz < 0)
+ {
+ dirx = -1;
+ horiz = -horiz;
+ }
+ else
+ dirx = 1;
+ if(vert < 0)
+ {
+ diry = -1;
+ vert = -vert;
+ }
+ else
+ diry = 1;
+
+ if(horiz == 0 && vert == 0)
+ {
+ fm7_line_set_pixel(state, x1, y1);
+ byte_count = 1;
+ }
+ else if(horiz == 0)
+ {
+ for(;;)
+ {
+ addr = fm7_line_set_pixel(state, x1, y1);
+ if(addr != old_addr)
+ {
+ byte_count++;
+ old_addr = addr;
+ }
+ if(y1 == y2)
+ break;
+ y1 += diry;
+ }
+ }
+ else if(vert == 0)
+ {
+ for(;;)
+ {
+ addr = fm7_line_set_pixel(state, x1, y1);
+ if(addr != old_addr)
+ {
+ byte_count++;
+ old_addr = addr;
+ }
+ if(x1 == x2)
+ break;
+ x1 += dirx;
+ }
+ }
+ else if(horiz >= vert)
+ {
+ rep = horiz >> 1;
+ for(;;)
+ {
+ addr = fm7_line_set_pixel(state, x1, y1);
+ if(addr != old_addr)
+ {
+ byte_count++;
+ old_addr = addr;
+ }
+ if(x1 == x2)
+ break;
+ x1 += dirx;
+ rep -= vert;
+ if(rep < 0)
+ {
+ rep += horiz;
+ y1 += diry;
+ }
+ }
+ }
+ else
+ {
+ rep = vert >> 1;
+ for(;;)
+ {
+ addr = fm7_line_set_pixel(state, x1, y1);
+ if(addr != old_addr)
+ {
+ byte_count++;
+ old_addr = addr;
+ }
+ if(y1 == y2)
+ break;
+ y1 += diry;
+ rep -= horiz;
+ if(rep < 0)
+ {
+ rep += vert;
+ x1 += dirx;
+ }
+ }
+ }
+
+ // set timer to disable busy flag
+ // 1/16 us for each byte changed
+ machine.scheduler().timer_set(attotime::from_usec(byte_count/16), FUNC(fm77av_alu_task_end));
+}
+
+READ8_MEMBER(fm7_state::fm7_vram_r)
+{
+ int offs;
+ UINT16 page = 0x0000;
+
+ if(m_video.active_video_page != 0)
+ page = 0xc000;
+
+ if(offset < 0x4000 && (m_video.multi_page & 0x01))
+ return 0xff;
+ if((offset < 0x8000 && offset >=0x4000) && (m_video.multi_page & 0x02))
+ return 0xff;
+ if((offset < 0xc000 && offset >=0x8000) && (m_video.multi_page & 0x04))
+ return 0xff;
+
+ if(m_alu.command & 0x80) // ALU active, writes to VRAM even when reading it (go figure)
+ {
+ fm7_state *state = machine().driver_data<fm7_state>();
+ fm7_alu_function(state, offset+page);
+ }
+
+ if(m_video.modestatus & 0x40)
+ {
+ if(m_video.active_video_page != 0)
+ offs = (offset & 0xe000) | ((offset + m_video.vram_offset2) & 0x1fff);
+ else
+ offs = (offset & 0xe000) | ((offset + m_video.vram_offset) & 0x1fff);
+ }
+ else
+ {
+ if(m_video.active_video_page != 0)
+ offs = (offset & 0xc000) | ((offset + m_video.vram_offset2) & 0x3fff);
+ else
+ offs = (offset & 0xc000) | ((offset + m_video.vram_offset) & 0x3fff);
+ }
+ return m_video_ram[offs + page];
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram_w)
+{
+ int offs;
+ UINT16 page = 0x0000;
+
+ if(m_video.active_video_page != 0)
+ page = 0xc000;
+
+ if(offset < 0x4000 && (m_video.multi_page & 0x01))
+ return;
+ if((offset < 0x8000 && offset >=0x4000) && (m_video.multi_page & 0x02))
+ return;
+ if((offset < 0xc000 && offset >=0x8000) && (m_video.multi_page & 0x04))
+ return;
+
+ if(m_alu.command & 0x80) // ALU active
+ {
+ fm7_state *state = machine().driver_data<fm7_state>();
+ fm7_alu_function(state, offset+page);
+ return;
+ }
+
+ if(m_video.modestatus & 0x40)
+ {
+ if(m_video.active_video_page != 0)
+ offs = (offset & 0xe000) | ((offset + m_video.vram_offset2) & 0x1fff);
+ else
+ offs = (offset & 0xe000) | ((offset + m_video.vram_offset) & 0x1fff);
+ }
+ else
+ {
+ if(m_video.active_video_page != 0)
+ offs = (offset & 0xc000) | ((offset + m_video.vram_offset2) & 0x3fff);
+ else
+ offs = (offset & 0xc000) | ((offset + m_video.vram_offset) & 0x3fff);
+ }
+// if(m_video.vram_access != 0)
+ m_video_ram[offs+page] = data;
+}
+
+// not pretty, but it should work.
+WRITE8_MEMBER(fm7_state::fm7_vram_banked_w)
+{
+ int offs;
+ UINT16 page = 0x0000;
+
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return;
+
+ if(m_video.active_video_page != 0)
+ page = 0xc000;
+
+ if(offset < 0x4000 && (m_video.multi_page & 0x01))
+ return;
+ if((offset < 0x8000 && offset >=0x4000) && (m_video.multi_page & 0x02))
+ return;
+ if((offset < 0xc000 && offset >=0x8000) && (m_video.multi_page & 0x04))
+ return;
+
+ if(m_alu.command & 0x80) // ALU active
+ {
+ fm7_state *state = machine().driver_data<fm7_state>();
+ fm7_alu_function(state, offset+page);
+ return;
+ }
+
+ if(m_video.modestatus & 0x40)
+ {
+ if(m_video.active_video_page != 0)
+ offs = (offset & 0xe000) | ((offset + m_video.vram_offset2) & 0x1fff);
+ else
+ offs = (offset & 0xe000) | ((offset + m_video.vram_offset) & 0x1fff);
+ }
+ else
+ {
+ if(m_video.active_video_page != 0)
+ offs = (offset & 0xc000) | ((offset + m_video.vram_offset2) & 0x3fff);
+ else
+ offs = (offset & 0xc000) | ((offset + m_video.vram_offset) & 0x3fff);
+ }
+ m_video_ram[offs+page] = data;
+}
+
+READ8_MEMBER(fm7_state::fm7_vram0_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset);
+}
+
+READ8_MEMBER(fm7_state::fm7_vram1_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0x1000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vram2_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0x2000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vram3_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0x3000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vram4_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0x4000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vram5_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0x5000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vram6_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0x6000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vram7_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0x7000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vram8_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0x8000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vram9_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0x9000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vramA_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0xa000);
+}
+
+READ8_MEMBER(fm7_state::fm7_vramB_r)
+{
+ if(!m_video.sub_halt) // no access if sub CPU is not halted.
+ return 0xff;
+ return fm7_vram_r(space,offset+0xb000);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram0_w)
+{
+ fm7_vram_banked_w(space,offset,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram1_w)
+{
+ fm7_vram_banked_w(space,offset+0x1000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram2_w)
+{
+ fm7_vram_banked_w(space,offset+0x2000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram3_w)
+{
+ fm7_vram_banked_w(space,offset+0x3000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram4_w)
+{
+ fm7_vram_banked_w(space,offset+0x4000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram5_w)
+{
+ fm7_vram_banked_w(space,offset+0x5000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram6_w)
+{
+ fm7_vram_banked_w(space,offset+0x6000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram7_w)
+{
+ fm7_vram_banked_w(space,offset+0x7000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram8_w)
+{
+ fm7_vram_banked_w(space,offset+0x8000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vram9_w)
+{
+ fm7_vram_banked_w(space,offset+0x9000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vramA_w)
+{
+ fm7_vram_banked_w(space,offset+0xa000,data);
+}
+
+WRITE8_MEMBER(fm7_state::fm7_vramB_w)
+{
+ fm7_vram_banked_w(space,offset+0xb000,data);
+}
+
+/*
+ * Sub CPU: I/O port 0xd408
+ *
+ * On read, enables the CRT display
+ * On write, disables the CRT display
+ */
+READ8_MEMBER(fm7_state::fm7_crt_r)
+{
+ m_video.crt_enable = 1;
+ return 0xff;
+}
+
+WRITE8_MEMBER(fm7_state::fm7_crt_w)
+{
+ m_video.crt_enable = 0;
+}
+
+/*
+ * Sub CPU: I/O ports 0xd40e - 0xd40f
+ *
+ * 0xd40e: bits 0-6 - offset in bytes (high byte) (bit 6 is used for 400 line video only)
+ * 0xd40f: bits 0-7 - offset in bytes (low byte)
+ */
+WRITE8_MEMBER(fm7_state::fm7_vram_offset_w)
+{
+ UINT16 new_offset = 0;
+
+ switch(offset)
+ {
+ case 0:
+ if(m_video.active_video_page != 0)
+ new_offset = ((data & 0x3f) << 8) | (m_video.vram_offset2 & 0x00ff);
+ else
+ new_offset = ((data & 0x3f) << 8) | (m_video.vram_offset & 0x00ff);
+ break;
+ case 1: // low 5 bits are used on FM-77AV and later only
+ if(m_type == SYS_FM7)
+ new_offset = (m_video.vram_offset & 0xff00) | (data & 0xe0);
+ else
+ {
+ if(m_video.active_video_page != 0)
+ {
+ if(m_video.fine_offset != 0)
+ new_offset = (m_video.vram_offset2 & 0xff00) | (data & 0xff);
+ else
+ new_offset = (m_video.vram_offset2 & 0xff00) | (data & 0xe0);
+ }
+ else
+ {
+ if(m_video.fine_offset != 0)
+ new_offset = (m_video.vram_offset & 0xff00) | (data & 0xff);
+ else
+ new_offset = (m_video.vram_offset & 0xff00) | (data & 0xe0);
+ }
+ }
+ break;
+ }
+ if(m_video.active_video_page != 0)
+ m_video.vram_offset2 = new_offset;
+ else
+ m_video.vram_offset = new_offset;
+}
+
+/*
+ * Main CPU: port 0xfd37
+ * Multipage
+ * Port is write-only
+ *
+ * bits 6-4: VRAM planes to display (G,R,B) (1=disable)
+ * bits 2-0: VRAM CPU access (G,R,B) (1=disable)
+ */
+WRITE8_MEMBER(fm7_state::fm7_multipage_w)
+{
+ m_video.multi_page = data & 0x77;
+}
+
+/*
+ * Main CPU: I/O ports 0xfd38-0xfd3f
+ * Colour palette.
+ * Each port represents one of eight colours. Palette is 3-bit.
+ * bit 2 = Green
+ * bit 1 = Red
+ * bit 0 = Blue
+ */
+READ8_MEMBER(fm7_state::fm7_palette_r)
+{
+ return m_video.fm7_pal[offset];
+}
+
+WRITE8_MEMBER(fm7_state::fm7_palette_w)
+{
+ UINT8 r = 0,g = 0,b = 0;
+
+ if(data & 0x04)
+ g = 0xff;
+ if(data & 0x02)
+ r = 0xff;
+ if(data & 0x01)
+ b = 0xff;
+
+ palette_set_color(machine(),offset,MAKE_RGB(r,g,b));
+ m_video.fm7_pal[offset] = data & 0x07;
+}
+
+/*
+ * Main CPU: 0xfd30 - 0xfd34
+ * Analog colour palette (FM-77AV and later only)
+ * All ports are write-only.
+ *
+ * fd30: colour select(?) high 4 bits (LC11-LC8)
+ * fd31: colour select(?) low 8 bits (LC7-LC0)
+ * fd32: blue level (4 bits)
+ * fd33: red level (4 bits)
+ * fd34: green level (4 bits)
+ */
+WRITE8_MEMBER(fm7_state::fm77av_analog_palette_w)
+{
+ int val;
+
+ switch(offset)
+ {
+ case 0:
+ val = ((data & 0x0f) << 8) | (m_video.fm77av_pal_selected & 0x00ff);
+ m_video.fm77av_pal_selected = val;
+ break;
+ case 1:
+ val = data | (m_video.fm77av_pal_selected & 0x0f00);
+ m_video.fm77av_pal_selected = val;
+ break;
+ case 2:
+ m_video.fm77av_pal_b[m_video.fm77av_pal_selected] = (data & 0x0f) << 4;
+ palette_set_color(machine(),m_video.fm77av_pal_selected+8,
+ MAKE_RGB(m_video.fm77av_pal_r[m_video.fm77av_pal_selected],
+ m_video.fm77av_pal_g[m_video.fm77av_pal_selected],
+ m_video.fm77av_pal_b[m_video.fm77av_pal_selected]));
+ break;
+ case 3:
+ m_video.fm77av_pal_r[m_video.fm77av_pal_selected] = (data & 0x0f) << 4;
+ palette_set_color(machine(),m_video.fm77av_pal_selected+8,
+ MAKE_RGB(m_video.fm77av_pal_r[m_video.fm77av_pal_selected],
+ m_video.fm77av_pal_g[m_video.fm77av_pal_selected],
+ m_video.fm77av_pal_b[m_video.fm77av_pal_selected]));
+ break;
+ case 4:
+ m_video.fm77av_pal_g[m_video.fm77av_pal_selected] = (data & 0x0f) << 4;
+ palette_set_color(machine(),m_video.fm77av_pal_selected+8,
+ MAKE_RGB(m_video.fm77av_pal_r[m_video.fm77av_pal_selected],
+ m_video.fm77av_pal_g[m_video.fm77av_pal_selected],
+ m_video.fm77av_pal_b[m_video.fm77av_pal_selected]));
+ break;
+ }
+}
+
+
+/*
+ * Sub CPU: 0xd430 - BUSY/NMI/Bank register (FM77AV series only)
+ *
+ * On read: bit 7 - 0 if in VBlank
+ * bit 4 - ALU busy(0)/ready(1)
+ * bit 2 - VSync status (1 if active?)
+ * bit 0 - RESET
+ *
+ * On write: bits 1-0 - CGROM select (maps to 0xd800)
+ * bit 2 - fine offset enable (enables OA4-OA0 bits in VRAM offset)
+ * bit 5 - active VRAM page
+ * bit 6 - display VRAM page
+ * bit 7 - NMI mask register (1=mask)
+ */
+READ8_MEMBER(fm7_state::fm77av_video_flags_r)
+{
+ UINT8 ret = 0xff;
+
+ if(machine().primary_screen->vblank())
+ ret &= ~0x80;
+
+ if(m_alu.busy != 0)
+ ret &= ~0x10;
+
+ if(m_video.vsync_flag == 0)
+ ret &= ~0x04;
+
+ if(!m_video.sub_reset)
+ ret &= ~0x01;
+
+ return ret;
+}
+
+WRITE8_MEMBER(fm7_state::fm77av_video_flags_w)
+{
+ UINT8* RAM = memregion("subsyscg")->base();
+
+ m_video.cgrom = data & 0x03;
+ membank("bank20")->set_base(RAM+(m_video.cgrom*0x800));
+ m_video.fine_offset = data & 0x04;
+ m_video.active_video_page = data & 0x20;
+ m_video.display_video_page = data & 0x40;
+ m_video.nmi_mask = data & 0x80;
+}
+
+/*
+ * Main CPU: port 0xfd12
+ * Sub mode status register (FM-77AV or later)
+ * bit 6 (R/W) - Video mode width(?) 0=640 (default) 1=320.
+ * bit 1 (R/O) - DISPTMG status (0=blank)
+ * bit 0 (R/O) - VSync status (1=sync?)
+ */
+READ8_MEMBER(fm7_state::fm77av_sub_modestatus_r)
+{
+ UINT8 ret = 0x00;
+
+ ret |= 0xbc;
+ ret |= (m_video.modestatus & 0x40);
+
+ if(!machine().primary_screen->vblank())
+ ret |= 0x02;
+
+ if(m_video.vsync_flag != 0)
+ ret |= 0x01;
+
+ return ret;
+}
+
+WRITE8_MEMBER(fm7_state::fm77av_sub_modestatus_w)
+{
+ m_video.modestatus = data & 0x40;
+ if(data & 0x40)
+ {
+ rectangle rect(0, 320-1, 0, 200-1);
+ machine().primary_screen->configure(320,200,rect,HZ_TO_ATTOSECONDS(60));
+ }
+ else
+ {
+ rectangle rect(0, 640-1, 0, 200-1);
+ machine().primary_screen->configure(640,200,rect,HZ_TO_ATTOSECONDS(60));
+ }
+}
+
+/*
+ * Main CPU: port 0xfd13
+ * Sub Bank select register
+ *
+ * bits 1 and 0 select which subsys ROM to be banked into sub CPU space
+ * on the FM-77AV40 and later, bit 2 can also selected to bank in sub monitor RAM.
+ */
+WRITE8_MEMBER(fm7_state::fm77av_sub_bank_w)
+{
+// UINT8* RAM = memregion("sub")->base();
+ UINT8* ROM;
+
+ if((data & 0x03) == (m_sb_prev & 0x03))
+ return;
+
+ m_video.subrom = data & 0x03;
+ switch (data & 0x03)
+ {
+ case 0x00: // Type C, 640x200 (as used on the FM-7)
+ ROM = memregion("subsys_c")->base();
+ // membank(20)->set_base(ROM);
+ membank("bank21")->set_base(ROM+0x800);
+ logerror("VID: Sub ROM Type C selected\n");
+ break;
+ case 0x01: // Type A, 640x200
+ ROM = memregion("subsys_a")->base();
+ // membank(20)->set_base(RAM+0xd800);
+ membank("bank21")->set_base(ROM);
+ logerror("VID: Sub ROM Type A selected\n");
+ break;
+ case 0x02: // Type B, 320x200
+ ROM = memregion("subsys_b")->base();
+ // membank(20)->set_base(RAM+0xd800);
+ membank("bank21")->set_base(ROM);
+ logerror("VID: Sub ROM Type B selected\n");
+ break;
+ case 0x03: // CG Font?
+ ROM = memregion("subsyscg")->base();
+ // membank(20)->set_base(RAM+0xd800);
+ membank("bank21")->set_base(ROM);
+ logerror("VID: Sub ROM CG selected\n");
+ break;
+ }
+ // reset sub CPU, set busy flag, set reset flag
+ cputag_set_input_line(machine(),"sub",INPUT_LINE_RESET,PULSE_LINE);
+ m_video.sub_busy = 0x80;
+ m_video.sub_halt = 0;
+ m_video.sub_reset = 1;
+ m_sb_prev = data;
+}
+
+/*
+ * Sub CPU: ports 0xd410-0xd42b (FM-77AV and later only)
+ * Video operations
+ *
+ * 0xd410 (R/W): Command register
+ * bit 7: 0=DIS 1=Start
+ * bits 6-5: MBIT1, MBIT2
+ * bits 2-0: Draw mode
+ * 0 0 0 - PSET
+ * 0 1 0 - OR
+ * 0 1 1 - AND
+ * 1 0 0 - XOR
+ * 1 0 1 - NOT
+ * 1 1 0 - TILEPAINT
+ * 1 1 1 - COMPARE
+ * 0xd411 (R/W): Logical colour (bits 2-0, G-R-B)
+ * 0xd412 (R/W): Mask register
+ * 0xd413 (R) : Compare data (?)
+ * 0xd413-1a(W): Compare registers (bits 2-0, G-R-B, 1=mask (bit 7))
+ * 0xd41b (R/W): Bank disable register (bits 2-0, G-R-B, 1=disable, bit 3 must always be 1)
+ * 0xd41c-1e(W): Tilepaint registers (B-R-G)
+ * 0xd420-21(W): Line Address offset register (High-Low, A13-A1)
+ * 0xd422-23(W): Line style pattern register (High-Low, P15-P0)
+ * 0xd424-25(W): Line X0 (High-Low, X9-X0)
+ * 0xd426-27(W): Line Y0 (High-Low, Y8-Y0)
+ * 0xd428-29(W): Line X1 (High-Low, X9-X0)
+ * 0xd42a-2b(W): Line Y1 (High-Low, Y8-Y0)
+ */
+READ8_MEMBER(fm7_state::fm77av_alu_r)
+{
+ switch(offset)
+ {
+ case 0x00:
+ logerror("ALU: read from command register (%02x)\n",m_alu.command);
+ return m_alu.command;
+ case 0x01:
+ logerror("ALU: read from logical colour\n");
+ return m_alu.lcolour;
+ case 0x02:
+ logerror("ALU: read from mask register\n");
+ return m_alu.mask;
+ case 0x03:
+ logerror("ALU: read from compare data register (%02x)\n",m_alu.compare_data);
+ return m_alu.compare_data;
+ case 0x0b:
+ logerror("ALU: read from bank disable register\n");
+ return 0xf7 | m_alu.bank_disable;
+ default:
+ logerror("ALU: read from invalid register 0x%02x\n",offset);
+ return 0xff;
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(fm7_state::fm77av_alu_w)
+{
+ UINT16 dat;
+
+ switch(offset)
+ {
+ case 0x00:
+ m_alu.command = data;
+ logerror("ALU: write to command register - %02x\n",data);
+ break;
+ case 0x01:
+ m_alu.lcolour = data & 0x07;
+ logerror("ALU: write to logical colour - %02x\n",data);
+ break;
+ case 0x02:
+ m_alu.mask = data;
+ logerror("ALU: write to mask register - %02x\n",data);
+ break;
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ m_alu.compare[offset-3] = data;
+ logerror("ALU: write to compare register %i - %02x\n",offset-3,data);
+ break;
+ case 0x0b:
+ m_alu.bank_disable = data & 0x03;
+// logerror("ALU: write to bank disable register - %02x\n",data);
+ break;
+ case 0x0c:
+ m_alu.tilepaint_b = data;
+// logerror("ALU: write to tilepaint (blue) register - %02x\n",data);
+ break;
+ case 0x0d:
+ m_alu.tilepaint_r = data;
+// logerror("ALU: write to tilepaint (red) register - %02x\n",data);
+ break;
+ case 0x0e:
+ m_alu.tilepaint_g = data;
+// logerror("ALU: write to tilepaint (green) register - %02x\n",data);
+ break;
+ case 0x10:
+ dat = ((data & 0x1f) << 8) | (m_alu.addr_offset & 0x00ff);
+ m_alu.addr_offset = dat;
+// logerror("ALU: write to address offset (high) register - %02x (%04x)\n",data,m_alu.addr_offset);
+ break;
+ case 0x11:
+ dat = (m_alu.addr_offset & 0xff00) | data;
+ m_alu.addr_offset = dat;
+// logerror("ALU: write to address offset (low) register - %02x (%04x)\n",data,m_alu.addr_offset);
+ break;
+ case 0x12:
+ dat = (data << 8) | (m_alu.line_style & 0x00ff);
+ m_alu.line_style = dat;
+// logerror("ALU: write to line style (high) register - %02x (%04x)\n",data,m_alu.line_style);
+ break;
+ case 0x13:
+ dat = (m_alu.line_style & 0xff00) | data;
+ m_alu.line_style = dat;
+// logerror("ALU: write to line style (low) register - %02x (%04x)\n",data,m_alu.line_style);
+ break;
+ case 0x14:
+ dat = ((data & 0x03) << 8) | (m_alu.x0 & 0x00ff);
+ m_alu.x0 = dat;
+// logerror("ALU: write to X0 (high) register - %02x (%04x)\n",data,m_alu.x0);
+ break;
+ case 0x15:
+ dat = (m_alu.x0 & 0xff00) | data;
+ m_alu.x0 = dat;
+// logerror("ALU: write to X0 (low) register - %02x (%04x)\n",data,m_alu.x0);
+ break;
+ case 0x16:
+ dat = ((data & 0x01) << 8) | (m_alu.y0 & 0x00ff);
+ m_alu.y0 = dat;
+// logerror("ALU: write to Y0 (high) register - %02x (%04x)\n",data,m_alu.y0);
+ break;
+ case 0x17:
+ dat = (m_alu.y0 & 0xff00) | data;
+ m_alu.y0 = dat;
+// logerror("ALU: write to Y0 (low) register - %02x (%04x)\n",data,m_alu.y0);
+ break;
+ case 0x18:
+ dat = ((data & 0x03) << 8) | (m_alu.x1 & 0x00ff);
+ m_alu.x1 = dat;
+// logerror("ALU: write to X1 (high) register - %02x (%04x)\n",data,m_alu.x1);
+ break;
+ case 0x19:
+ dat = (m_alu.x1 & 0xff00) | data;
+ m_alu.x1 = dat;
+// logerror("ALU: write to X1 (low) register - %02x (%04x)\n",data,m_alu.x1);
+ break;
+ case 0x1a:
+ dat = ((data & 0x01) << 8) | (m_alu.y1 & 0x00ff);
+ m_alu.y1 = dat;
+// logerror("ALU: write to Y1 (high) register - %02x (%04x)\n",data,m_alu.y1);
+ break;
+ case 0x1b:
+ dat = (m_alu.y1 & 0xff00) | data;
+ m_alu.y1 = dat;
+ // draw line
+ fm77av_line_draw(machine());
+// logerror("ALU: write to Y1 (low) register - %02x (%04x)\n",data,m_alu.y1);
+ break;
+ default:
+ logerror("ALU: write 0x%02x to invalid register 0x%02x\n",data,offset);
+ }
+}
+
+TIMER_CALLBACK( fm77av_vsync )
+{
+ fm7_state *state = machine.driver_data<fm7_state>();
+ if(param == 0) // start of vsync
+ {
+ state->m_video.vsync_flag = 1;
+ state->m_fm77av_vsync_timer->adjust(attotime::from_usec(510),1); // VSync length for 200 line modes = 0.51ms
+ }
+ else
+ {
+ state->m_video.vsync_flag = 0;
+ state->m_fm77av_vsync_timer->adjust(machine.primary_screen->time_until_vblank_end());
+ }
+}
+
+// called when banked into main CPU space by the MMR, available only if sub CPU is halted
+READ8_MEMBER(fm7_state::fm7_sub_ram_ports_banked_r)
+{
+ UINT8* RAM = memregion("maincpu")->base();
+ UINT8* ROM;
+
+ if(!m_video.sub_halt)
+ return 0xff;
+
+ if(offset < 0x380) // work RAM
+ return RAM[0x1d000+offset];
+ if(offset >= 0x380 && offset < 0x400) // shared RAM
+ return m_shared_ram[offset-0x380];
+ if(offset >= 0x500 && offset < 0x800) // work RAM
+ return RAM[0x1d000+offset];
+ if(offset > 0x800) // CGROM
+ {
+ ROM = memregion("subsyscg")->base();
+ return ROM[(m_video.cgrom*0x800)+(offset-0x800)];
+ }
+
+ if(offset >= 0x410 && offset <= 0x42b)
+ return fm77av_alu_r(space,offset-0x410);
+
+ switch(offset)
+ {
+ case 0x400:
+ case 0x401:
+ return fm7_sub_keyboard_r(space,offset-0x400);
+ case 0x402:
+ return fm7_cancel_ack(space,0);
+ case 0x403:
+ return fm7_sub_beeper_r(space,0);
+ case 0x404:
+ return fm7_attn_irq_r(space,0);
+ case 0x408:
+ return fm7_crt_r(space,0);
+ case 0x409:
+ return fm7_vram_access_r(space,0);
+ case 0x40a:
+ return fm7_sub_busyflag_r(space,0);
+ case 0x430:
+ return fm77av_video_flags_r(space,0);
+ case 0x431:
+ case 0x432:
+ return fm77av_key_encoder_r(space,offset-0x431);
+ default:
+ logerror("Unmapped read from sub CPU port 0xd%03x via MMR banking\n",offset);
+ return 0xff;
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(fm7_state::fm7_sub_ram_ports_banked_w)
+{
+ UINT8* RAM = memregion("maincpu")->base();
+
+ if(!m_video.sub_halt)
+ return;
+
+ if(offset < 0x380) // work RAM
+ {
+ RAM[0x1d000+offset] = data;
+ return;
+ }
+ if(offset >= 0x380 && offset < 0x400) // shared RAM
+ {
+ m_shared_ram[offset-0x380] = data;
+ return;
+ }
+ if(offset >= 0x500 && offset < 0x800) // work RAM
+ {
+ RAM[0x1d000+offset] = data;
+ return;
+ }
+
+ if(offset >= 0x410 && offset <= 0x42b)
+ {
+ fm77av_alu_w(space,offset-0x410,data);
+ return;
+ }
+
+ switch(offset)
+ {
+ case 0x408:
+ fm7_crt_w(space,0,data);
+ break;
+ case 0x409:
+ fm7_vram_access_w(space,0,data);
+ break;
+ case 0x40a:
+ fm7_sub_busyflag_w(space,0,data);
+ break;
+ case 0x40e:
+ case 0x40f:
+ fm7_vram_offset_w(space,offset-0x40e,data);
+ break;
+ case 0x430:
+ fm77av_video_flags_w(space,0,data);
+ break;
+ case 0x431:
+ case 0x432:
+ fm77av_key_encoder_w(space,offset-0x431,data);
+ break;
+ default:
+ logerror("Unmapped write of 0x%02x to sub CPU port 0xd%03x via MMR banking\n",data,offset);
+ }
+}
+
+READ8_MEMBER(fm7_state::fm7_console_ram_banked_r)
+{
+ UINT8* RAM = memregion("maincpu")->base();
+
+ if(!m_video.sub_halt)
+ return 0xff;
+
+ return RAM[0x1c000+offset];
+}
+
+WRITE8_MEMBER(fm7_state::fm7_console_ram_banked_w)
+{
+ UINT8* RAM = memregion("maincpu")->base();
+
+ if(!m_video.sub_halt)
+ return;
+
+ RAM[0x1c000+offset] = data;
+}
+
+VIDEO_START( fm7 )
+{
+ fm7_state *state = machine.driver_data<fm7_state>();
+ state->m_video.vram_access = 0;
+ state->m_video.crt_enable = 0;
+ state->m_video.vram_offset = 0x0000;
+ state->m_video.vram_offset2 = 0x0000;
+ state->m_video.sub_reset = 0;
+ state->m_video.multi_page = 0;
+ state->m_video.subrom = 0;
+ state->m_video.cgrom = 0;
+ state->m_video.fine_offset = 0;
+ state->m_video.nmi_mask = 0;
+ state->m_video.active_video_page = 0;
+ state->m_video.display_video_page = 0;
+ state->m_video.vsync_flag = 0;
+}
+
+SCREEN_UPDATE_IND16( fm7 )
+{
+ fm7_state *state = screen.machine().driver_data<fm7_state>();
+ UINT8 code_r = 0,code_g = 0,code_b = 0;
+ UINT8 code_r2 = 0,code_g2 = 0,code_b2 = 0;
+ UINT8 code_r3 = 0,code_g3 = 0,code_b3 = 0;
+ UINT8 code_r4 = 0,code_g4 = 0,code_b4 = 0;
+ UINT16 col;
+ int y, x, b;
+ UINT16 page = 0x0000;
+
+ if(state->m_video.display_video_page != 0)
+ page = 0xc000;
+
+ if(state->m_video.crt_enable == 0)
+ return 0;
+
+ if(state->m_video.modestatus & 0x40) // 320x200 mode
+ {
+ for (y = 0; y < 200; y++)
+ {
+ for (x = 0; x < 40; x++)
+ {
+ if(!(state->m_video.multi_page & 0x40))
+ {
+ code_r = state->m_video_ram[0x8000 + ((y*40 + x + state->m_video.vram_offset) & 0x1fff)];
+ code_r2 = state->m_video_ram[0xa000 + ((y*40 + x + state->m_video.vram_offset) & 0x1fff)];
+ code_r3 = state->m_video_ram[0x14000 + ((y*40 + x + state->m_video.vram_offset2) & 0x1fff)];
+ code_r4 = state->m_video_ram[0x16000 + ((y*40 + x + state->m_video.vram_offset2) & 0x1fff)];
+ }
+ if(!(state->m_video.multi_page & 0x20))
+ {
+ code_g = state->m_video_ram[0x4000 + ((y*40 + x + state->m_video.vram_offset) & 0x1fff)];
+ code_g2 = state->m_video_ram[0x6000 + ((y*40 + x + state->m_video.vram_offset) & 0x1fff)];
+ code_g3 = state->m_video_ram[0x10000 + ((y*40 + x + state->m_video.vram_offset2) & 0x1fff)];
+ code_g4 = state->m_video_ram[0x12000 + ((y*40 + x + state->m_video.vram_offset2) & 0x1fff)];
+ }
+ if(!(state->m_video.multi_page & 0x10))
+ {
+ code_b = state->m_video_ram[0x0000 + ((y*40 + x + state->m_video.vram_offset) & 0x1fff)];
+ code_b2 = state->m_video_ram[0x2000 + ((y*40 + x + state->m_video.vram_offset) & 0x1fff)];
+ code_b3 = state->m_video_ram[0xc000 + ((y*40 + x + state->m_video.vram_offset2) & 0x1fff)];
+ code_b4 = state->m_video_ram[0xe000 + ((y*40 + x + state->m_video.vram_offset2) & 0x1fff)];
+ }
+ for (b = 0; b < 8; b++)
+ {
+ col = (((code_b >> b) & 0x01) ? 8 : 0) | (((code_b2 >> b) & 0x01) ? 4 : 0) | (((code_b3 >> b) & 0x01) ? 2 : 0) | (((code_b4 >> b) & 0x01) ? 1 : 0);
+ col |= (((code_g >> b) & 0x01) ? 128 : 0) | (((code_g2 >> b) & 0x01) ? 64 : 0) | (((code_g3 >> b) & 0x01) ? 32 : 0) | (((code_g4 >> b) & 0x01) ? 16 : 0);
+ col |= (((code_r >> b) & 0x01) ? 2048 : 0) | (((code_r2 >> b) & 0x01) ? 1024 : 0) | (((code_r3 >> b) & 0x01) ? 512 : 0) | (((code_r4 >> b) & 0x01) ? 256 : 0);
+ col += 8; // use analog palette
+ bitmap.pix16(y, x*8+(7-b)) = col;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (y = 0; y < 200; y++)
+ {
+ for (x = 0; x < 80; x++)
+ {
+ if(!(state->m_video.multi_page & 0x40))
+ code_r = state->m_video_ram[page + 0x8000 + ((y*80 + x + state->m_video.vram_offset) & 0x3fff)];
+ if(!(state->m_video.multi_page & 0x20))
+ code_g = state->m_video_ram[page + 0x4000 + ((y*80 + x + state->m_video.vram_offset) & 0x3fff)];
+ if(!(state->m_video.multi_page & 0x10))
+ code_b = state->m_video_ram[page + 0x0000 + ((y*80 + x + state->m_video.vram_offset) & 0x3fff)];
+ for (b = 0; b < 8; b++)
+ {
+ col = (((code_r >> b) & 0x01) ? 4 : 0) + (((code_g >> b) & 0x01) ? 2 : 0) + (((code_b >> b) & 0x01) ? 1 : 0);
+ bitmap.pix16(y, x*8+(7-b)) = col;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static const rgb_t fm7_initial_palette[8] = {
+ MAKE_RGB(0x00, 0x00, 0x00), // 0
+ MAKE_RGB(0x00, 0x00, 0xff), // 1
+ MAKE_RGB(0xff, 0x00, 0x00), // 2
+ MAKE_RGB(0xff, 0x00, 0xff), // 3
+ MAKE_RGB(0x00, 0xff, 0x00), // 4
+ MAKE_RGB(0x00, 0xff, 0xff), // 5
+ MAKE_RGB(0xff, 0xff, 0x00), // 6
+ MAKE_RGB(0xff, 0xff, 0xff), // 7
+};
+
+PALETTE_INIT( fm7 )
+{
+ fm7_state *state = machine.driver_data<fm7_state>();
+ int x;
+
+ palette_set_colors(machine, 0, fm7_initial_palette, ARRAY_LENGTH(fm7_initial_palette));
+ for(x=0;x<8;x++)
+ state->m_video.fm7_pal[x] = x;
+}
+
diff --git a/src/mess/video/fmtowns.c b/src/mess/video/fmtowns.c
new file mode 100644
index 00000000000..f64385cde2c
--- /dev/null
+++ b/src/mess/video/fmtowns.c
@@ -0,0 +1,1867 @@
+
+/*
+ * FM Towns video hardware
+ *
+ * Resolution: from 320x200 to 768x512
+ *
+ * Up to two graphics layers
+ *
+ * Sprites
+ *
+ * CRTC registers (16-bit):
+ *
+ * 0: HSync width 1
+ * 1: HSync width 2
+ * 4: HSync total
+ * 5: VSync width 1
+ * 6: VSync width 2
+ * 7: Equalising pulse accountable time (what?)
+ * 8: VSync total
+ *
+ * 9:
+ * 10: Graphic layer 0 horizontal start/end
+ * 11:
+ * 12: Graphic layer 1 horizontal start/end
+ *
+ * 13:
+ * 14: Graphic layer 0 vertical start/end
+ * 15:
+ * 16: Graphic layer 1 vertical start/end
+ *
+ * 17: Graphic layer 0 initial address?
+ * 18: Graphic layer 0 horizontal adjust
+ * 19: Graphic layer 0 field indirect address offset
+ * 20: Graphic layer 0 line indirect address offset
+ *
+ * 21-24: As above, but for Graphic layer 1
+ *
+ * 27: Layer zoom. bit 0 = x2 horizontal zoom layer 0
+ * to be confirmed bit 5 = x2 vertical zoom layer 0
+ * bit 9 = x2 horizontal zoom layer 1
+ * bit 13 = x2 vertical zoom layer 1
+ *
+ * 28: Control register 0
+ * VSync enable (bit 15) (blank display?)
+ * Scroll type (layer 0 = bit 4, layer 1 = bit 5)
+ * 0 = spherical scroll, 1 = cylindrical scroll
+ *
+ * 29: Control register 1
+ * Dot clock (bits 1 and 0)
+ * 0x00 = 28.6363MHz
+ * 0x01 = 24.5454MHz
+ * 0x02 = 25.175MHz
+ * 0x03 = 21.0525MHz (default?)
+ *
+ * 30: Dummy register
+ *
+ * 31: Control register 2
+ *
+ * Video registers:
+ *
+ * 0: Graphic layer(s) type: (others likely exist)
+ * bit 4 = 2 layers
+ * bits 2-3 = layer 1 mode
+ * bits 0-1 = layer 0 mode
+ * mode: 1 = 16 colours, 2 = 256 colours, 3 = highcolour (16-bit)
+ * 0 = disabled?
+ *
+ * 1: Layer reverse (priority?) (bit 0)
+ * YM (bit 2) - unknown
+ * peltype (bits 4 and 5)
+ *
+ *
+ * Sprite registers:
+ *
+ * 0,1: Maximum sprite (last one to render?) (10-bit)
+ *
+ * 1 (bit 7): Enable sprite display
+ *
+ * 2,3: X offset (9-bit)
+ *
+ * 4,5: Y offset (9-bit)
+ *
+ * 6 (bit 4): VRAM location (0=0x40000,1=0x60000)
+ *
+ */
+
+#include "emu.h"
+#include "machine/pic8259.h"
+#include "machine/ram.h"
+#include "includes/fmtowns.h"
+
+//#define CRTC_REG_DISP 1
+//#define SPR_DEBUG 1
+
+//static UINT32 pshift; // for debugging
+
+static void draw_sprites(running_machine &machine, const rectangle* rect);
+
+static void towns_crtc_refresh_mode(running_machine &machine)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ unsigned int width,height;
+
+ rectangle scr(0, state->m_video.towns_crtc_reg[4], 0, state->m_video.towns_crtc_reg[8] / 2);
+
+ // layer 0
+ width = state->m_video.towns_crtc_reg[10] - state->m_video.towns_crtc_reg[9];
+ height = (state->m_video.towns_crtc_reg[14] - state->m_video.towns_crtc_reg[13]) / 2;
+ state->m_video.towns_crtc_layerscr[0].min_x = scr.xcenter() - (width / 2);
+ state->m_video.towns_crtc_layerscr[0].min_y = scr.ycenter() - (height / 2);
+ state->m_video.towns_crtc_layerscr[0].max_x = scr.xcenter() + (width / 2);
+ state->m_video.towns_crtc_layerscr[0].max_y = scr.ycenter() + (height / 2);
+
+ // layer 1
+ width = state->m_video.towns_crtc_reg[12] - state->m_video.towns_crtc_reg[11];
+ height = (state->m_video.towns_crtc_reg[16] - state->m_video.towns_crtc_reg[15]) / 2;
+ state->m_video.towns_crtc_layerscr[1].min_x = scr.xcenter() - (width / 2);
+ state->m_video.towns_crtc_layerscr[1].min_y = scr.ycenter() - (height / 2);
+ state->m_video.towns_crtc_layerscr[1].max_x = scr.xcenter() + (width / 2);
+ state->m_video.towns_crtc_layerscr[1].max_y = scr.ycenter() + (height / 2);
+
+ // sanity checks
+ if(scr.max_x == 0 || scr.max_y == 0)
+ return;
+ if(scr.max_x <= scr.min_x || scr.max_y <= scr.min_y)
+ return;
+
+ machine.primary_screen->configure(scr.max_x+1,scr.max_y+1,scr,HZ_TO_ATTOSECONDS(60));
+}
+
+READ8_MEMBER( towns_state::towns_gfx_high_r )
+{
+ return m_towns_gfxvram[offset];
+}
+
+WRITE8_MEMBER( towns_state::towns_gfx_high_w )
+{
+ m_towns_gfxvram[offset] = data;
+}
+
+READ8_MEMBER( towns_state::towns_gfx_r )
+{
+ UINT8 ret = 0;
+
+ if(m_towns_mainmem_enable != 0)
+ return m_messram->pointer()[offset+0xc0000];
+
+ offset = offset << 2;
+
+ if(m_video.towns_vram_page_sel != 0)
+ offset += 0x20000;
+
+ ret = (((m_towns_gfxvram[offset] >> m_video.towns_vram_rplane) << 7) & 0x80)
+ | (((m_towns_gfxvram[offset] >> m_video.towns_vram_rplane) << 2) & 0x40)
+ | (((m_towns_gfxvram[offset+1] >> m_video.towns_vram_rplane) << 5) & 0x20)
+ | (((m_towns_gfxvram[offset+1] >> m_video.towns_vram_rplane)) & 0x10)
+ | (((m_towns_gfxvram[offset+2] >> m_video.towns_vram_rplane) << 3) & 0x08)
+ | (((m_towns_gfxvram[offset+2] >> m_video.towns_vram_rplane) >> 2) & 0x04)
+ | (((m_towns_gfxvram[offset+3] >> m_video.towns_vram_rplane) << 1) & 0x02)
+ | (((m_towns_gfxvram[offset+3] >> m_video.towns_vram_rplane) >> 4) & 0x01);
+
+ return ret;
+}
+
+WRITE8_MEMBER( towns_state::towns_gfx_w )
+{
+ if(m_towns_mainmem_enable != 0)
+ {
+ m_messram->pointer()[offset+0xc0000] = data;
+ return;
+ }
+ offset = offset << 2;
+ if(m_video.towns_vram_page_sel != 0)
+ offset += 0x20000;
+ if(m_video.towns_vram_wplane & 0x08)
+ {
+ m_towns_gfxvram[offset] &= ~0x88;
+ m_towns_gfxvram[offset] |= ((data & 0x80) >> 4) | ((data & 0x40) << 1);
+ m_towns_gfxvram[offset + 1] &= ~0x88;
+ m_towns_gfxvram[offset + 1] |= ((data & 0x20) >> 2) | ((data & 0x10) << 3);
+ m_towns_gfxvram[offset + 2] &= ~0x88;
+ m_towns_gfxvram[offset + 2] |= ((data & 0x08)) | ((data & 0x04) << 5);
+ m_towns_gfxvram[offset + 3] &= ~0x88;
+ m_towns_gfxvram[offset + 3] |= ((data & 0x02) << 2) | ((data & 0x01) << 7);
+ }
+ if(m_video.towns_vram_wplane & 0x04)
+ {
+ m_towns_gfxvram[offset] &= ~0x44;
+ m_towns_gfxvram[offset] |= ((data & 0x80) >> 5) | ((data & 0x40));
+ m_towns_gfxvram[offset + 1] &= ~0x44;
+ m_towns_gfxvram[offset + 1] |= ((data & 0x20) >> 3) | ((data & 0x10) << 2);
+ m_towns_gfxvram[offset + 2] &= ~0x44;
+ m_towns_gfxvram[offset + 2] |= ((data & 0x08) >> 1) | ((data & 0x04) << 4);
+ m_towns_gfxvram[offset + 3] &= ~0x44;
+ m_towns_gfxvram[offset + 3] |= ((data & 0x02) << 1) | ((data & 0x01) << 6);
+ }
+ if(m_video.towns_vram_wplane & 0x02)
+ {
+ m_towns_gfxvram[offset] &= ~0x22;
+ m_towns_gfxvram[offset] |= ((data & 0x80) >> 6) | ((data & 0x40) >> 1);
+ m_towns_gfxvram[offset + 1] &= ~0x22;
+ m_towns_gfxvram[offset + 1] |= ((data & 0x20) >> 4) | ((data & 0x10) << 1);
+ m_towns_gfxvram[offset + 2] &= ~0x22;
+ m_towns_gfxvram[offset + 2] |= ((data & 0x08) >> 2) | ((data & 0x04) << 3);
+ m_towns_gfxvram[offset + 3] &= ~0x22;
+ m_towns_gfxvram[offset + 3] |= ((data & 0x02)) | ((data & 0x01) << 5);
+ }
+ if(m_video.towns_vram_wplane & 0x01)
+ {
+ m_towns_gfxvram[offset] &= ~0x11;
+ m_towns_gfxvram[offset] |= ((data & 0x80) >> 7) | ((data & 0x40) >> 2);
+ m_towns_gfxvram[offset + 1] &= ~0x11;
+ m_towns_gfxvram[offset + 1] |= ((data & 0x20) >> 5) | ((data & 0x10));
+ m_towns_gfxvram[offset + 2] &= ~0x11;
+ m_towns_gfxvram[offset + 2] |= ((data & 0x08) >> 3) | ((data & 0x04) << 2);
+ m_towns_gfxvram[offset + 3] &= ~0x11;
+ m_towns_gfxvram[offset + 3] |= ((data & 0x02) >> 1) | ((data & 0x01) << 4);
+ }
+}
+
+static void towns_update_kanji_offset(running_machine &machine)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ // this is a little over the top...
+ if(state->m_video.towns_kanji_code_h < 0x30)
+ {
+ state->m_video.towns_kanji_offset = ((state->m_video.towns_kanji_code_l & 0x1f) << 4)
+ | (((state->m_video.towns_kanji_code_l - 0x20) & 0x20) << 8)
+ | (((state->m_video.towns_kanji_code_l - 0x20) & 0x40) << 6)
+ | ((state->m_video.towns_kanji_code_h & 0x07) << 9);
+ }
+ else if(state->m_video.towns_kanji_code_h < 0x70)
+ {
+ state->m_video.towns_kanji_offset = ((state->m_video.towns_kanji_code_l & 0x1f) << 4)
+ + (((state->m_video.towns_kanji_code_l - 0x20) & 0x60) << 8)
+ + ((state->m_video.towns_kanji_code_h & 0x0f) << 9)
+ + (((state->m_video.towns_kanji_code_h - 0x30) & 0x70) * 0xc00)
+ + 0x8000;
+ }
+ else
+ {
+ state->m_video.towns_kanji_offset = ((state->m_video.towns_kanji_code_l & 0x1f) << 4)
+ | (((state->m_video.towns_kanji_code_l - 0x20) & 0x20) << 8)
+ | (((state->m_video.towns_kanji_code_l - 0x20) & 0x40) << 6)
+ | ((state->m_video.towns_kanji_code_h & 0x07) << 9)
+ | 0x38000;
+ }
+}
+
+READ8_MEMBER( towns_state::towns_video_cff80_r )
+{
+ UINT8* ROM = space.machine().root_device().memregion("user")->base();
+
+ switch(offset)
+ {
+ case 0x00: // mix register
+ return m_video.towns_crtc_mix;
+ case 0x01: // read/write plane select (bit 0-3 write, bit 6-7 read)
+ return ((m_video.towns_vram_rplane << 6) & 0xc0) | m_video.towns_vram_wplane;
+ case 0x02: // display planes (bits 0-2,5), display page select (bit 4)
+ return m_video.towns_display_plane | m_video.towns_display_page_sel;
+ case 0x03: // VRAM page select (bit 5)
+ if(m_video.towns_vram_page_sel != 0)
+ return 0x10;
+ else
+ return 0x00;
+ case 0x06:
+ if(m_video.towns_vblank_flag != 0)
+ return 0x10;
+ else
+ return 0x00;
+ case 0x16: // Kanji character data
+ return ROM[(m_video.towns_kanji_offset << 1) + 0x180000];
+ case 0x17: // Kanji character data
+ return ROM[(m_video.towns_kanji_offset++ << 1) + 0x180001];
+ case 0x19: // ANK CG ROM
+ if(m_towns_ankcg_enable != 0)
+ return 0x01;
+ else
+ return 0x00;
+ default:
+ logerror("VGA: read from invalid or unimplemented memory-mapped port %05x\n",0xcff80+offset*4);
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER( towns_state::towns_video_cff80_w )
+{
+ switch(offset)
+ {
+ case 0x00: // mix register
+ m_video.towns_crtc_mix = data;
+ break;
+ case 0x01: // read/write plane select (bit 0-3 write, bit 6-7 read)
+ m_video.towns_vram_wplane = data & 0x0f;
+ m_video.towns_vram_rplane = (data & 0xc0) >> 6;
+ towns_update_video_banks(space);
+ //logerror("VGA: VRAM wplane select = 0x%02x\n",towns_vram_wplane);
+ break;
+ case 0x02: // display plane (bits 0-2), display page select (bit 4)
+ m_video.towns_display_plane = data & 0x27;
+ m_video.towns_display_page_sel = data & 0x10;
+ break;
+ case 0x03: // VRAM page select (bit 4)
+ m_video.towns_vram_page_sel = data & 0x10;
+ break;
+ case 0x14: // Kanji offset (high)
+ m_video.towns_kanji_code_h = data & 0x7f;
+ towns_update_kanji_offset(space.machine());
+ //logerror("VID: Kanji code set (high) = %02x %02x\n",towns_kanji_code_h,towns_kanji_code_l);
+ break;
+ case 0x15: // Kanji offset (low)
+ m_video.towns_kanji_code_l = data & 0x7f;
+ towns_update_kanji_offset(space.machine());
+ //logerror("VID: Kanji code set (low) = %02x %02x\n",towns_kanji_code_h,towns_kanji_code_l);
+ break;
+ case 0x19: // ANK CG ROM
+ m_towns_ankcg_enable = data & 0x01;
+ towns_update_video_banks(space);
+ break;
+ default:
+ logerror("VGA: write %08x to invalid or unimplemented memory-mapped port %05x\n",data,0xcff80+offset);
+ }
+}
+
+READ8_MEMBER( towns_state::towns_video_cff80_mem_r )
+{
+ if(m_towns_mainmem_enable != 0)
+ return m_messram->pointer()[offset+0xcff80];
+
+ return towns_video_cff80_r(space,offset);
+}
+
+WRITE8_MEMBER( towns_state::towns_video_cff80_mem_w )
+{
+ if(m_towns_mainmem_enable != 0)
+ {
+ m_messram->pointer()[offset+0xcff80] = data;
+ return;
+ }
+ towns_video_cff80_w(space,offset,data);
+}
+
+/*
+ * port 0x440-0x443 - CRTC
+ * 0x440 = register select
+ * 0x442/3 = register data (16-bit)
+ * 0x448 = shifter register select
+ * 0x44a = shifter register data (8-bit)
+ *
+ */
+READ8_MEMBER(towns_state::towns_video_440_r)
+{
+ UINT8 ret = 0;
+ UINT16 xpos,ypos;
+
+ switch(offset)
+ {
+ case 0x00:
+ return m_video.towns_crtc_sel;
+ case 0x02:
+// logerror("CRTC: reading register %i (0x442) [%04x]\n",towns_crtc_sel,towns_crtc_reg[towns_crtc_sel]);
+ if(m_video.towns_crtc_sel == 30)
+ return 0x00;
+ return m_video.towns_crtc_reg[m_video.towns_crtc_sel] & 0x00ff;
+ case 0x03:
+// logerror("CRTC: reading register %i (0x443) [%04x]\n",towns_crtc_sel,towns_crtc_reg[towns_crtc_sel]);
+ if(m_video.towns_crtc_sel == 30)
+ {
+ // check video position
+ xpos = space.machine().primary_screen->hpos();
+ ypos = space.machine().primary_screen->vpos();
+
+ if(xpos < (m_video.towns_crtc_reg[0] & 0xfe))
+ ret |= 0x02;
+ if(ypos < (m_video.towns_crtc_reg[6] & 0x1f))
+ ret |= 0x04;
+ if(xpos < m_video.towns_crtc_layerscr[0].max_x && xpos > m_video.towns_crtc_layerscr[0].min_x)
+ ret |= 0x10;
+ if(xpos < m_video.towns_crtc_layerscr[1].max_x && xpos > m_video.towns_crtc_layerscr[1].min_x)
+ ret |= 0x20;
+ if(ypos < m_video.towns_crtc_layerscr[0].max_y && ypos > m_video.towns_crtc_layerscr[0].min_y)
+ ret |= 0x40;
+ if(ypos < m_video.towns_crtc_layerscr[1].max_y && ypos > m_video.towns_crtc_layerscr[1].min_y)
+ ret |= 0x80;
+
+ return ret;
+ }
+ return (m_video.towns_crtc_reg[m_video.towns_crtc_sel] & 0xff00) >> 8;
+ case 0x08:
+ return m_video.towns_video_sel;
+ case 0x0a:
+ logerror("Video: reading register %i (0x44a) [%02x]\n",m_video.towns_video_sel,m_video.towns_video_reg[m_video.towns_video_sel]);
+ return m_video.towns_video_reg[m_video.towns_video_sel];
+ case 0x0c:
+ if(m_video.towns_dpmd_flag != 0)
+ {
+ m_video.towns_dpmd_flag = 0;
+ ret |= 0x80;
+ }
+ ret |= (m_video.towns_sprite_flag ? 0x02 : 0x00); // Sprite drawing flag
+ ret |= m_video.towns_sprite_page & 0x01;
+ return ret;
+ case 0x10:
+ return m_video.towns_sprite_sel;
+ case 0x12:
+ logerror("SPR: reading register %i (0x452) [%02x]\n",m_video.towns_sprite_sel,m_video.towns_sprite_reg[m_video.towns_sprite_sel]);
+ return m_video.towns_sprite_reg[m_video.towns_sprite_sel];
+ //default:
+ //logerror("VID: read port %04x\n",offset+0x440);
+ }
+ return 0x00;
+}
+
+WRITE8_MEMBER(towns_state::towns_video_440_w)
+{
+ switch(offset)
+ {
+ case 0x00:
+ m_video.towns_crtc_sel = data;
+ break;
+ case 0x02:
+// logerror("CRTC: writing register %i (0x442) [%02x]\n",towns_crtc_sel,data);
+ m_video.towns_crtc_reg[m_video.towns_crtc_sel] =
+ (m_video.towns_crtc_reg[m_video.towns_crtc_sel] & 0xff00) | data;
+ towns_crtc_refresh_mode(space.machine());
+ break;
+ case 0x03:
+// logerror("CRTC: writing register %i (0x443) [%02x]\n",towns_crtc_sel,data);
+ m_video.towns_crtc_reg[m_video.towns_crtc_sel] =
+ (m_video.towns_crtc_reg[m_video.towns_crtc_sel] & 0x00ff) | (data << 8);
+ towns_crtc_refresh_mode(space.machine());
+ break;
+ case 0x08:
+ m_video.towns_video_sel = data & 0x01;
+ break;
+ case 0x0a:
+ logerror("Video: writing register %i (0x44a) [%02x]\n",m_video.towns_video_sel,data);
+ m_video.towns_video_reg[m_video.towns_video_sel] = data;
+ break;
+ case 0x10:
+ m_video.towns_sprite_sel = data & 0x07;
+ break;
+ case 0x12:
+ logerror("SPR: writing register %i (0x452) [%02x]\n",m_video.towns_sprite_sel,data);
+ m_video.towns_sprite_reg[m_video.towns_sprite_sel] = data;
+ break;
+ default:
+ logerror("VID: wrote 0x%02x to port %04x\n",data,offset+0x440);
+ }
+}
+
+READ8_MEMBER(towns_state::towns_video_5c8_r)
+{
+ //logerror("VID: read port %04x\n",offset+0x5c8);
+ switch(offset)
+ {
+ case 0x00: // 0x5c8 - disable TVRAM?
+ if(m_video.towns_tvram_enable != 0)
+ {
+ m_video.towns_tvram_enable = 0;
+ return 0x80;
+ }
+ else
+ return 0x00;
+ }
+ return 0x00;
+}
+
+WRITE8_MEMBER(towns_state::towns_video_5c8_w)
+{
+ device_t* dev = m_pic_slave;
+
+ switch(offset)
+ {
+ case 0x02: // 0x5ca - VSync clear?
+ pic8259_ir3_w(dev, 0);
+ if(IRQ_LOG) logerror("PIC: IRQ11 (VSync) set low\n");
+ //towns_vblank_flag = 0;
+ break;
+ }
+ logerror("VID: wrote 0x%02x to port %04x\n",data,offset+0x5c8);
+}
+
+/* Video/CRTC
+ *
+ * 0xfd90 - palette colour select
+ * 0xfd92/4/6 - BRG value
+ * 0xfd98-9f - degipal(?)
+ */
+READ8_MEMBER(towns_state::towns_video_fd90_r)
+{
+ UINT8 ret = 0;
+ UINT16 xpos;
+
+// logerror("VID: read port %04x\n",offset+0xfd90);
+ switch(offset)
+ {
+ case 0x00:
+ return m_video.towns_palette_select;
+ case 0x02:
+ return m_video.towns_palette_b[m_video.towns_palette_select];
+ case 0x04:
+ return m_video.towns_palette_r[m_video.towns_palette_select];
+ case 0x06:
+ return m_video.towns_palette_g[m_video.towns_palette_select];
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ return m_video.towns_degipal[offset-0x08];
+ case 0x10: // "sub status register"
+ // check video position
+ xpos = space.machine().primary_screen->hpos();
+
+ if(xpos < m_video.towns_crtc_layerscr[0].max_x && xpos > m_video.towns_crtc_layerscr[0].min_x)
+ ret |= 0x02;
+ if(m_video.towns_vblank_flag)
+ ret |= 0x01;
+ return ret;
+ }
+ return 0x00;
+}
+
+WRITE8_MEMBER(towns_state::towns_video_fd90_w)
+{
+ switch(offset)
+ {
+ case 0x00:
+ m_video.towns_palette_select = data;
+ break;
+ case 0x02:
+ m_video.towns_palette_b[m_video.towns_palette_select] = data;
+ break;
+ case 0x04:
+ m_video.towns_palette_r[m_video.towns_palette_select] = data;
+ break;
+ case 0x06:
+ m_video.towns_palette_g[m_video.towns_palette_select] = data;
+ break;
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ m_video.towns_degipal[offset-0x08] = data;
+ m_video.towns_dpmd_flag = 1;
+ break;
+ case 0x10:
+ m_video.towns_layer_ctrl = data;
+ break;
+ }
+ logerror("VID: wrote 0x%02x to port %04x\n",data,offset+0xfd90);
+}
+
+READ8_MEMBER(towns_state::towns_video_ff81_r)
+{
+ return ((m_video.towns_vram_rplane << 6) & 0xc0) | m_video.towns_vram_wplane;
+}
+
+WRITE8_MEMBER(towns_state::towns_video_ff81_w)
+{
+ m_video.towns_vram_wplane = data & 0x0f;
+ m_video.towns_vram_rplane = (data & 0xc0) >> 6;
+ towns_update_video_banks(space);
+ logerror("VGA: VRAM wplane select (I/O) = 0x%02x\n",m_video.towns_vram_wplane);
+}
+
+READ32_MEMBER(towns_state::towns_video_unknown_r)
+{
+ return 0x00000000;
+}
+
+/*
+ * Sprite RAM, low memory
+ * Writing to 0xc8xxx or 0xcaxxx activates TVRAM
+ * Writing to I/O port 0x5c8 disables TVRAM
+ * (bit 7 returns high if TVRAM was previously active)
+ *
+ * In TVRAM mode:
+ * 0xc8000-0xc8fff: ASCII text (2 bytes each: ISO646 code, then attribute)
+ * 0xca000-0xcafff: JIS code
+ */
+READ8_MEMBER(towns_state::towns_spriteram_low_r)
+{
+ UINT8* RAM = m_messram->pointer();
+ UINT8* ROM = space.machine().root_device().memregion("user")->base();
+
+ if(offset < 0x1000)
+ { // 0xc8000-0xc8fff
+ if(m_towns_mainmem_enable == 0)
+ {
+// if(towns_tvram_enable == 0)
+// return towns_sprram[offset];
+// else
+ return m_towns_txtvram[offset];
+ }
+ else
+ return RAM[offset + 0xc8000];
+ }
+ if(offset >= 0x1000 && offset < 0x2000)
+ { // 0xc9000-0xc9fff
+ return RAM[offset + 0xc9000];
+ }
+ if(offset >= 0x2000 && offset < 0x3000)
+ { // 0xca000-0xcafff
+ if(m_towns_mainmem_enable == 0)
+ {
+ if(m_towns_ankcg_enable != 0 && offset < 0x2800)
+ return ROM[0x180000 + 0x3d000 + (offset-0x2000)];
+// if(towns_tvram_enable == 0)
+// return m_towns_sprram[offset];
+// else
+ return m_towns_txtvram[offset];
+ }
+ else
+ return RAM[offset + 0xca000];
+ }
+ return 0x00;
+}
+
+WRITE8_MEMBER(towns_state::towns_spriteram_low_w)
+{
+ UINT8* RAM = m_messram->pointer();
+
+ if(offset < 0x1000)
+ { // 0xc8000-0xc8fff
+ m_video.towns_tvram_enable = 1;
+ if(m_towns_mainmem_enable == 0)
+ m_towns_txtvram[offset] = data;
+ else
+ RAM[offset + 0xc8000] = data;
+ }
+ if(offset >= 0x1000 && offset < 0x2000)
+ {
+ RAM[offset + 0xc9000] = data;
+ }
+ if(offset >= 0x2000 && offset < 0x3000)
+ { // 0xca000-0xcafff
+ m_video.towns_tvram_enable = 1;
+ if(m_towns_mainmem_enable == 0)
+ m_towns_txtvram[offset] = data;
+ else
+ RAM[offset + 0xca000] = data;
+ }
+}
+
+READ8_MEMBER( towns_state::towns_spriteram_r )
+{
+ return m_towns_txtvram[offset];
+}
+
+WRITE8_MEMBER( towns_state::towns_spriteram_w )
+{
+ m_towns_txtvram[offset] = data;
+}
+
+/*
+ * Sprites
+ *
+ * Max. 1024, 16x16, 16 colours per sprite
+ * 128kB Sprite RAM (8kB attributes, 120kB pattern/colour data)
+ * Sprites are rendered directly to VRAM layer 1 (VRAM offset 0x40000 or 0x60000)
+ *
+ * Sprite RAM format:
+ * 4 words per sprite
+ * +0: X position (10-bit)
+ * +2: Y position (10-bit)
+ * +4: Sprite Attribute
+ * bit 15: enforce offsets (regs 2-5)
+ * bit 12,13: flip sprite
+ * bits 10-0: Sprite RAM offset containing sprite pattern
+ * TODO: other attributes (zoom?)
+ * +6: Sprite Colour
+ * bit 15: use colour data in located in sprite RAM offset in bits 11-0 (x32)
+ */
+static void render_sprite_4(running_machine &machine, UINT32 poffset, UINT32 coffset, UINT16 x, UINT16 y, UINT16 xflip, UINT16 yflip, const rectangle* rect)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ UINT16 xpos,ypos;
+ UINT16 col,pixel;
+ UINT32 voffset;
+ UINT16 xstart,xend,ystart,yend;
+ int xdir,ydir;
+ int width = (state->m_video.towns_crtc_reg[12] - state->m_video.towns_crtc_reg[11]) / (((state->m_video.towns_crtc_reg[27] & 0x0f00) >> 8)+1);
+ int height = (state->m_video.towns_crtc_reg[16] - state->m_video.towns_crtc_reg[15]) / (((state->m_video.towns_crtc_reg[27] & 0xf000) >> 12)+2);
+
+ if(xflip)
+ {
+ xstart = x+14;
+ xend = x-2;
+ xdir = -2;
+ }
+ else
+ {
+ xstart = x+1;
+ xend = x+17;
+ xdir = 2;
+ }
+ if(yflip)
+ {
+ ystart = y+15;
+ yend = y-1;
+ ydir = -1;
+ }
+ else
+ {
+ ystart = y;
+ yend = y+16;
+ ydir = 1;
+ }
+ xstart &= 0x1ff;
+ xend &= 0x1ff;
+ ystart &= 0x1ff;
+ yend &= 0x1ff;
+ poffset &= 0x1ffff;
+
+ for(ypos=ystart;ypos!=yend;ypos+=ydir,ypos&=0x1ff)
+ {
+ for(xpos=xstart;xpos!=xend;xpos+=xdir,xpos&=0x1ff)
+ {
+ if(state->m_video.towns_sprite_page != 0)
+ voffset = 0x20000;
+ else
+ voffset = 0x00000;
+ pixel = (state->m_towns_txtvram[poffset] & 0xf0) >> 4;
+ col = state->m_towns_txtvram[coffset+(pixel*2)] | (state->m_towns_txtvram[coffset+(pixel*2)+1] << 8);
+ voffset += (state->m_video.towns_crtc_reg[24] * 4) * (ypos & 0x1ff); // scanline size in bytes * y pos
+ voffset += (xpos & 0x1ff) * 2;
+ if((state->m_video.towns_sprite_page != 0 && voffset > 0x1ffff && voffset < 0x40000)
+ || (state->m_video.towns_sprite_page == 0 && voffset < 0x20000))
+ {
+ if(xpos < width && ypos < height && pixel != 0)
+ {
+ state->m_towns_gfxvram[0x40000+voffset+1] = (col & 0xff00) >> 8;
+ state->m_towns_gfxvram[0x40000+voffset] = col & 0x00ff;
+ }
+ }
+ if(xflip)
+ voffset+=2;
+ else
+ voffset-=2;
+ pixel = state->m_towns_txtvram[poffset] & 0x0f;
+ col = state->m_towns_txtvram[coffset+(pixel*2)] | (state->m_towns_txtvram[coffset+(pixel*2)+1] << 8);
+ if((state->m_video.towns_sprite_page != 0 && voffset > 0x1ffff && voffset < 0x40000)
+ || (state->m_video.towns_sprite_page == 0 && voffset < 0x20000))
+ {
+ if(xpos < width && ypos < height && pixel != 0)
+ {
+ state->m_towns_gfxvram[0x40000+voffset+1] = (col & 0xff00) >> 8;
+ state->m_towns_gfxvram[0x40000+voffset] = col & 0x00ff;
+ }
+ }
+ poffset++;
+ poffset &= 0x1ffff;
+ }
+ }
+}
+
+static void render_sprite_16(running_machine &machine, UINT32 poffset, UINT16 x, UINT16 y, UINT16 xflip, UINT16 yflip, const rectangle* rect)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ UINT16 xpos,ypos;
+ UINT16 col;
+ UINT32 voffset;
+ UINT16 xstart,ystart,xend,yend;
+ int xdir,ydir;
+ int width = (state->m_video.towns_crtc_reg[12] - state->m_video.towns_crtc_reg[11]) / (((state->m_video.towns_crtc_reg[27] & 0x0f00) >> 8)+1);
+ int height = (state->m_video.towns_crtc_reg[16] - state->m_video.towns_crtc_reg[15]) / (((state->m_video.towns_crtc_reg[27] & 0xf000) >> 12)+2);
+
+ if(xflip)
+ {
+ xstart = x+16;
+ xend = x;
+ xdir = -1;
+ }
+ else
+ {
+ xstart = x+1;
+ xend = x+17;
+ xdir = 1;
+ }
+ if(yflip)
+ {
+ ystart = y+15;
+ yend = y-1;
+ ydir = -1;
+ }
+ else
+ {
+ ystart = y;
+ yend = y+16;
+ ydir = 1;
+ }
+ xstart &= 0x1ff;
+ xend &= 0x1ff;
+ ystart &= 0x1ff;
+ yend &= 0x1ff;
+ poffset &= 0x1ffff;
+
+ for(ypos=ystart;ypos!=yend;ypos+=ydir,ypos&=0x1ff)
+ {
+ for(xpos=xstart;xpos!=xend;xpos+=xdir,xpos&=0x1ff)
+ {
+ if(state->m_video.towns_sprite_page != 0)
+ voffset = 0x20000;
+ else
+ voffset = 0x00000;
+ col = state->m_towns_txtvram[poffset] | (state->m_towns_txtvram[poffset+1] << 8);
+ voffset += (state->m_video.towns_crtc_reg[24] * 4) * (ypos & 0x1ff); // scanline size in bytes * y pos
+ voffset += (xpos & 0x1ff) * 2;
+ if((state->m_video.towns_sprite_page != 0 && voffset > 0x1ffff && voffset < 0x40000)
+ || (state->m_video.towns_sprite_page == 0 && voffset < 0x20000))
+ {
+ if(xpos < width && ypos < height && col < 0x8000)
+ {
+ state->m_towns_gfxvram[0x40000+voffset+1] = (col & 0xff00) >> 8;
+ state->m_towns_gfxvram[0x40000+voffset] = col & 0x00ff;
+ }
+ }
+ poffset+=2;
+ poffset &= 0x1ffff;
+ }
+ }
+}
+
+static void draw_sprites(running_machine &machine, const rectangle* rect)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ UINT16 sprite_limit = (state->m_video.towns_sprite_reg[0] | (state->m_video.towns_sprite_reg[1] << 8)) & 0x3ff;
+ int n;
+ UINT16 x,y,attr,colour;
+ UINT16 xoff = (state->m_video.towns_sprite_reg[2] | (state->m_video.towns_sprite_reg[3] << 8)) & 0x1ff;
+ UINT16 yoff = (state->m_video.towns_sprite_reg[4] | (state->m_video.towns_sprite_reg[5] << 8)) & 0x1ff;
+ UINT32 poffset,coffset;
+
+ if(!(state->m_video.towns_sprite_reg[1] & 0x80))
+ return;
+
+ // clears VRAM for each frame?
+ if(state->m_video.towns_sprite_page == 0)
+ memset(state->m_towns_gfxvram+0x40000,0x80,0x20000);
+ else
+ memset(state->m_towns_gfxvram+0x60000,0x80,0x20000);
+
+ for(n=sprite_limit;n<1024;n++)
+ {
+ x = state->m_towns_txtvram[8*n] | (state->m_towns_txtvram[8*n+1] << 8);
+ y = state->m_towns_txtvram[8*n+2] | (state->m_towns_txtvram[8*n+3] << 8);
+ attr = state->m_towns_txtvram[8*n+4] | (state->m_towns_txtvram[8*n+5] << 8);
+ colour = state->m_towns_txtvram[8*n+6] | (state->m_towns_txtvram[8*n+7] << 8);
+ if(attr & 0x8000)
+ {
+ x += xoff;
+ y += yoff;
+ }
+ x &= 0x1ff;
+ y &= 0x1ff;
+
+ if(colour & 0x8000)
+ {
+ poffset = (attr & 0x3ff) << 7;
+ coffset = (colour & 0xfff) << 5;
+#ifdef SPR_DEBUG
+ printf("Sprite4 #%i, X %i Y %i Attr %04x Col %04x Poff %08x Coff %08x\n",
+ n,x,y,attr,colour,poffset,coffset);
+#endif
+ if(!(colour & 0x2000))
+ render_sprite_4(machine,(poffset)&0x1ffff,coffset,x,y,attr&0x2000,attr&0x1000,rect);
+ }
+ else
+ {
+ poffset = (attr & 0x3ff) << 7;
+#ifdef SPR_DEBUG
+ printf("Sprite16 #%i, X %i Y %i Attr %04x Col %04x Poff %08x",
+ n,x,y,attr,colour,poffset);
+#endif
+ if(!(colour & 0x2000))
+ render_sprite_16(machine,(poffset)&0x1ffff,x,y,attr&0x2000,attr&0x1000,rect);
+ }
+ }
+
+ if(state->m_video.towns_sprite_page == 0) // flip VRAM page
+ state->m_video.towns_sprite_page = 1;
+ else
+ state->m_video.towns_sprite_page = 0;
+
+ state->m_video.towns_sprite_flag = 1; // we are now drawing
+ state->m_video.sprite_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(128 * (1025-sprite_limit)));
+}
+
+static void towns_crtc_draw_scan_layer_hicolour(running_machine &machine, bitmap_rgb32 &bitmap,const rectangle* rect,int layer,int line,int scanline)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ UINT32 off = 0;
+ int x;
+ UINT16 colour;
+ int hzoom = 1;
+ int linesize;
+ UINT32 scroll;
+
+ if(layer == 0)
+ linesize = state->m_video.towns_crtc_reg[20] * 4;
+ else
+ linesize = state->m_video.towns_crtc_reg[24] * 4;
+
+ if(state->m_video.towns_display_page_sel != 0)
+ off = 0x20000;
+
+// if((layer == 1) && (state->m_video.towns_sprite_reg[1] & 0x80) && (state->m_video.towns_sprite_page == 1))
+// off = 0x20000;
+
+ if(layer != 0)
+ {
+ if(!(state->m_video.towns_video_reg[0] & 0x10))
+ return;
+ if(!(state->m_video.towns_crtc_reg[28] & 0x10))
+ off += (state->m_video.towns_crtc_reg[21]) << 2; // initial offset
+ else
+ {
+ scroll = ((state->m_video.towns_crtc_reg[21] & 0xfc00) << 2) | (((state->m_video.towns_crtc_reg[21] & 0x3ff) << 2));
+ off += scroll;
+ }
+ off += (state->m_video.towns_crtc_reg[11] - state->m_video.towns_crtc_reg[22]);
+ hzoom = ((state->m_video.towns_crtc_reg[27] & 0x0f00) >> 8) + 1;
+ }
+ else
+ {
+ if(!(state->m_video.towns_crtc_reg[28] & 0x20))
+ off += (state->m_video.towns_crtc_reg[17]) << 2; // initial offset
+ else
+ {
+ scroll = ((state->m_video.towns_crtc_reg[17] & 0xfc00) << 2) | (((state->m_video.towns_crtc_reg[17] & 0x3ff) << 2));
+ off += scroll;
+ }
+ off += (state->m_video.towns_crtc_reg[9] - state->m_video.towns_crtc_reg[18]);
+ hzoom = (state->m_video.towns_crtc_reg[27] & 0x000f) + 1;
+ }
+
+ off += line * linesize;
+ off &= ~0x01;
+
+ if(hzoom == 1)
+ {
+ for(x=rect->min_x;x<rect->max_x;x++)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+
+ colour = (state->m_towns_gfxvram[off+(layer*0x40000)+1] << 8) | state->m_towns_gfxvram[off+(layer*0x40000)];
+ if(colour < 0x8000)
+ {
+ bitmap.pix32(scanline, x) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ }
+ off+=2;
+ }
+ }
+
+ if(hzoom == 2)
+ { // x2 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=2)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = (state->m_towns_gfxvram[off+(layer*0x40000)+1] << 8) | state->m_towns_gfxvram[off+(layer*0x40000)];
+ if(colour < 0x8000)
+ {
+ bitmap.pix32(scanline, x) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+1) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ }
+ off+=2;
+ }
+ }
+
+ if(hzoom == 3)
+ { // x3 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=3)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = (state->m_towns_gfxvram[off+(layer*0x40000)+1] << 8) | state->m_towns_gfxvram[off+(layer*0x40000)];
+ if(colour < 0x8000)
+ {
+ bitmap.pix32(scanline, x) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+1) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+2) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ }
+ off+=2;
+ }
+ }
+
+ if(hzoom == 4)
+ { // x4 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=4)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = (state->m_towns_gfxvram[off+(layer*0x40000)+1] << 8) | state->m_towns_gfxvram[off+(layer*0x40000)];
+ if(colour < 0x8000)
+ {
+ bitmap.pix32(scanline, x) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+1) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+2) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+3) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ }
+ off+=2;
+ }
+ }
+
+ if(hzoom == 5)
+ { // x5 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=5)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = (state->m_towns_gfxvram[off+(layer*0x40000)+1] << 8) | state->m_towns_gfxvram[off+(layer*0x40000)];
+ if(colour < 0x8000)
+ {
+ bitmap.pix32(scanline, x) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+1) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+2) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+3) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ bitmap.pix32(scanline, x+4) =
+ ((colour & 0x001f) << 3)
+ | ((colour & 0x7c00) << 1)
+ | ((colour & 0x03e0) << 14);
+ }
+ off+=2;
+ }
+ }
+}
+
+static void towns_crtc_draw_scan_layer_256(running_machine &machine, bitmap_rgb32 &bitmap,const rectangle* rect,int layer,int line,int scanline)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ int off = 0;
+ int x;
+ UINT8 colour;
+ int hzoom = 1;
+ int linesize;
+ UINT32 scroll;
+
+ if(state->m_video.towns_display_page_sel != 0)
+ off = 0x20000;
+
+// if((layer == 1) && (state->m_video.towns_sprite_reg[1] & 0x80) && (state->m_video.towns_sprite_page == 1))
+// off = 0x20000;
+
+ if(layer == 0)
+ linesize = state->m_video.towns_crtc_reg[20] * 8;
+ else
+ linesize = state->m_video.towns_crtc_reg[24] * 8;
+
+ if(layer != 0)
+ {
+ if(!(state->m_video.towns_video_reg[0] & 0x10))
+ return;
+ if(!(state->m_video.towns_crtc_reg[28] & 0x10))
+ off += state->m_video.towns_crtc_reg[21] << 3; // initial offset
+ else
+ {
+ scroll = ((state->m_video.towns_crtc_reg[21] & 0xfc00) << 3) | (((state->m_video.towns_crtc_reg[21] & 0x3ff) << 3));
+ off += scroll;
+ }
+ off += (state->m_video.towns_crtc_reg[11] - state->m_video.towns_crtc_reg[22]);
+ hzoom = ((state->m_video.towns_crtc_reg[27] & 0x0f00) >> 8) + 1;
+ }
+ else
+ {
+ if(!(state->m_video.towns_crtc_reg[28] & 0x20))
+ off += state->m_video.towns_crtc_reg[17] << 3; // initial offset
+ else
+ {
+ scroll = ((state->m_video.towns_crtc_reg[17] & 0xfc00) << 3) | (((state->m_video.towns_crtc_reg[17] & 0x3ff) << 3));
+ off += scroll;
+ }
+ off += (state->m_video.towns_crtc_reg[9] - state->m_video.towns_crtc_reg[18]);
+ hzoom = (state->m_video.towns_crtc_reg[27] & 0x000f) + 1;
+ }
+
+ off += line * linesize;
+
+ if(hzoom == 1)
+ {
+ for(x=rect->min_x;x<rect->max_x;x++)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)];
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+
+ if(hzoom == 2)
+ { // x2 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=2)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)+1];
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+1) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+
+ if(hzoom == 3)
+ { // x3 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=3)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)+1];
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+1) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+2) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+
+ if(hzoom == 4)
+ { // x4 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=4)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)+1];
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+1) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+2) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+3) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+
+ if(hzoom == 5)
+ { // x5 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=5)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)+1];
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+1) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+2) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+3) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+4) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+}
+
+static void towns_crtc_draw_scan_layer_16(running_machine &machine, bitmap_rgb32 &bitmap,const rectangle* rect,int layer,int line,int scanline)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ int off = 0;
+ int x;
+ UINT8 colour;
+ int hzoom = 1;
+ int linesize;
+ UINT32 scroll;
+
+ if(state->m_video.towns_display_page_sel != 0)
+ off = 0x20000;
+
+// if((layer == 1) && (state->m_video.towns_sprite_reg[1] & 0x80) && (state->m_video.towns_sprite_page == 1))
+// off = 0x20000;
+
+ if(layer == 0)
+ linesize = state->m_video.towns_crtc_reg[20] * 4;
+ else
+ linesize = state->m_video.towns_crtc_reg[24] * 4;
+
+ if(layer != 0)
+ {
+ if(!(state->m_video.towns_video_reg[0] & 0x10))
+ return;
+ if(!(state->m_video.towns_crtc_reg[28] & 0x10))
+ off += state->m_video.towns_crtc_reg[21]; // initial offset
+ else
+ {
+ scroll = ((state->m_video.towns_crtc_reg[21] & 0xfc00)<<2) | (((state->m_video.towns_crtc_reg[21] & 0x3ff)<<2));
+ off += scroll;
+ }
+ off += (state->m_video.towns_crtc_reg[11] - state->m_video.towns_crtc_reg[22]);
+ hzoom = ((state->m_video.towns_crtc_reg[27] & 0x0f00) >> 8) + 1;
+ }
+ else
+ {
+ if(!(state->m_video.towns_crtc_reg[28] & 0x20))
+ off += state->m_video.towns_crtc_reg[17]; // initial offset
+ else
+ {
+ scroll = ((state->m_video.towns_crtc_reg[17] & 0xfc00)<<2) | (((state->m_video.towns_crtc_reg[17] & 0x3ff)<<2));
+ off += scroll;
+ }
+ off += (state->m_video.towns_crtc_reg[9] - state->m_video.towns_crtc_reg[18]);
+ hzoom = (state->m_video.towns_crtc_reg[27] & 0x000f) + 1;
+ }
+
+ off += line * linesize;
+
+ if(hzoom == 1)
+ {
+ for(x=rect->min_x;x<rect->max_x;x+=2)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] >> 4;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x+1) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] & 0x0f;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+
+ if(hzoom == 2)
+ { // x2 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=4)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] >> 4;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x+2) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+3) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] & 0x0f;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+1) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+
+ if(hzoom == 3)
+ { // x3 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=6)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] >> 4;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x+3) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+4) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+5) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] & 0x0f;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+1) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+2) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+
+ if(hzoom == 4)
+ { // x4 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=8)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] >> 4;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x+4) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+5) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+6) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+7) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] & 0x0f;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+1) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+2) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+3) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+
+ if(hzoom == 5)
+ { // x5 horizontal zoom
+ for(x=rect->min_x;x<rect->max_x;x+=10)
+ {
+ if(state->m_video.towns_video_reg[0] & 0x10)
+ off &= 0x3ffff; // 2 layers
+ else
+ off &= 0x7ffff; // 1 layer
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] >> 4;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x+5) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+6) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+7) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+8) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+9) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ colour = state->m_towns_gfxvram[off+(layer*0x40000)] & 0x0f;
+ if(colour != 0)
+ {
+ bitmap.pix32(scanline, x) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+1) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+2) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+3) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ bitmap.pix32(scanline, x+4) =
+ (state->m_video.towns_palette_r[colour] << 16)
+ | (state->m_video.towns_palette_g[colour] << 8)
+ | (state->m_video.towns_palette_b[colour]);
+ }
+ off++;
+ }
+ }
+}
+
+static void towns_crtc_draw_layer(running_machine &machine,bitmap_rgb32 &bitmap,const rectangle* rect,int layer)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ int line;
+ int scanline;
+ int height;
+
+ if(layer == 0)
+ {
+ scanline = rect->min_y;
+ height = (rect->max_y - rect->min_y);
+ if(state->m_video.towns_crtc_reg[27] & 0x0010)
+ height /= 2;
+ switch(state->m_video.towns_video_reg[0] & 0x03)
+ {
+ case 0x01:
+ for(line=0;line<height;line++)
+ {
+ towns_crtc_draw_scan_layer_16(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ if(state->m_video.towns_crtc_reg[27] & 0x0010) // vertical zoom
+ {
+ towns_crtc_draw_scan_layer_16(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ }
+ }
+ break;
+ case 0x02:
+ for(line=0;line<height;line++)
+ {
+ towns_crtc_draw_scan_layer_256(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ if(state->m_video.towns_crtc_reg[27] & 0x0010) // vertical zoom
+ {
+ towns_crtc_draw_scan_layer_256(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ }
+ }
+ break;
+ case 0x03:
+ for(line=0;line<height;line++)
+ {
+ towns_crtc_draw_scan_layer_hicolour(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ if(state->m_video.towns_crtc_reg[27] & 0x0010) // vertical zoom
+ {
+ towns_crtc_draw_scan_layer_hicolour(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ scanline = rect->min_y;
+ height = (rect->max_y - rect->min_y);
+ if(state->m_video.towns_crtc_reg[27] & 0x1000)
+ height /= 2;
+ switch(state->m_video.towns_video_reg[0] & 0x0c)
+ {
+ case 0x04:
+ for(line=0;line<height;line++)
+ {
+ towns_crtc_draw_scan_layer_16(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ if(state->m_video.towns_crtc_reg[27] & 0x1000) // vertical zoom
+ {
+ towns_crtc_draw_scan_layer_16(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ }
+ }
+ break;
+ case 0x08:
+ for(line=0;line<height;line++)
+ {
+ towns_crtc_draw_scan_layer_256(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ if(state->m_video.towns_crtc_reg[27] & 0x1000) // vertical zoom
+ {
+ towns_crtc_draw_scan_layer_256(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ }
+ }
+ break;
+ case 0x0c:
+ for(line=0;line<height;line++)
+ {
+ towns_crtc_draw_scan_layer_hicolour(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ if(state->m_video.towns_crtc_reg[27] & 0x1000) // vertical zoom
+ {
+ towns_crtc_draw_scan_layer_hicolour(machine,bitmap,rect,layer,line,scanline);
+ scanline++;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void render_text_char(running_machine &machine, UINT8 x, UINT8 y, UINT8 ascii, UINT16 jis, UINT8 attr)
+{
+ towns_state* state = machine.driver_data<towns_state>();
+ UINT32 rom_addr;
+ UINT32 vram_addr;
+ UINT16 linesize = state->m_video.towns_crtc_reg[24] * 4;
+ UINT8 code_h,code_l;
+ UINT8 colour;
+ UINT8 data;
+ UINT8 temp;
+ UINT8* font_rom = state->memregion("user")->base();
+ int a,b;
+
+ // all characters are 16 pixels high
+ vram_addr = (x * 4) + (y * (linesize * 16));
+
+ if((attr & 0xc0) == 0)
+ rom_addr = 0x3d800 + (ascii * 128);
+ else
+ {
+ code_h = (jis & 0xff00) >> 8;
+ code_l = jis & 0x00ff;
+ if(code_h < 0x30)
+ {
+ rom_addr = ((code_l & 0x1f) << 4)
+ | (((code_l - 0x20) & 0x20) << 8)
+ | (((code_l - 0x20) & 0x40) << 6)
+ | ((code_h & 0x07) << 9);
+ }
+ else if(code_h < 0x70)
+ {
+ rom_addr = ((code_l & 0x1f) << 4)
+ + (((code_l - 0x20) & 0x60) << 8)
+ + ((code_h & 0x0f) << 9)
+ + (((code_h - 0x30) & 0x70) * 0xc00)
+ + 0x8000;
+ }
+ else
+ {
+ rom_addr = ((code_l & 0x1f) << 4)
+ | (((code_l - 0x20) & 0x20) << 8)
+ | (((code_l - 0x20) & 0x40) << 6)
+ | ((code_h & 0x07) << 9)
+ | 0x38000;
+ }
+ }
+ colour = attr & 0x07;
+ if(attr & 0x20)
+ colour |= 0x08;
+
+ for(a=0;a<16;a++) // for each scanline
+ {
+ if((attr & 0xc0) == 0)
+ data = font_rom[0x180000 + rom_addr + a];
+ else
+ {
+ if((attr & 0xc0) == 0x80)
+ data = font_rom[0x180000 + rom_addr + (a*2)];
+ else
+ data = font_rom[0x180000 + rom_addr + (a*2) + 1];
+ }
+
+ if(attr & 0x08)
+ data = ~data; // inverse
+
+ // and finally, put the data in VRAM
+ for(b=0;b<8;b+=2)
+ {
+ temp = 0;
+ if(data & (1<<b))
+ temp |= ((colour & 0x0f) << 4);
+ if(data & (1<<(b+1)))
+ temp |= (colour & 0x0f);
+ //state->m_towns_gfxvram[0x40000+vram_addr+(b/2)] = temp;
+ }
+
+ vram_addr += linesize;
+ vram_addr &= 0x3ffff;
+ }
+}
+
+static void draw_text_layer(running_machine &machine)
+{
+/*
+ * Text format
+ * 2 bytes per character at both 0xc8000 and 0xca000
+ * 0xc8xxx: Byte 1: ASCII character
+ * Byte 2: Attributes
+ * bits 2-0: GRB (or is it BRG?)
+ * bit 3: Inverse
+ * bit 4: Blink
+ * bit 5: high brightness
+ * bits 7-6: Kanji high/low
+ *
+ * If either bits 6 or 7 are high, then a fullwidth Kanji character is displayed
+ * at this location. The character displayed is represented by a 2-byte
+ * JIS code at the same offset at 0xca000.
+ *
+ * The video hardware renders text to VRAM layer 1, there is no separate text layer
+ */
+ towns_state* state = machine.driver_data<towns_state>();
+ int x,y,c = 0;
+
+ for(y=0;y<40;y++)
+ {
+ for(x=0;x<80;x++)
+ {
+ render_text_char(machine,x,y,state->m_towns_txtvram[c],((state->m_towns_txtvram[c+0x2000] << 8)|(state->m_towns_txtvram[c+0x2001])),state->m_towns_txtvram[c+1]);
+ c+=2;
+ }
+ }
+}
+
+static TIMER_CALLBACK( towns_sprite_done )
+{
+ // sprite drawing is complete, lower flag
+ towns_state* state = machine.driver_data<towns_state>();
+ state->m_video.towns_sprite_flag = 0;
+ if(state->m_video.towns_sprite_page != 0)
+ state->m_video.towns_crtc_reg[21] |= 0x8000;
+ else
+ state->m_video.towns_crtc_reg[21] &= ~0x8000;
+}
+
+static TIMER_CALLBACK( towns_vblank_end )
+{
+ // here we'll clear the vsync signal, I presume it goes low on it's own eventually
+ towns_state* state = machine.driver_data<towns_state>();
+ device_t* dev = (device_t*)ptr;
+ pic8259_ir3_w(dev, 0); // IRQ11 = VSync
+ if(IRQ_LOG) logerror("PIC: IRQ11 (VSync) set low\n");
+ state->m_video.towns_vblank_flag = 0;
+}
+
+INTERRUPT_GEN( towns_vsync_irq )
+{
+ towns_state* state = device->machine().driver_data<towns_state>();
+ device_t* dev = state->m_pic_slave;
+ pic8259_ir3_w(dev, 1); // IRQ11 = VSync
+ if(IRQ_LOG) logerror("PIC: IRQ11 (VSync) set high\n");
+ state->m_video.towns_vblank_flag = 1;
+ device->machine().scheduler().timer_set(device->machine().primary_screen->time_until_vblank_end(), FUNC(towns_vblank_end), 0, (void*)dev);
+ if(state->m_video.towns_tvram_enable)
+ draw_text_layer(dev->machine());
+ if(state->m_video.towns_sprite_reg[1] & 0x80)
+ draw_sprites(dev->machine(),&state->m_video.towns_crtc_layerscr[1]);
+}
+
+void towns_state::video_start()
+{
+ m_video.towns_vram_wplane = 0x00;
+ m_video.towns_sprite_page = 0;
+ m_video.sprite_timer = machine().scheduler().timer_alloc(FUNC(towns_sprite_done));
+}
+
+UINT32 towns_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(0x00000000, cliprect);
+
+ if(!(m_video.towns_video_reg[1] & 0x01))
+ {
+ if(!screen.machine().input().code_pressed(KEYCODE_Q))
+ {
+ if((m_video.towns_layer_ctrl & 0x03) != 0)
+ towns_crtc_draw_layer(screen.machine(),bitmap,&m_video.towns_crtc_layerscr[1],1);
+ }
+ if(!screen.machine().input().code_pressed(KEYCODE_W))
+ {
+ if((m_video.towns_layer_ctrl & 0x0c) != 0)
+ towns_crtc_draw_layer(screen.machine(),bitmap,&m_video.towns_crtc_layerscr[0],0);
+ }
+ }
+ else
+ {
+ if(!screen.machine().input().code_pressed(KEYCODE_Q))
+ {
+ if((m_video.towns_layer_ctrl & 0x0c) != 0)
+ towns_crtc_draw_layer(screen.machine(),bitmap,&m_video.towns_crtc_layerscr[0],0);
+ }
+ if(!screen.machine().input().code_pressed(KEYCODE_W))
+ {
+ if((m_video.towns_layer_ctrl & 0x03) != 0)
+ towns_crtc_draw_layer(screen.machine(),bitmap,&m_video.towns_crtc_layerscr[1],1);
+ }
+ }
+
+#if 0
+#ifdef SPR_DEBUG
+ if(screen.machine().input().code_pressed(KEYCODE_O))
+ pshift+=0x80;
+ if(screen.machine().input().code_pressed(KEYCODE_I))
+ pshift-=0x80;
+ popmessage("Pixel shift = %08x",pshift);
+#endif
+#endif
+
+#ifdef CRTC_REG_DISP
+ popmessage("CRTC: %i %i %i %i %i %i %i %i %i\n%i %i %i %i | %i %i %i %i\n%04x %i %i %i | %04x %i %i %i\nZOOM: %04x\nVideo: %02x %02x\nText=%i Spr=%02x\nReg28=%04x",
+ m_video.towns_crtc_reg[0],m_video.towns_crtc_reg[1],m_video.towns_crtc_reg[2],m_video.towns_crtc_reg[3],
+ m_video.towns_crtc_reg[4],m_video.towns_crtc_reg[5],m_video.towns_crtc_reg[6],m_video.towns_crtc_reg[7],
+ m_video.towns_crtc_reg[8],
+ m_video.towns_crtc_reg[9],m_video.towns_crtc_reg[10],m_video.towns_crtc_reg[11],m_video.towns_crtc_reg[12],
+ m_video.towns_crtc_reg[13],m_video.towns_crtc_reg[14],m_video.towns_crtc_reg[15],m_video.towns_crtc_reg[16],
+ m_video.towns_crtc_reg[17],m_video.towns_crtc_reg[18],m_video.towns_crtc_reg[19],m_video.towns_crtc_reg[20],
+ m_video.towns_crtc_reg[21],m_video.towns_crtc_reg[22],m_video.towns_crtc_reg[23],m_video.towns_crtc_reg[24],
+ m_video.towns_crtc_reg[27],m_video.towns_video_reg[0],m_video.towns_video_reg[1],m_video.towns_tvram_enable,m_video.towns_sprite_reg[1] & 0x80,
+ m_video.towns_crtc_reg[28]);
+#endif
+
+ return 0;
+}
+
diff --git a/src/mess/video/galaxy.c b/src/mess/video/galaxy.c
new file mode 100644
index 00000000000..52b5bd6aa17
--- /dev/null
+++ b/src/mess/video/galaxy.c
@@ -0,0 +1,137 @@
+/***************************************************************************
+
+ galaxy.c
+
+ Functions to emulate the video hardware of the Galaksija.
+
+ 20/05/2008 - Real video implementation by Miodrag Milanovic
+ 01/03/2008 - Update by Miodrag Milanovic to make Galaksija video work with new SVN code
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/galaxy.h"
+#include "cpu/z80/z80.h"
+
+
+static TIMER_CALLBACK( gal_video )
+{
+ galaxy_state *state = machine.driver_data<galaxy_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int y, x;
+ if (state->m_interrupts_enabled == TRUE)
+ {
+ UINT8 *gfx = state->memregion("gfx1")->base();
+ UINT8 dat = (state->m_latch_value & 0x3c) >> 2;
+ if ((state->m_gal_cnt >= 48 * 2) && (state->m_gal_cnt < 48 * 210)) // display on screen just state->m_first 208 lines
+ {
+ UINT8 mode = (state->m_latch_value >> 1) & 1; // bit 2 latch represents mode
+ UINT16 addr = (cpu_get_reg(machine.device("maincpu"), Z80_I) << 8) | cpu_get_reg(machine.device("maincpu"), Z80_R) | ((state->m_latch_value & 0x80) ^ 0x80);
+ if (mode == 0)
+ {
+ // Text mode
+ if (state->m_first == 0 && (cpu_get_reg(machine.device("maincpu"), Z80_R) & 0x1f) == 0)
+ {
+ // Due to a fact that on real processor latch value is set at
+ // the end of last cycle we need to skip dusplay of double
+ // state->m_first char in each row
+ state->m_code = 0x00;
+ state->m_first = 1;
+ }
+ else
+ {
+ state->m_code = space->read_byte(addr) & 0xbf;
+ state->m_code += (state->m_code & 0x80) >> 1;
+ state->m_code = gfx[(state->m_code & 0x7f) +(dat << 7 )] ^ 0xff;
+ state->m_first = 0;
+ }
+ y = state->m_gal_cnt / 48 - 2;
+ x = (state->m_gal_cnt % 48) * 8;
+
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 0) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 1) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 2) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 3) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 4) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 5) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 6) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 7) & 1;
+ }
+ else
+ { // Graphics mode
+ if (state->m_first < 4 && (cpu_get_reg(machine.device("maincpu"), Z80_R) & 0x1f) == 0)
+ {
+ // Due to a fact that on real processor latch value is set at
+ // the end of last cycle we need to skip dusplay of 4 times
+ // state->m_first char in each row
+ state->m_code = 0x00;
+ state->m_first++;
+ }
+ else
+ {
+ state->m_code = space->read_byte(addr) ^ 0xff;
+ state->m_first = 0;
+ }
+ y = state->m_gal_cnt / 48 - 2;
+ x = (state->m_gal_cnt % 48) * 8;
+
+ /* hack - until calc of R is fixed in Z80 */
+ if (x == 11 * 8 && y == 0)
+ {
+ state->m_start_addr = addr;
+ }
+ if ((x / 8 >= 11) && (x / 8 < 44))
+ {
+ state->m_code = space->read_byte(state->m_start_addr + y * 32 + (state->m_gal_cnt % 48) - 11) ^ 0xff;
+ }
+ else
+ {
+ state->m_code = 0x00;
+ }
+ /* end of hack */
+
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 0) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 1) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 2) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 3) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 4) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 5) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 6) & 1; x++;
+ state->m_bitmap.pix16(y, x ) = (state->m_code >> 7) & 1;
+ }
+ }
+ state->m_gal_cnt++;
+ }
+}
+
+void galaxy_set_timer(running_machine &machine)
+{
+ galaxy_state *state = machine.driver_data<galaxy_state>();
+ state->m_gal_cnt = 0;
+ state->m_gal_video_timer->adjust(attotime::zero, 0, attotime::from_hz(6144000 / 8));
+}
+
+VIDEO_START( galaxy )
+{
+ galaxy_state *state = machine.driver_data<galaxy_state>();
+ state->m_gal_cnt = 0;
+
+ state->m_gal_video_timer = machine.scheduler().timer_alloc(FUNC(gal_video));
+ state->m_gal_video_timer->adjust(attotime::zero, 0, attotime::never);
+
+ machine.primary_screen->register_screen_bitmap(state->m_bitmap);
+}
+
+SCREEN_UPDATE_IND16( galaxy )
+{
+ galaxy_state *state = screen.machine().driver_data<galaxy_state>();
+ state->m_gal_video_timer->adjust(attotime::zero, 0, attotime::never);
+ if (state->m_interrupts_enabled == FALSE)
+ {
+ const rectangle black_area(0, 384 - 1, 0, 208 - 1);
+ state->m_bitmap.fill(0, black_area);
+ }
+ state->m_interrupts_enabled = FALSE;
+ copybitmap(bitmap, state->m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
diff --git a/src/mess/video/galeb.c b/src/mess/video/galeb.c
new file mode 100644
index 00000000000..a38fa53b2ae
--- /dev/null
+++ b/src/mess/video/galeb.c
@@ -0,0 +1,45 @@
+/***************************************************************************
+
+ Galeb video driver by Miodrag Milanovic
+
+ 01/03/2008 Updated to work with latest SVN code
+ 22/02/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/galeb.h"
+
+
+const gfx_layout galeb_charlayout =
+{
+ 8, 8, /* 8x8 characters */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ {0}, /* no bitplanes; 1 bit per pixel */
+ {7, 6, 5, 4, 3, 2, 1, 0},
+ {0 * 8, 1 * 8, 2 * 8, 3 * 8, 4 * 8, 5 * 8, 6 * 8, 7 * 8},
+ 8*8 /* size of one char */
+};
+
+VIDEO_START( galeb )
+{
+}
+
+SCREEN_UPDATE_IND16( galeb )
+{
+ galeb_state *state = screen.machine().driver_data<galeb_state>();
+ int x,y;
+
+ for(y = 0; y < 16; y++ )
+ {
+ for(x = 0; x < 48; x++ )
+ {
+ int code = state->m_video_ram[15 + x + y*64];
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], code , 0, 0,0, x*8,y*8);
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/gamecom.c b/src/mess/video/gamecom.c
new file mode 100644
index 00000000000..ef903c07490
--- /dev/null
+++ b/src/mess/video/gamecom.c
@@ -0,0 +1,72 @@
+
+#include "includes/gamecom.h"
+
+#define Y_PIXELS 200
+
+
+static TIMER_CALLBACK( gamecom_scanline )
+ {
+ gamecom_state *state = machine.driver_data<gamecom_state>();
+ // draw line
+ if ( state->m_scanline == 0 )
+ state->m_base_address = ( state->m_p_ram[SM8521_LCDC] & 0x40 ) ? 0x2000 : 0x0000;
+
+ if ( ~state->m_p_ram[SM8521_LCDC] & 0x80 )
+ {
+ rectangle rec(0, Y_PIXELS - 1, state->m_scanline, state->m_scanline);
+ state->m_bitmap.fill(0, rec );
+ return;
+ }
+ else
+ {
+ UINT8 *line = &state->m_p_videoram[ state->m_base_address + 40 * state->m_scanline ];
+ int pal[4];
+ int i;
+
+ switch( state->m_p_ram[SM8521_LCDC] & 0x30 )
+ {
+ case 0x00:
+ pal[0] = 4;
+ pal[1] = 3;
+ pal[2] = 2;
+ pal[3] = 0;
+ break;
+ case 0x10:
+ pal[0] = 4;
+ pal[1] = 3;
+ pal[2] = 1;
+ pal[3] = 0;
+ break;
+ case 0x20:
+ pal[0] = 4;
+ pal[1] = 3;
+ pal[2] = 1;
+ pal[3] = 0;
+ break;
+ case 0x30:
+ pal[0] = 4;
+ pal[1] = 2;
+ pal[2] = 1;
+ pal[3] = 0;
+ break;
+ }
+ for( i = 0; i < 40; i++ )
+ {
+ UINT8 p = line[i];
+ state->m_bitmap.pix16(i * 4 + 0, state->m_scanline) = pal[ ( p >> 6 ) & 3 ];
+ state->m_bitmap.pix16(i * 4 + 1, state->m_scanline) = pal[ ( p >> 4 ) & 3 ];
+ state->m_bitmap.pix16(i * 4 + 2, state->m_scanline) = pal[ ( p >> 2 ) & 3 ];
+ state->m_bitmap.pix16(i * 4 + 3, state->m_scanline) = pal[ ( p ) & 3 ];
+ }
+ }
+
+ state->m_scanline = ( state->m_scanline + 1 ) % Y_PIXELS;
+}
+
+VIDEO_START( gamecom )
+{
+ gamecom_state *state = machine.driver_data<gamecom_state>();
+ state->m_scanline_timer = machine.scheduler().timer_alloc(FUNC(gamecom_scanline));
+ state->m_scanline_timer->adjust( machine.primary_screen->time_until_pos(0 ), 0, machine.primary_screen->scan_period() );
+ machine.primary_screen->register_screen_bitmap(state->m_bitmap);
+}
diff --git a/src/mess/video/gb.c b/src/mess/video/gb.c
new file mode 100644
index 00000000000..9d859931938
--- /dev/null
+++ b/src/mess/video/gb.c
@@ -0,0 +1,2392 @@
+/***************************************************************************
+
+ gb.c
+
+ Video file to handle emulation of the Nintendo Game Boy.
+
+ Original code Carsten Sorensen 1998
+ Mess modifications, bug fixes and speedups Hans de Goede 1998
+ Bug fixes, SGB and GBC code Anthony Kruize 2002
+ Improvements to match real hardware Wilbert Pol 2006-2008
+
+ Timing is not accurate enough:
+ - Mode 3 takes 172 cycles (measuered with logic analyzer by costis)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/lr35902/lr35902.h"
+#include "includes/gb.h"
+
+#define LCDCONT state->m_lcd.gb_vid_regs[0x00] /* LCD control register */
+#define LCDSTAT state->m_lcd.gb_vid_regs[0x01] /* LCD status register */
+#define SCROLLY state->m_lcd.gb_vid_regs[0x02] /* Starting Y position of the background */
+#define SCROLLX state->m_lcd.gb_vid_regs[0x03] /* Starting X position of the background */
+#define CURLINE state->m_lcd.gb_vid_regs[0x04] /* Current screen line being scanned */
+#define CMPLINE state->m_lcd.gb_vid_regs[0x05] /* Gen. int. when scan reaches this line */
+#define BGRDPAL state->m_lcd.gb_vid_regs[0x07] /* Background palette */
+#define SPR0PAL state->m_lcd.gb_vid_regs[0x08] /* Sprite palette #0 */
+#define SPR1PAL state->m_lcd.gb_vid_regs[0x09] /* Sprite palette #1 */
+#define WNDPOSY state->m_lcd.gb_vid_regs[0x0A] /* Window Y position */
+#define WNDPOSX state->m_lcd.gb_vid_regs[0x0B] /* Window X position */
+#define KEY1 state->m_lcd.gb_vid_regs[0x0D] /* Prepare speed switch */
+#define HDMA1 state->m_lcd.gb_vid_regs[0x11] /* HDMA source high byte */
+#define HDMA2 state->m_lcd.gb_vid_regs[0x12] /* HDMA source low byte */
+#define HDMA3 state->m_lcd.gb_vid_regs[0x13] /* HDMA destination high byte */
+#define HDMA4 state->m_lcd.gb_vid_regs[0x14] /* HDMA destination low byte */
+#define HDMA5 state->m_lcd.gb_vid_regs[0x15] /* HDMA length/mode/start */
+#define GBCBCPS state->m_lcd.gb_vid_regs[0x28] /* Backgound palette spec */
+#define GBCBCPD state->m_lcd.gb_vid_regs[0x29] /* Backgound palette data */
+#define GBCOCPS state->m_lcd.gb_vid_regs[0x2A] /* Object palette spec */
+#define GBCOCPD state->m_lcd.gb_vid_regs[0x2B] /* Object palette data */
+
+enum {
+ UNLOCKED=0,
+ LOCKED
+};
+
+
+/* Prototypes */
+static TIMER_CALLBACK(gb_lcd_timer_proc);
+static TIMER_CALLBACK(gbc_lcd_timer_proc);
+static void gb_lcd_switch_on( running_machine &machine );
+
+static const unsigned char palette[] =
+{
+/* Simple black and white palette */
+/* 0xFF,0xFF,0xFF,
+ 0xB0,0xB0,0xB0,
+ 0x60,0x60,0x60,
+ 0x00,0x00,0x00 */
+
+/* Possibly needs a little more green in it */
+ 0xFF,0xFB,0x87, /* Background */
+ 0xB1,0xAE,0x4E, /* Light */
+ 0x84,0x80,0x4E, /* Medium */
+ 0x4E,0x4E,0x4E, /* Dark */
+
+/* Palette for Game Boy Pocket/Light */
+ 0xC4,0xCF,0xA1, /* Background */
+ 0x8B,0x95,0x6D, /* Light */
+ 0x6B,0x73,0x53, /* Medium */
+ 0x41,0x41,0x41, /* Dark */
+};
+
+static const unsigned char palette_megaduck[] = {
+ 0x6B, 0xA6, 0x4A, 0x43, 0x7A, 0x63, 0x25, 0x59, 0x55, 0x12, 0x42, 0x4C
+};
+
+/* Initialise the palettes */
+PALETTE_INIT( gb )
+{
+ int ii;
+ for( ii = 0; ii < 4; ii++)
+ {
+ palette_set_color_rgb(machine, ii, palette[ii*3+0], palette[ii*3+1], palette[ii*3+2]);
+ }
+}
+
+PALETTE_INIT( gbp )
+{
+ int ii;
+ for( ii = 0; ii < 4; ii++)
+ {
+ palette_set_color_rgb(machine, ii, palette[(ii + 4)*3+0], palette[(ii + 4)*3+1], palette[(ii + 4)*3+2]);
+ }
+}
+
+PALETTE_INIT( sgb )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ int ii, r, g, b;
+
+ for( ii = 0; ii < 32768; ii++ )
+ {
+ r = (ii & 0x1F) << 3;
+ g = ((ii >> 5) & 0x1F) << 3;
+ b = ((ii >> 10) & 0x1F) << 3;
+ palette_set_color_rgb(machine, ii, r, g, b );
+ }
+
+ /* Some default colours for non-SGB games */
+ state->m_sgb_pal[0] = 32767;
+ state->m_sgb_pal[1] = 21140;
+ state->m_sgb_pal[2] = 10570;
+ state->m_sgb_pal[3] = 0;
+ /* The rest of the colortable can be black */
+ for( ii = 4; ii < 8*16; ii++ )
+ state->m_sgb_pal[ii] = 0;
+}
+
+PALETTE_INIT( gbc )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ int ii, r, g, b;
+
+ for( ii = 0; ii < 32768; ii++ )
+ {
+ r = (ii & 0x1F) << 3;
+ g = ((ii >> 5) & 0x1F) << 3;
+ b = ((ii >> 10) & 0x1F) << 3;
+ palette_set_color_rgb( machine, ii, r, g, b );
+ }
+
+ /* Background is initialised as white */
+ for( ii = 0; ii < 32; ii++ )
+ state->m_lcd.cgb_bpal[ii] = 32767;
+ /* Sprites are supposed to be uninitialized, but we'll make them black */
+ for( ii = 0; ii < 32; ii++ )
+ state->m_lcd.cgb_spal[ii] = 0;
+}
+
+PALETTE_INIT( megaduck )
+{
+ int ii;
+ for( ii = 0; ii < 4; ii++)
+ {
+ palette_set_color_rgb(machine, ii, palette_megaduck[ii*3+0], palette_megaduck[ii*3+1], palette_megaduck[ii*3+2]);
+ }
+}
+
+
+INLINE void gb_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = (UINT16)color;
+}
+
+/*
+ Select which sprites should be drawn for the current scanline and return the
+ number of sprites selected.
+ */
+static void gb_select_sprites( gb_state *state )
+{
+ int i, /*yindex,*/ line, height;
+ UINT8 *oam = state->m_lcd.gb_oam->base() + 39 * 4;
+
+ state->m_lcd.sprCount = 0;
+
+ /* If video hardware is enabled and sprites are enabled */
+ if ( ( LCDCONT & 0x80 ) && ( LCDCONT & 0x02 ) )
+ {
+ /* Check for stretched sprites */
+ if ( LCDCONT & 0x04 )
+ {
+ height = 16;
+ }
+ else
+ {
+ height = 8;
+ }
+
+ //yindex = state->m_lcd.current_line;
+ line = state->m_lcd.current_line + 16;
+
+ for( i = 39; i >= 0; i-- )
+ {
+ if ( line >= oam[0] && line < ( oam[0] + height ) && oam[1] && oam[1] < 168 )
+ {
+ /* We limit the sprite count to max 10 here;
+ proper games should not exceed this... */
+ if ( state->m_lcd.sprCount < 10 )
+ {
+ state->m_lcd.sprite[state->m_lcd.sprCount] = i;
+ state->m_lcd.sprCount++;
+ }
+ }
+ oam -= 4;
+ }
+ }
+}
+
+INLINE void gb_update_sprites ( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ UINT8 height, tilemask, line, *oam, *vram;
+ int i, yindex;
+
+ if (LCDCONT & 0x04)
+ {
+ height = 16;
+ tilemask = 0xFE;
+ }
+ else
+ {
+ height = 8;
+ tilemask = 0xFF;
+ }
+
+ yindex = state->m_lcd.current_line;
+ line = state->m_lcd.current_line + 16;
+
+ oam = state->m_lcd.gb_oam->base() + 39 * 4;
+ vram = state->m_lcd.gb_vram->base();
+ for (i = 39; i >= 0; i--)
+ {
+ /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
+ if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
+ {
+ UINT16 data;
+ UINT8 bit, *spal;
+ int xindex, adr;
+
+ spal = (oam[3] & 0x10) ? state->m_lcd.gb_spal1 : state->m_lcd.gb_spal0;
+ xindex = oam[1] - 8;
+ if (oam[3] & 0x40) /* flip y ? */
+ {
+ adr = (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2;
+ }
+ else
+ {
+ adr = (oam[2] & tilemask) * 16 + (line - oam[0]) * 2;
+ }
+ data = (vram[adr + 1] << 8) | vram[adr];
+
+ switch (oam[3] & 0xA0)
+ {
+ case 0xA0: /* priority is set (behind bgnd & wnd, flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
+ if (colour && !state->m_lcd.bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
+ gb_plot_pixel(bitmap, xindex, yindex, spal[colour]);
+ data >>= 1;
+ }
+ break;
+ case 0x20: /* priority is not set (overlaps bgnd & wnd, flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
+ if (colour && xindex >= 0 && xindex < 160)
+ gb_plot_pixel(bitmap, xindex, yindex, spal[colour]);
+ data >>= 1;
+ }
+ break;
+ case 0x80: /* priority is set (behind bgnd & wnd, don't flip x) */
+ for (bit = 0; bit < 8 && xindex < 160; bit++, xindex++)
+ {
+ register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
+ if (colour && !state->m_lcd.bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
+ gb_plot_pixel(bitmap, xindex, yindex, spal[colour]);
+ data <<= 1;
+ }
+ break;
+ case 0x00: /* priority is not set (overlaps bgnd & wnd, don't flip x) */
+ for (bit = 0; bit < 8 && xindex < 160; bit++, xindex++)
+ {
+ register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
+ if (colour && xindex >= 0 && xindex < 160)
+ gb_plot_pixel(bitmap, xindex, yindex, spal[colour]);
+ data <<= 1;
+ }
+ break;
+ }
+ }
+ oam -= 4;
+ }
+}
+
+static void gb_update_scanline( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ bitmap_ind16 &bitmap = state->m_bitmap;
+
+ g_profiler.start(PROFILER_VIDEO);
+
+ /* Make sure we're in mode 3 */
+ if ( ( LCDSTAT & 0x03 ) == 0x03 )
+ {
+ /* Calculate number of pixels to render based on time still left on the timer */
+ UINT32 cycles_to_go = machine.device<cpu_device>("maincpu")->attotime_to_cycles(state->m_lcd.lcd_timer ->remaining( ) );
+ int l = 0;
+
+ if ( state->m_lcd.start_x < 0 )
+ {
+ /* Window is enabled if the hardware says so AND the current scanline is
+ * within the window AND the window X coordinate is <=166 */
+ state->m_lcd.layer[1].enabled = ( ( LCDCONT & 0x20 ) && ( state->m_lcd.current_line >= WNDPOSY ) && ( WNDPOSX <= 166 ) ) ? 1 : 0;
+
+ /* BG is enabled if the hardware says so AND (window_off OR (window_on
+ * AND window's X position is >=7 ) ) */
+ state->m_lcd.layer[0].enabled = ( ( LCDCONT & 0x01 ) && ( ( ! state->m_lcd.layer[1].enabled ) || ( state->m_lcd.layer[1].enabled && ( WNDPOSX >= 7 ) ) ) ) ? 1 : 0;
+
+ if ( state->m_lcd.layer[0].enabled )
+ {
+ state->m_lcd.layer[0].bgline = ( SCROLLY + state->m_lcd.current_line ) & 0xFF;
+ state->m_lcd.layer[0].bg_map = state->m_lcd.gb_bgdtab;
+ state->m_lcd.layer[0].bg_tiles = state->m_lcd.gb_chrgen;
+ state->m_lcd.layer[0].xindex = SCROLLX >> 3;
+ state->m_lcd.layer[0].xshift = SCROLLX & 7;
+ state->m_lcd.layer[0].xstart = 0;
+ state->m_lcd.layer[0].xend = 160;
+ }
+
+ if ( state->m_lcd.layer[1].enabled )
+ {
+ int xpos;
+
+ xpos = WNDPOSX - 7; /* Window is offset by 7 pixels */
+ if ( xpos < 0 )
+ xpos = 0;
+
+ state->m_lcd.layer[1].bgline = state->m_lcd.window_lines_drawn;
+ state->m_lcd.layer[1].bg_map = state->m_lcd.gb_wndtab;
+ state->m_lcd.layer[1].bg_tiles = state->m_lcd.gb_chrgen;
+ state->m_lcd.layer[1].xindex = 0;
+ state->m_lcd.layer[1].xshift = 0;
+ state->m_lcd.layer[1].xstart = xpos;
+ state->m_lcd.layer[1].xend = 160;
+ state->m_lcd.layer[0].xend = xpos;
+ }
+ state->m_lcd.start_x = 0;
+ }
+
+ if ( cycles_to_go < 160 )
+ {
+ state->m_lcd.end_x = MIN(160 - cycles_to_go,160);
+ /* Draw empty pixels when the background is disabled */
+ if ( ! ( LCDCONT & 0x01 ) )
+ {
+ rectangle r(state->m_lcd.start_x, state->m_lcd.end_x - 1, state->m_lcd.current_line, state->m_lcd.current_line);
+ bitmap.fill(state->m_lcd.gb_bpal[0], r );
+ }
+ while ( l < 2 )
+ {
+ UINT8 xindex, *map, *tiles;
+ UINT16 data;
+ int i, tile_index;
+
+ if ( ! state->m_lcd.layer[l].enabled )
+ {
+ l++;
+ continue;
+ }
+ map = state->m_lcd.layer[l].bg_map + ( ( state->m_lcd.layer[l].bgline << 2 ) & 0x3E0 );
+ tiles = state->m_lcd.layer[l].bg_tiles + ( ( state->m_lcd.layer[l].bgline & 7 ) << 1 );
+ xindex = state->m_lcd.start_x;
+ if ( xindex < state->m_lcd.layer[l].xstart )
+ xindex = state->m_lcd.layer[l].xstart;
+ i = state->m_lcd.end_x;
+ if ( i > state->m_lcd.layer[l].xend )
+ i = state->m_lcd.layer[l].xend;
+ i = i - xindex;
+
+ tile_index = ( map[ state->m_lcd.layer[l].xindex ] ^ state->m_lcd.gb_tile_no_mod ) * 16;
+ data = tiles[ tile_index ] | ( tiles[ tile_index+1 ] << 8 );
+ data <<= state->m_lcd.layer[l].xshift;
+
+ while ( i > 0 )
+ {
+ while ( ( state->m_lcd.layer[l].xshift < 8 ) && i )
+ {
+ register int colour = ( ( data & 0x8000 ) ? 2 : 0 ) | ( ( data & 0x0080 ) ? 1 : 0 );
+ gb_plot_pixel( bitmap, xindex, state->m_lcd.current_line, state->m_lcd.gb_bpal[ colour ] );
+ state->m_lcd.bg_zbuf[ xindex ] = colour;
+ xindex++;
+ data <<= 1;
+ state->m_lcd.layer[l].xshift++;
+ i--;
+ }
+ if ( state->m_lcd.layer[l].xshift == 8 )
+ {
+ /* Take possible changes to SCROLLY into account */
+ if ( l == 0 )
+ {
+ state->m_lcd.layer[0].bgline = ( SCROLLY + state->m_lcd.current_line ) & 0xFF;
+ map = state->m_lcd.layer[l].bg_map + ( ( state->m_lcd.layer[l].bgline << 2 ) & 0x3E0 );
+ tiles = state->m_lcd.layer[l].bg_tiles + ( ( state->m_lcd.layer[l].bgline & 7 ) << 1 );
+ }
+
+ state->m_lcd.layer[l].xindex = ( state->m_lcd.layer[l].xindex + 1 ) & 31;
+ state->m_lcd.layer[l].xshift = 0;
+ tile_index = ( map[ state->m_lcd.layer[l].xindex ] ^ state->m_lcd.gb_tile_no_mod ) * 16;
+ data = tiles[ tile_index ] | ( tiles[ tile_index+1 ] << 8 );
+ }
+ }
+ l++;
+ }
+ if ( state->m_lcd.end_x == 160 && LCDCONT & 0x02 )
+ {
+ gb_update_sprites(machine);
+ }
+ state->m_lcd.start_x = state->m_lcd.end_x;
+ }
+ }
+ else
+ {
+ if ( ! ( LCDCONT & 0x80 ) )
+ {
+ /* Draw an empty line when LCD is disabled */
+ if ( state->m_lcd.previous_line != state->m_lcd.current_line )
+ {
+ if ( state->m_lcd.current_line < 144 )
+ {
+ screen_device *screen = machine.first_screen();
+ const rectangle &r = screen->visible_area();
+ rectangle r1(r.min_x, r.max_x, state->m_lcd.current_line, state->m_lcd.current_line);
+ bitmap.fill(0, r1 );
+ }
+ state->m_lcd.previous_line = state->m_lcd.current_line;
+ }
+ }
+ }
+
+ g_profiler.stop();
+}
+
+/* --- Super Game Boy Specific --- */
+
+INLINE void sgb_update_sprites (running_machine &machine)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ UINT8 height, tilemask, line, *oam, *vram, pal;
+ INT16 i, yindex;
+
+ if (LCDCONT & 0x04)
+ {
+ height = 16;
+ tilemask = 0xFE;
+ }
+ else
+ {
+ height = 8;
+ tilemask = 0xFF;
+ }
+
+ /* Offset to center of screen */
+ yindex = state->m_lcd.current_line + SGB_YOFFSET;
+ line = state->m_lcd.current_line + 16;
+
+ oam = state->m_lcd.gb_oam->base() + 39 * 4;
+ vram = state->m_lcd.gb_vram->base();
+ for (i = 39; i >= 0; i--)
+ {
+ /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
+ if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
+ {
+ UINT16 data;
+ UINT8 bit, *spal;
+ INT16 xindex;
+ int adr;
+
+ spal = (oam[3] & 0x10) ? state->m_lcd.gb_spal1 : state->m_lcd.gb_spal0;
+ xindex = oam[1] - 8;
+ if (oam[3] & 0x40) /* flip y ? */
+ {
+ adr = (oam[2] & tilemask) * 16 + (height -1 - line + oam[0]) * 2;
+ }
+ else
+ {
+ adr = (oam[2] & tilemask) * 16 + (line - oam[0]) * 2;
+ }
+ data = (vram[adr + 1] << 8) | vram[adr];
+
+ /* Find the palette to use */
+ pal = state->m_sgb_pal_map[(xindex >> 3)][((yindex - SGB_YOFFSET) >> 3)] << 2;
+
+ /* Offset to center of screen */
+ xindex += SGB_XOFFSET;
+
+ switch (oam[3] & 0xA0)
+ {
+ case 0xA0: /* priority is set (behind bgnd & wnd, flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
+ if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour && !state->m_lcd.bg_zbuf[xindex - SGB_XOFFSET])
+ gb_plot_pixel(bitmap, xindex, yindex, state->m_sgb_pal[pal + spal[colour]]);
+ data >>= 1;
+ }
+ break;
+ case 0x20: /* priority is not set (overlaps bgnd & wnd, flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
+ if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour)
+ gb_plot_pixel(bitmap, xindex, yindex, state->m_sgb_pal[pal + spal[colour]]);
+ data >>= 1;
+ }
+ break;
+ case 0x80: /* priority is set (behind bgnd & wnd, don't flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
+ if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour && !state->m_lcd.bg_zbuf[xindex - SGB_XOFFSET])
+ gb_plot_pixel(bitmap, xindex, yindex, state->m_sgb_pal[pal + spal[colour]]);
+ data <<= 1;
+ }
+ break;
+ case 0x00: /* priority is not set (overlaps bgnd & wnd, don't flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
+ if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour)
+ gb_plot_pixel(bitmap, xindex, yindex, state->m_sgb_pal[pal + spal[colour]]);
+ data <<= 1;
+ }
+ break;
+ }
+ }
+ oam -= 4;
+ }
+}
+
+static void sgb_refresh_border(running_machine &machine)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ UINT16 data, data2;
+ UINT16 yidx, xidx, xindex;
+ UINT8 *map, *tiles, *tiles2;
+ UINT8 pal, i;
+ bitmap_ind16 &bitmap = state->m_bitmap;
+
+ map = state->m_sgb_tile_map - 64;
+
+ for( yidx = 0; yidx < 224; yidx++ )
+ {
+ xindex = 0;
+ map += (yidx % 8) ? 0 : 64;
+ for( xidx = 0; xidx < 64; xidx+=2 )
+ {
+ if( map[xidx+1] & 0x80 ) /* Vertical flip */
+ tiles = state->m_sgb_tile_data + ( ( 7 - ( yidx % 8 ) ) << 1 );
+ else /* No vertical flip */
+ tiles = state->m_sgb_tile_data + ( ( yidx % 8 ) << 1 );
+ tiles2 = tiles + 16;
+
+ pal = (map[xidx+1] & 0x1C) >> 2;
+ if( pal == 0 )
+ pal = 1;
+ pal <<= 4;
+
+ if( state->m_sgb_hack )
+ { /* A few games do weird stuff */
+ UINT8 tileno = map[xidx];
+ if( tileno >= 128 ) tileno = ((64 + tileno) % 128) + 128;
+ else tileno = (64 + tileno) % 128;
+ data = tiles[ tileno * 32 ] | ( tiles[ ( tileno * 32 ) + 1 ] << 8 );
+ data2 = tiles2[ tileno * 32 ] | ( tiles2[ ( tileno * 32 ) + 1 ] << 8 );
+ }
+ else
+ {
+ data = tiles[ map[xidx] * 32 ] | ( tiles[ (map[xidx] * 32 ) + 1 ] << 8 );
+ data2 = tiles2[ map[xidx] * 32 ] | ( tiles2[ (map[xidx] * 32 ) + 1 ] << 8 );
+ }
+
+ for( i = 0; i < 8; i++ )
+ {
+ register UINT8 colour;
+ if( (map[xidx+1] & 0x40) ) /* Horizontal flip */
+ {
+ colour = ((data & 0x0001) ? 1 : 0) | ((data & 0x0100) ? 2 : 0) |
+ ((data2 & 0x0001) ? 4 : 0) | ((data2 & 0x0100) ? 8 : 0);
+ data >>= 1;
+ data2 >>= 1;
+ }
+ else /* No horizontal flip */
+ {
+ colour = ((data & 0x0080) ? 1 : 0) | ((data & 0x8000) ? 2 : 0) |
+ ((data2 & 0x0080) ? 4 : 0) | ((data2 & 0x8000) ? 8 : 0);
+ data <<= 1;
+ data2 <<= 1;
+ }
+ /* A slight hack below so we don't draw over the GB screen.
+ * Drawing there is allowed, but due to the way we draw the
+ * scanline, it can obscure the screen even when it shouldn't.
+ */
+ if( !((yidx >= SGB_YOFFSET && yidx < SGB_YOFFSET + 144) &&
+ (xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160)) )
+ {
+ gb_plot_pixel(bitmap, xindex, yidx, state->m_sgb_pal[pal + colour]);
+ }
+ xindex++;
+ }
+ }
+ }
+}
+
+static void sgb_update_scanline( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ bitmap_ind16 &bitmap = state->m_bitmap;
+
+ g_profiler.start(PROFILER_VIDEO);
+
+ if ( ( LCDSTAT & 0x03 ) == 0x03 )
+ {
+ /* Calcuate number of pixels to render based on time still left on the timer */
+ UINT32 cycles_to_go = machine.device<cpu_device>("maincpu")->attotime_to_cycles(state->m_lcd.lcd_timer ->remaining( ) );
+ int l = 0;
+
+ if ( state->m_lcd.start_x < 0 )
+ {
+ /* Window is enabled if the hardware says so AND the current scanline is
+ * within the window AND the window X coordinate is <=166 */
+ state->m_lcd.layer[1].enabled = ((LCDCONT & 0x20) && state->m_lcd.current_line >= WNDPOSY && WNDPOSX <= 166) ? 1 : 0;
+
+ /* BG is enabled if the hardware says so AND (window_off OR (window_on
+ * AND window's X position is >=7 ) ) */
+ state->m_lcd.layer[0].enabled = ((LCDCONT & 0x01) && ((!state->m_lcd.layer[1].enabled) || (state->m_lcd.layer[1].enabled && WNDPOSX >= 7))) ? 1 : 0;
+
+ if ( state->m_lcd.layer[0].enabled )
+ {
+ state->m_lcd.layer[0].bgline = ( SCROLLY + state->m_lcd.current_line ) & 0xFF;
+ state->m_lcd.layer[0].bg_map = state->m_lcd.gb_bgdtab;
+ state->m_lcd.layer[0].bg_tiles = state->m_lcd.gb_chrgen;
+ state->m_lcd.layer[0].xindex = SCROLLX >> 3;
+ state->m_lcd.layer[0].xshift = SCROLLX & 7;
+ state->m_lcd.layer[0].xstart = 0;
+ state->m_lcd.layer[0].xend = 160;
+ }
+
+ if ( state->m_lcd.layer[1].enabled )
+ {
+ int xpos;
+
+ /* Window X position is offset by 7 so we'll need to adjust */
+ xpos = WNDPOSX - 7;
+ if (xpos < 0)
+ xpos = 0;
+
+ state->m_lcd.layer[1].bgline = state->m_lcd.window_lines_drawn;
+ state->m_lcd.layer[1].bg_map = state->m_lcd.gb_wndtab;
+ state->m_lcd.layer[1].bg_tiles = state->m_lcd.gb_chrgen;
+ state->m_lcd.layer[1].xindex = 0;
+ state->m_lcd.layer[1].xshift = 0;
+ state->m_lcd.layer[1].xstart = xpos;
+ state->m_lcd.layer[1].xend = 160;
+ state->m_lcd.layer[0].xend = xpos;
+ }
+ state->m_lcd.start_x = 0;
+ }
+
+ if ( cycles_to_go == 0 )
+ {
+
+ /* Does this belong here? or should it be moved to the else block */
+ /* Handle SGB mask */
+ switch( state->m_sgb_window_mask )
+ {
+ case 1: /* Freeze screen */
+ return;
+ case 2: /* Blank screen (black) */
+ {
+ rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160-1, SGB_YOFFSET, SGB_YOFFSET + 144 - 1);
+ bitmap.fill(0, r );
+ } return;
+ case 3: /* Blank screen (white - or should it be color 0?) */
+ {
+ rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, SGB_YOFFSET, SGB_YOFFSET + 144 - 1);
+ bitmap.fill(32767, r );
+ } return;
+ }
+
+ /* Draw the "border" if we're on the first line */
+ if ( state->m_lcd.current_line == 0 )
+ {
+ sgb_refresh_border(machine);
+ }
+ }
+ if ( cycles_to_go < 160 )
+ {
+ state->m_lcd.end_x = MIN(160 - cycles_to_go,160);
+
+ /* if background or screen disabled clear line */
+ if ( ! ( LCDCONT & 0x01 ) )
+ {
+ rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, state->m_lcd.current_line + SGB_YOFFSET, state->m_lcd.current_line + SGB_YOFFSET);
+ bitmap.fill(0, r );
+ }
+ while( l < 2 )
+ {
+ UINT8 xindex, sgb_palette, *map, *tiles;
+ UINT16 data;
+ int i, tile_index;
+
+ if ( ! state->m_lcd.layer[l].enabled )
+ {
+ l++;
+ continue;
+ }
+ map = state->m_lcd.layer[l].bg_map + ( ( state->m_lcd.layer[l].bgline << 2 ) & 0x3E0 );
+ tiles = state->m_lcd.layer[l].bg_tiles + ( ( state->m_lcd.layer[l].bgline & 7 ) << 1 );
+ xindex = state->m_lcd.start_x;
+ if ( xindex < state->m_lcd.layer[l].xstart )
+ xindex = state->m_lcd.layer[l].xstart;
+ i = state->m_lcd.end_x;
+ if ( i > state->m_lcd.layer[l].xend )
+ i = state->m_lcd.layer[l].xend;
+ i = i - xindex;
+
+ tile_index = (map[state->m_lcd.layer[l].xindex] ^ state->m_lcd.gb_tile_no_mod) * 16;
+ data = tiles[tile_index] | ( tiles[tile_index + 1] << 8 );
+ data <<= state->m_lcd.layer[l].xshift;
+
+ /* Figure out which palette we're using */
+ sgb_palette = state->m_sgb_pal_map[ ( state->m_lcd.end_x - i ) >> 3 ][ state->m_lcd.current_line >> 3 ] << 2;
+
+ while( i > 0 )
+ {
+ while( ( state->m_lcd.layer[l].xshift < 8 ) && i )
+ {
+ register int colour = ( ( data & 0x8000 ) ? 2 : 0 ) | ( ( data & 0x0080 ) ? 1 : 0 );
+ gb_plot_pixel( bitmap, xindex + SGB_XOFFSET, state->m_lcd.current_line + SGB_YOFFSET, state->m_sgb_pal[ sgb_palette + state->m_lcd.gb_bpal[colour]] );
+ state->m_lcd.bg_zbuf[xindex] = colour;
+ xindex++;
+ data <<= 1;
+ state->m_lcd.layer[l].xshift++;
+ i--;
+ }
+ if ( state->m_lcd.layer[l].xshift == 8 )
+ {
+ /* Take possible changes to SCROLLY into account */
+ if ( l == 0 )
+ {
+ state->m_lcd.layer[0].bgline = ( SCROLLY + state->m_lcd.current_line ) & 0xFF;
+ map = state->m_lcd.layer[l].bg_map + ( ( state->m_lcd.layer[l].bgline << 2 ) & 0x3E0 );
+ tiles = state->m_lcd.layer[l].bg_tiles + ( ( state->m_lcd.layer[l].bgline & 7 ) << 1 );
+ }
+
+ state->m_lcd.layer[l].xindex = ( state->m_lcd.layer[l].xindex + 1 ) & 31;
+ state->m_lcd.layer[l].xshift = 0;
+ tile_index = ( map[ state->m_lcd.layer[l].xindex ] ^ state->m_lcd.gb_tile_no_mod ) * 16;
+ data = tiles[ tile_index ] | ( tiles[ tile_index + 1 ] << 8 );
+ sgb_palette = state->m_sgb_pal_map[ ( state->m_lcd.end_x - i ) >> 3 ][ state->m_lcd.current_line >> 3 ] << 2;
+ }
+ }
+ l++;
+ }
+ if ( ( state->m_lcd.end_x == 160 ) && ( LCDCONT & 0x02 ) )
+ {
+ sgb_update_sprites(machine);
+ }
+ state->m_lcd.start_x = state->m_lcd.end_x;
+ }
+ }
+ else
+ {
+ if ( ! ( LCDCONT * 0x80 ) )
+ {
+ /* if screen disabled clear line */
+ if ( state->m_lcd.previous_line != state->m_lcd.current_line )
+ {
+ /* Also refresh border here??? */
+ if ( state->m_lcd.current_line < 144 )
+ {
+ rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, state->m_lcd.current_line + SGB_YOFFSET, state->m_lcd.current_line + SGB_YOFFSET);
+ bitmap.fill(0, r);
+ }
+ state->m_lcd.previous_line = state->m_lcd.current_line;
+ }
+ }
+ }
+
+ g_profiler.stop();
+}
+
+/* --- Game Boy Color Specific --- */
+
+INLINE void cgb_update_sprites ( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ UINT8 height, tilemask, line, *oam;
+ int i, xindex, yindex;
+
+ if (LCDCONT & 0x04)
+ {
+ height = 16;
+ tilemask = 0xFE;
+ }
+ else
+ {
+ height = 8;
+ tilemask = 0xFF;
+ }
+
+ yindex = state->m_lcd.current_line;
+ line = state->m_lcd.current_line + 16;
+
+ oam = state->m_lcd.gb_oam->base() + 39 * 4;
+ for (i = 39; i >= 0; i--)
+ {
+ /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
+ if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
+ {
+ UINT16 data;
+ UINT8 bit, pal;
+
+ /* Handle mono mode for GB games */
+ if( ! state->m_lcd.gbc_mode )
+ pal = (oam[3] & 0x10) ? 4 : 0;
+ else
+ pal = ((oam[3] & 0x7) * 4);
+
+ xindex = oam[1] - 8;
+ if (oam[3] & 0x40) /* flip y ? */
+ {
+ data = *((UINT16 *) &state->m_lcd.gb_vram->base()[ ((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2]);
+ }
+ else
+ {
+ data = *((UINT16 *) &state->m_lcd.gb_vram->base()[ ((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (line - oam[0]) * 2]);
+ }
+#ifndef LSB_FIRST
+ data = (data << 8) | (data >> 8);
+#endif
+
+ switch (oam[3] & 0xA0)
+ {
+ case 0xA0: /* priority is set (behind bgnd & wnd, flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
+ if (colour && !state->m_lcd.bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
+ {
+ if ( ! state->m_lcd.gbc_mode )
+ colour = pal ? state->m_lcd.gb_spal1[colour] : state->m_lcd.gb_spal0[colour];
+ gb_plot_pixel(bitmap, xindex, yindex, state->m_lcd.cgb_spal[pal + colour]);
+ }
+ data >>= 1;
+ }
+ break;
+ case 0x20: /* priority is not set (overlaps bgnd & wnd, flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
+ if((state->m_lcd.bg_zbuf[xindex] & 0x80) && (state->m_lcd.bg_zbuf[xindex] & 0x7f) && (LCDCONT & 0x1))
+ colour = 0;
+ if (colour && xindex >= 0 && xindex < 160)
+ {
+ if ( ! state->m_lcd.gbc_mode )
+ colour = pal ? state->m_lcd.gb_spal1[colour] : state->m_lcd.gb_spal0[colour];
+ gb_plot_pixel(bitmap, xindex, yindex, state->m_lcd.cgb_spal[pal + colour]);
+ }
+ data >>= 1;
+ }
+ break;
+ case 0x80: /* priority is set (behind bgnd & wnd, don't flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
+ if (colour && !state->m_lcd.bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
+ {
+ if ( ! state->m_lcd.gbc_mode )
+ colour = pal ? state->m_lcd.gb_spal1[colour] : state->m_lcd.gb_spal0[colour];
+ gb_plot_pixel(bitmap, xindex, yindex, state->m_lcd.cgb_spal[pal + colour]);
+ }
+ data <<= 1;
+ }
+ break;
+ case 0x00: /* priority is not set (overlaps bgnd & wnd, don't flip x) */
+ for (bit = 0; bit < 8; bit++, xindex++)
+ {
+ register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
+ if((state->m_lcd.bg_zbuf[xindex] & 0x80) && (state->m_lcd.bg_zbuf[xindex] & 0x7f) && (LCDCONT & 0x1))
+ colour = 0;
+ if (colour && xindex >= 0 && xindex < 160)
+ {
+ if ( ! state->m_lcd.gbc_mode )
+ colour = pal ? state->m_lcd.gb_spal1[colour] : state->m_lcd.gb_spal0[colour];
+ gb_plot_pixel(bitmap, xindex, yindex, state->m_lcd.cgb_spal[pal + colour]);
+ }
+ data <<= 1;
+ }
+ break;
+ }
+ }
+ oam -= 4;
+ }
+}
+
+static void cgb_update_scanline ( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ bitmap_ind16 &bitmap = state->m_bitmap;
+
+ g_profiler.start(PROFILER_VIDEO);
+
+ if ( ( LCDSTAT & 0x03 ) == 0x03 )
+ {
+ /* Calcuate number of pixels to render based on time still left on the timer */
+ UINT32 cycles_to_go = machine.device<cpu_device>("maincpu")->attotime_to_cycles(state->m_lcd.lcd_timer ->remaining( ) );
+ int l = 0;
+
+ if ( state->m_lcd.start_x < 0 )
+ {
+ /* Window is enabled if the hardware says so AND the current scanline is
+ * within the window AND the window X coordinate is <=166 */
+ state->m_lcd.layer[1].enabled = ( ( LCDCONT & 0x20 ) && ( state->m_lcd.current_line >= WNDPOSY ) && ( WNDPOSX <= 166 ) ) ? 1 : 0;
+
+ /* BG is enabled if the hardware says so AND (window_off OR (window_on
+ * AND window's X position is >=7 ) ) */
+ state->m_lcd.layer[0].enabled = ( ( LCDCONT & 0x01 ) && ( ( ! state->m_lcd.layer[1].enabled ) || ( state->m_lcd.layer[1].enabled && ( WNDPOSX >= 7 ) ) ) ) ? 1 : 0;
+
+ if ( state->m_lcd.layer[0].enabled )
+ {
+ state->m_lcd.layer[0].bgline = ( SCROLLY + state->m_lcd.current_line ) & 0xFF;
+ state->m_lcd.layer[0].bg_map = state->m_lcd.gb_bgdtab;
+ state->m_lcd.layer[0].gbc_map = state->m_lcd.gbc_bgdtab;
+ state->m_lcd.layer[0].xindex = SCROLLX >> 3;
+ state->m_lcd.layer[0].xshift = SCROLLX & 7;
+ state->m_lcd.layer[0].xstart = 0;
+ state->m_lcd.layer[0].xend = 160;
+ }
+
+ if ( state->m_lcd.layer[1].enabled )
+ {
+ int xpos;
+
+ /* Window X position is offset by 7 so we'll need to adust */
+ xpos = WNDPOSX - 7;
+ if (xpos < 0)
+ xpos = 0;
+
+ state->m_lcd.layer[1].bgline = state->m_lcd.window_lines_drawn;
+ state->m_lcd.layer[1].bg_map = state->m_lcd.gb_wndtab;
+ state->m_lcd.layer[1].gbc_map = state->m_lcd.gbc_wndtab;
+ state->m_lcd.layer[1].xindex = 0;
+ state->m_lcd.layer[1].xshift = 0;
+ state->m_lcd.layer[1].xstart = xpos;
+ state->m_lcd.layer[1].xend = 160;
+ state->m_lcd.layer[0].xend = xpos;
+ }
+ state->m_lcd.start_x = 0;
+ }
+
+ if ( cycles_to_go < 160 )
+ {
+ state->m_lcd.end_x = MIN(160 - cycles_to_go,160);
+ /* Draw empty line when the background is disabled */
+ if ( ! ( LCDCONT & 0x01 ) )
+ {
+ rectangle r(state->m_lcd.start_x, state->m_lcd.end_x - 1, state->m_lcd.current_line, state->m_lcd.current_line);
+ bitmap.fill(( ! state->m_lcd.gbc_mode ) ? 0 : 32767 , r);
+ }
+ while ( l < 2 )
+ {
+ UINT8 xindex, *map, *tiles, *gbcmap;
+ UINT16 data;
+ int i, tile_index;
+
+ if ( ! state->m_lcd.layer[l].enabled )
+ {
+ l++;
+ continue;
+ }
+ map = state->m_lcd.layer[l].bg_map + ( ( state->m_lcd.layer[l].bgline << 2 ) & 0x3E0 );
+ gbcmap = state->m_lcd.layer[l].gbc_map + ( ( state->m_lcd.layer[l].bgline << 2 ) & 0x3E0 );
+ tiles = ( gbcmap[ state->m_lcd.layer[l].xindex ] & 0x08 ) ? state->m_lcd.gbc_chrgen : state->m_lcd.gb_chrgen;
+
+ /* Check for vertical flip */
+ if ( gbcmap[ state->m_lcd.layer[l].xindex ] & 0x40 )
+ {
+ tiles += ( ( 7 - ( state->m_lcd.layer[l].bgline & 0x07 ) ) << 1 );
+ }
+ else
+ {
+ tiles += ( ( state->m_lcd.layer[l].bgline & 0x07 ) << 1 );
+ }
+ xindex = state->m_lcd.start_x;
+ if ( xindex < state->m_lcd.layer[l].xstart )
+ xindex = state->m_lcd.layer[l].xstart;
+ i = state->m_lcd.end_x;
+ if ( i > state->m_lcd.layer[l].xend )
+ i = state->m_lcd.layer[l].xend;
+ i = i - xindex;
+
+ tile_index = ( map[ state->m_lcd.layer[l].xindex ] ^ state->m_lcd.gb_tile_no_mod ) * 16;
+ data = tiles[ tile_index ] | ( tiles[ tile_index + 1 ] << 8 );
+ /* Check for horinzontal flip */
+ if ( gbcmap[ state->m_lcd.layer[l].xindex ] & 0x20 )
+ {
+ data >>= state->m_lcd.layer[l].xshift;
+ }
+ else
+ {
+ data <<= state->m_lcd.layer[l].xshift;
+ }
+
+ while ( i > 0 )
+ {
+ while ( ( state->m_lcd.layer[l].xshift < 8 ) && i )
+ {
+ int colour;
+ /* Check for horinzontal flip */
+ if ( gbcmap[ state->m_lcd.layer[l].xindex ] & 0x20 )
+ {
+ colour = ( ( data & 0x0100 ) ? 2 : 0 ) | ( ( data & 0x0001 ) ? 1 : 0 );
+ data >>= 1;
+ }
+ else
+ {
+ colour = ( ( data & 0x8000 ) ? 2 : 0 ) | ( ( data & 0x0080 ) ? 1 : 0 );
+ data <<= 1;
+ }
+ gb_plot_pixel( bitmap, xindex, state->m_lcd.current_line, state->m_lcd.cgb_bpal[ ( ! state->m_lcd.gbc_mode ) ? state->m_lcd.gb_bpal[colour] : ( ( ( gbcmap[ state->m_lcd.layer[l].xindex ] & 0x07 ) * 4 ) + colour ) ] );
+ state->m_lcd.bg_zbuf[ xindex ] = colour + ( gbcmap[ state->m_lcd.layer[l].xindex ] & 0x80 );
+ xindex++;
+ state->m_lcd.layer[l].xshift++;
+ i--;
+ }
+ if ( state->m_lcd.layer[l].xshift == 8 )
+ {
+ /* Take possible changes to SCROLLY into account */
+ if ( l == 0 )
+ {
+ state->m_lcd.layer[0].bgline = ( SCROLLY + state->m_lcd.current_line ) & 0xFF;
+ map = state->m_lcd.layer[l].bg_map + ( ( state->m_lcd.layer[l].bgline << 2 ) & 0x3E0 );
+ gbcmap = state->m_lcd.layer[l].gbc_map + ( ( state->m_lcd.layer[l].bgline << 2 ) & 0x3E0 );
+ }
+
+ state->m_lcd.layer[l].xindex = ( state->m_lcd.layer[l].xindex + 1 ) & 31;
+ state->m_lcd.layer[l].xshift = 0;
+ tiles = ( gbcmap[ state->m_lcd.layer[l].xindex ] & 0x08 ) ? state->m_lcd.gbc_chrgen : state->m_lcd.gb_chrgen;
+
+ /* Check for vertical flip */
+ if ( gbcmap[ state->m_lcd.layer[l].xindex ] & 0x40 )
+ {
+ tiles += ( ( 7 - ( state->m_lcd.layer[l].bgline & 0x07 ) ) << 1 );
+ }
+ else
+ {
+ tiles += ( ( state->m_lcd.layer[l].bgline & 0x07 ) << 1 );
+ }
+ tile_index = ( map[ state->m_lcd.layer[l].xindex ] ^ state->m_lcd.gb_tile_no_mod ) * 16;
+ data = tiles[ tile_index ] | ( tiles[ tile_index + 1 ] << 8 );
+ }
+ }
+ l++;
+ }
+ if ( state->m_lcd.end_x == 160 && ( LCDCONT & 0x02 ) )
+ {
+ cgb_update_sprites( machine );
+ }
+ state->m_lcd.start_x = state->m_lcd.end_x;
+ }
+ }
+ else
+ {
+ if ( ! ( LCDCONT & 0x80 ) )
+ {
+ /* Draw an empty line when LCD is disabled */
+ if ( state->m_lcd.previous_line != state->m_lcd.current_line )
+ {
+ if ( state->m_lcd.current_line < 144 )
+ {
+ screen_device *screen = machine.first_screen();
+ const rectangle &r1 = screen->visible_area();
+ rectangle r(r1.min_x, r1.max_x, state->m_lcd.current_line, state->m_lcd.current_line);
+ bitmap.fill(( ! state->m_lcd.gbc_mode ) ? 0 : 32767 , r);
+ }
+ state->m_lcd.previous_line = state->m_lcd.current_line;
+ }
+ }
+ }
+
+ g_profiler.stop();
+}
+
+/* OAM contents on power up.
+
+The OAM area seems contain some kind of unit fingerprint. On each boot
+the data is almost always the same. Some random bits are flipped between
+different boots. It is currently unknown how much these fingerprints
+differ between different units.
+
+OAM fingerprints taken from Wilbert Pol's own unit.
+*/
+
+static const UINT8 dmg_oam_fingerprint[0x100] = {
+ 0xD8, 0xE6, 0xB3, 0x89, 0xEC, 0xDE, 0x11, 0x62, 0x0B, 0x7E, 0x48, 0x9E, 0xB9, 0x6E, 0x26, 0xC9,
+ 0x36, 0xF4, 0x7D, 0xE4, 0xD9, 0xCE, 0xFA, 0x5E, 0xA3, 0x77, 0x60, 0xFC, 0x1C, 0x64, 0x8B, 0xAC,
+ 0xB6, 0x74, 0x3F, 0x9A, 0x0E, 0xFE, 0xEA, 0xA9, 0x40, 0x3A, 0x7A, 0xB6, 0xF2, 0xED, 0xA8, 0x3E,
+ 0xAF, 0x2C, 0xD2, 0xF2, 0x01, 0xE0, 0x5B, 0x3A, 0x53, 0x6A, 0x1C, 0x6C, 0x20, 0xD9, 0x22, 0xB4,
+ 0x8C, 0x38, 0x71, 0x69, 0x3E, 0x93, 0xA3, 0x22, 0xCE, 0x76, 0x24, 0xE7, 0x1A, 0x14, 0x6B, 0xB1,
+ 0xF9, 0x3D, 0xBF, 0x3D, 0x74, 0x64, 0xCB, 0xF5, 0xDC, 0x9A, 0x53, 0xC6, 0x0E, 0x78, 0x34, 0xCB,
+ 0x42, 0xB3, 0xFF, 0x07, 0x73, 0xAE, 0x6C, 0xA2, 0x6F, 0x6A, 0xA4, 0x66, 0x0A, 0x8C, 0x40, 0xB3,
+ 0x9A, 0x3D, 0x39, 0x78, 0xAB, 0x29, 0xE7, 0xC5, 0x7A, 0xDD, 0x51, 0x95, 0x2B, 0xE4, 0x1B, 0xF6,
+ 0x31, 0x16, 0x34, 0xFE, 0x11, 0xF2, 0x5E, 0x11, 0xF3, 0x95, 0x66, 0xB9, 0x37, 0xC2, 0xAD, 0x6D,
+ 0x1D, 0xA7, 0x79, 0x06, 0xD7, 0xE5, 0x8F, 0xFA, 0x9C, 0x02, 0x0C, 0x31, 0x8B, 0x17, 0x2E, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const UINT8 mgb_oam_fingerprint[0x100] = {
+ 0xB9, 0xE9, 0x0D, 0x69, 0xBB, 0x7F, 0x00, 0x80, 0xE9, 0x7B, 0x79, 0xA2, 0xFD, 0xCF, 0xD8, 0x0A,
+ 0x87, 0xEF, 0x44, 0x11, 0xFE, 0x37, 0x10, 0x21, 0xFA, 0xFF, 0x00, 0x17, 0xF6, 0x4F, 0x83, 0x03,
+ 0x3A, 0xF4, 0x00, 0x24, 0xBB, 0xAE, 0x05, 0x01, 0xFF, 0xF7, 0x12, 0x48, 0xA7, 0x5E, 0xF6, 0x28,
+ 0x5B, 0xFF, 0x2E, 0x10, 0xFF, 0xB9, 0x50, 0xC8, 0xAF, 0x77, 0x2C, 0x1A, 0x62, 0xD7, 0x81, 0xC2,
+ 0xFD, 0x5F, 0xA0, 0x94, 0xAF, 0xFF, 0x51, 0x20, 0x36, 0x76, 0x50, 0x0A, 0xFD, 0xF6, 0x20, 0x00,
+ 0xFE, 0xF7, 0xA0, 0x68, 0xFF, 0xFC, 0x29, 0x51, 0xA3, 0xFA, 0x06, 0xC4, 0x94, 0xFF, 0x39, 0x0A,
+ 0xFF, 0x6C, 0x20, 0x20, 0xF1, 0xAD, 0x0C, 0x81, 0x56, 0xFB, 0x03, 0x82, 0xFF, 0xFF, 0x08, 0x58,
+ 0x96, 0x7E, 0x01, 0x4D, 0xFF, 0xE4, 0x82, 0xE3, 0x3D, 0xBB, 0x54, 0x00, 0x3D, 0xF3, 0x04, 0x21,
+ 0xB7, 0x39, 0xCC, 0x10, 0xF9, 0x5B, 0x80, 0x50, 0x3F, 0x6A, 0x1C, 0x21, 0x1F, 0xFA, 0xA8, 0x52,
+ 0x5F, 0xB3, 0x44, 0xA1, 0x96, 0x1E, 0x00, 0x27, 0x63, 0x77, 0x30, 0x54, 0x37, 0x6F, 0x60, 0x22,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const UINT8 cgb_oam_fingerprint[0x100] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x74, 0xFF, 0x09, 0x00, 0x9D, 0x61, 0xA8, 0x28, 0x36, 0x1E, 0x58, 0xAA, 0x75, 0x74, 0xA1, 0x42,
+ 0x05, 0x96, 0x40, 0x09, 0x41, 0x02, 0x60, 0x00, 0x1F, 0x11, 0x22, 0xBC, 0x31, 0x52, 0x22, 0x54,
+ 0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
+ 0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
+ 0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
+ 0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04
+};
+
+/*
+ For an AGS in CGB mode this data is: */
+#if 0
+static const UINT8 abs_oam_fingerprint[0x100] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+#endif
+
+enum {
+ GB_LCD_STATE_LYXX_M3=1,
+ GB_LCD_STATE_LYXX_PRE_M0,
+ GB_LCD_STATE_LYXX_M0,
+ GB_LCD_STATE_LYXX_M0_SCX3,
+ GB_LCD_STATE_LYXX_M0_GBC_PAL,
+ GB_LCD_STATE_LYXX_M0_PRE_INC,
+ GB_LCD_STATE_LYXX_M0_INC,
+ GB_LCD_STATE_LY00_M2,
+ GB_LCD_STATE_LYXX_M2,
+ GB_LCD_STATE_LY9X_M1,
+ GB_LCD_STATE_LY9X_M1_INC,
+ GB_LCD_STATE_LY00_M1,
+ GB_LCD_STATE_LY00_M1_1,
+ GB_LCD_STATE_LY00_M1_2,
+ GB_LCD_STATE_LY00_M0
+};
+
+static TIMER_CALLBACK( gb_video_init_vbl )
+{
+ cputag_set_input_line( machine, "maincpu", VBL_INT, ASSERT_LINE );
+}
+
+MACHINE_START( gb_video )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ state->m_lcd.lcd_timer = machine.scheduler().timer_alloc(FUNC(gb_lcd_timer_proc));
+ machine.primary_screen->register_screen_bitmap(state->m_bitmap);
+}
+
+MACHINE_START( gbc_video )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ state->m_lcd.lcd_timer = machine.scheduler().timer_alloc(FUNC(gbc_lcd_timer_proc));
+ machine.primary_screen->register_screen_bitmap(state->m_bitmap);
+}
+
+UINT32 gb_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+void gb_video_reset( running_machine &machine, int mode )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ int i;
+ int vram_size = 0x2000;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ emu_timer *old_timer = state->m_lcd.lcd_timer;
+
+ memset( &state->m_lcd, 0, sizeof(state->m_lcd) );
+ state->m_lcd.lcd_timer = old_timer;
+
+ if (mode == GB_VIDEO_CGB) vram_size = 0x4000;
+
+ /* free regions if already allocated */
+ if (state->memregion("gfx1")->base()) machine.memory().region_free(":gfx1");
+ if (state->memregion("gfx2")->base()) machine.memory().region_free(":gfx2");
+
+ state->m_lcd.gb_vram = machine.memory().region_alloc(":gfx1", vram_size, 1, ENDIANNESS_LITTLE );
+ state->m_lcd.gb_oam = machine.memory().region_alloc(":gfx2", 0x100, 1, ENDIANNESS_LITTLE );
+ memset( state->m_lcd.gb_vram->base(), 0, vram_size );
+
+ state->m_lcd.gb_vram_ptr = state->m_lcd.gb_vram->base();
+ state->m_lcd.gb_chrgen = state->m_lcd.gb_vram->base();
+ state->m_lcd.gb_bgdtab = state->m_lcd.gb_vram->base() + 0x1C00;
+ state->m_lcd.gb_wndtab = state->m_lcd.gb_vram->base() + 0x1C00;
+
+ state->m_lcd.gb_vid_regs[0x06] = 0xFF;
+ for( i = 0x0c; i < _NR_GB_VID_REGS; i++ )
+ {
+ state->m_lcd.gb_vid_regs[i] = 0xFF;
+ }
+
+ LCDSTAT = 0x80;
+ LCDCONT = 0x00; /* Video hardware is turned off at boot time */
+ state->m_lcd.current_line = CURLINE = CMPLINE = 0x00;
+ SCROLLX = SCROLLY = 0x00;
+ SPR0PAL = SPR1PAL = 0xFF;
+ WNDPOSX = WNDPOSY = 0x00;
+
+ /* Initialize palette arrays */
+ for( i = 0; i < 4; i++ )
+ {
+ state->m_lcd.gb_bpal[i] = state->m_lcd.gb_spal0[i] = state->m_lcd.gb_spal1[i] = i;
+ }
+
+ switch( mode )
+ {
+ case GB_VIDEO_DMG:
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(456));
+
+ /* set the scanline update function */
+ state->update_scanline = gb_update_scanline;
+
+ memcpy( state->m_lcd.gb_oam->base(), dmg_oam_fingerprint, 0x100 );
+
+ break;
+ case GB_VIDEO_MGB:
+ /* set the scanline update function */
+ state->update_scanline = gb_update_scanline;
+ /* Initialize part of VRAM. This code must be deleted when we have added the bios dump */
+ for( i = 1; i < 0x0D; i++ )
+ {
+ state->m_lcd.gb_vram->base()[ 0x1903 + i ] = i;
+ state->m_lcd.gb_vram->base()[ 0x1923 + i ] = i + 0x0C;
+ }
+ state->m_lcd.gb_vram->base()[ 0x1910 ] = 0x19;
+
+
+ memcpy( state->m_lcd.gb_oam->base(), mgb_oam_fingerprint, 0x100 );
+
+ /* Make sure the VBlank interrupt is set when the first instruction gets executed */
+ machine.scheduler().timer_set(machine.device<cpu_device>("maincpu")->cycles_to_attotime(1), FUNC(gb_video_init_vbl));
+
+ /* Initialize some video registers */
+ state->gb_video_w( *space, 0x0, 0x91 ); /* LCDCONT */
+ state->gb_video_w( *space, 0x7, 0xFC ); /* BGRDPAL */
+ state->gb_video_w( *space, 0x8, 0xFC ); /* SPR0PAL */
+ state->gb_video_w( *space, 0x9, 0xFC ); /* SPR1PAL */
+
+ CURLINE = state->m_lcd.current_line = 0;
+ LCDSTAT = ( LCDSTAT & 0xF8 ) | 0x05;
+ state->m_lcd.mode = 1;
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(60), GB_LCD_STATE_LY00_M0);
+
+ break;
+ case GB_VIDEO_SGB:
+ /* set the scanline update function */
+ state->update_scanline = sgb_update_scanline;
+
+ break;
+
+ case GB_VIDEO_CGB:
+ /* set the scanline update function */
+ state->update_scanline = cgb_update_scanline;
+
+ memcpy( state->m_lcd.gb_oam->base(), cgb_oam_fingerprint, 0x100 );
+
+ state->m_lcd.gb_chrgen = state->m_lcd.gb_vram->base();
+ state->m_lcd.gbc_chrgen = state->m_lcd.gb_vram->base() + 0x2000;
+ state->m_lcd.gb_bgdtab = state->m_lcd.gb_wndtab = state->m_lcd.gb_vram->base() + 0x1C00;
+ state->m_lcd.gbc_bgdtab = state->m_lcd.gbc_wndtab = state->m_lcd.gb_vram->base() + 0x3C00;
+
+ /* HDMA disabled */
+ state->m_lcd.hdma_enabled = 0;
+ state->m_lcd.hdma_possible = 0;
+
+ state->m_lcd.gbc_mode = 1;
+ break;
+ }
+}
+
+static void gbc_hdma(running_machine &machine, UINT16 length)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ UINT16 src, dst;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ src = ((UINT16)HDMA1 << 8) | (HDMA2 & 0xF0);
+ dst = ((UINT16)(HDMA3 & 0x1F) << 8) | (HDMA4 & 0xF0);
+ dst |= 0x8000;
+ while( length > 0 )
+ {
+ space->write_byte( dst++, space->read_byte( src++ ) );
+ length--;
+ }
+ HDMA1 = src >> 8;
+ HDMA2 = src & 0xF0;
+ HDMA3 = 0x1f & (dst >> 8);
+ HDMA4 = dst & 0xF0;
+ HDMA5--;
+ if( (HDMA5 & 0x7f) == 0x7f )
+ {
+ HDMA5 = 0xff;
+ state->m_lcd.hdma_enabled = 0;
+ }
+}
+
+static void gb_increment_scanline( gb_state *state )
+{
+ state->m_lcd.current_line = ( state->m_lcd.current_line + 1 ) % 154;
+ if ( LCDCONT & 0x80 )
+ {
+ CURLINE = state->m_lcd.current_line;
+ }
+ if ( state->m_lcd.current_line == 0 )
+ {
+ state->m_lcd.window_lines_drawn = 0;
+ }
+}
+
+static TIMER_CALLBACK(gb_lcd_timer_proc)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ static const int sprite_cycles[] = { 0, 8, 20, 32, 44, 52, 64, 76, 88, 96, 108 };
+
+ state->m_lcd.state = param;
+
+ if ( LCDCONT & 0x80 )
+ {
+ switch( state->m_lcd.state )
+ {
+ case GB_LCD_STATE_LYXX_PRE_M0: /* Just before switching to mode 0 */
+ state->m_lcd.mode = 0;
+ if ( LCDSTAT & 0x08 )
+ {
+ if ( ! state->m_lcd.mode_irq )
+ {
+ if ( ! state->m_lcd.line_irq && ! state->m_lcd.delayed_line_irq )
+ {
+ state->m_lcd.mode_irq = 1;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ else
+ {
+ state->m_lcd.mode_irq = 0;
+ }
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0);
+ break;
+ case GB_LCD_STATE_LYXX_M0: /* Switch to mode 0 */
+ /* update current scanline */
+ (*state->update_scanline)( machine );
+ /* Increment the number of window lines drawn if enabled */
+ if ( state->m_lcd.layer[1].enabled )
+ {
+ state->m_lcd.window_lines_drawn++;
+ }
+ state->m_lcd.previous_line = state->m_lcd.current_line;
+ /* Set Mode 0 lcdstate */
+ state->m_lcd.mode = 0;
+ LCDSTAT &= 0xFC;
+ state->m_lcd.oam_locked = UNLOCKED;
+ state->m_lcd.vram_locked = UNLOCKED;
+ /*
+ There seems to a kind of feature in the Game Boy hardware when the lowest bits of the
+ SCROLLX register equals 3 or 7, then the delayed M0 irq is triggered 4 cycles later
+ than usual.
+ The SGB probably has the same bug.
+ */
+ if ( ( SCROLLX & 0x03 ) == 0x03 )
+ {
+ state->m_lcd.scrollx_adjust += 4;
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_SCX3);
+ break;
+ }
+ case GB_LCD_STATE_LYXX_M0_SCX3:
+ /* Generate lcd interrupt if requested */
+ if ( ! state->m_lcd.mode_irq && ( LCDSTAT & 0x08 ) &&
+ ( ( ! state->m_lcd.line_irq && state->m_lcd.delayed_line_irq ) || ! ( LCDSTAT & 0x40 ) ) )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(196 - state->m_lcd.scrollx_adjust - state->m_lcd.sprite_cycles), GB_LCD_STATE_LYXX_M0_PRE_INC);
+ break;
+ case GB_LCD_STATE_LYXX_M0_PRE_INC: /* Just before incrementing the line counter go to mode 2 internally */
+ if ( CURLINE < 143 )
+ {
+ state->m_lcd.mode = 2;
+ state->m_lcd.triggering_mode_irq = ( LCDSTAT & 0x20 ) ? 1 : 0;
+ if ( state->m_lcd.triggering_mode_irq )
+ {
+ if ( ! state->m_lcd.mode_irq )
+ {
+ if ( ! state->m_lcd.line_irq && ! state->m_lcd.delayed_line_irq )
+ {
+ state->m_lcd.mode_irq = 1;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ else
+ {
+ state->m_lcd.mode_irq = 0;
+ }
+ }
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_INC);
+ break;
+ case GB_LCD_STATE_LYXX_M0_INC: /* Increment LY, stay in M0 for 4 more cycles */
+ gb_increment_scanline(state);
+ state->m_lcd.delayed_line_irq = state->m_lcd.line_irq;
+ state->m_lcd.triggering_line_irq = ( ( CMPLINE == CURLINE ) && ( LCDSTAT & 0x40 ) ) ? 1 : 0;
+ state->m_lcd.line_irq = 0;
+ if ( ! state->m_lcd.mode_irq && ! state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq && ! state->m_lcd.triggering_mode_irq )
+ {
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ /* Reset LY==LYC STAT bit */
+ LCDSTAT &= 0xFB;
+ /* Check if we're going into VBlank next */
+ if ( CURLINE == 144 )
+ {
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
+ }
+ else
+ {
+ /* Internally switch to mode 2 */
+ state->m_lcd.mode = 2;
+ /* Generate lcd interrupt if requested */
+ if ( ! state->m_lcd.mode_irq && state->m_lcd.triggering_mode_irq &&
+ ( ( ! state->m_lcd.triggering_line_irq && ! state->m_lcd.delayed_line_irq ) || ! ( LCDSTAT & 0x40 ) ) )
+ {
+ state->m_lcd.mode_irq = 1;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M2);
+ }
+ break;
+ case GB_LCD_STATE_LY00_M2: /* Switch to mode 2 on line #0 */
+ /* Set Mode 2 lcdstate */
+ state->m_lcd.mode = 2;
+ LCDSTAT = ( LCDSTAT & 0xFC ) | 0x02;
+ state->m_lcd.oam_locked = LOCKED;
+ /* Generate lcd interrupt if requested */
+ if ( ( LCDSTAT & 0x20 ) && ! state->m_lcd.line_irq )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ /* Check for regular compensation of x-scroll register */
+ state->m_lcd.scrollx_adjust = ( SCROLLX & 0x04 ) ? 4 : 0;
+ /* Mode 2 lasts approximately 80 clock cycles */
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
+ break;
+ case GB_LCD_STATE_LYXX_M2: /* Switch to mode 2 */
+ /* Update STAT register to the correct state */
+ LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
+ state->m_lcd.oam_locked = LOCKED;
+ /* Generate lcd interrupt if requested */
+ if ( ( state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq && ! ( LCDSTAT & 0x20 ) ) ||
+ ( ! state->m_lcd.mode_irq && ! state->m_lcd.line_irq && ! state->m_lcd.delayed_line_irq && state->m_lcd.triggering_mode_irq ) )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ state->m_lcd.triggering_mode_irq = 0;
+ /* Check if LY==LYC STAT bit should be set */
+ if ( CURLINE == CMPLINE )
+ {
+ LCDSTAT |= 0x04;
+ }
+ /* Check for regular compensation of x-scroll register */
+ state->m_lcd.scrollx_adjust = ( SCROLLX & 0x04 ) ? 4 : 0;
+ /* Mode 2 last for approximately 80 clock cycles */
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
+ break;
+ case GB_LCD_STATE_LYXX_M3: /* Switch to mode 3 */
+ gb_select_sprites(state);
+ state->m_lcd.sprite_cycles = sprite_cycles[ state->m_lcd.sprCount ];
+ /* Set Mode 3 lcdstate */
+ state->m_lcd.mode = 3;
+ LCDSTAT = (LCDSTAT & 0xFC) | 0x03;
+ state->m_lcd.vram_locked = LOCKED;
+ /* Check for compensations of x-scroll register */
+ /* Mode 3 lasts for approximately 172+cycles needed to handle sprites clock cycles */
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(168 + state->m_lcd.scrollx_adjust + state->m_lcd.sprite_cycles), GB_LCD_STATE_LYXX_PRE_M0);
+ state->m_lcd.start_x = -1;
+ break;
+ case GB_LCD_STATE_LY9X_M1: /* Switch to or stay in mode 1 */
+ if ( CURLINE == 144 )
+ {
+ /* Trigger VBlank interrupt */
+ cputag_set_input_line( machine, "maincpu", VBL_INT, ASSERT_LINE );
+ /* Set VBlank lcdstate */
+ state->m_lcd.mode = 1;
+ LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
+ /* Trigger LCD interrupt if requested */
+ if ( LCDSTAT & 0x10 )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ /* Check if LY==LYC STAT bit should be set */
+ if ( CURLINE == CMPLINE )
+ {
+ LCDSTAT |= 0x04;
+ }
+ if ( state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(452), GB_LCD_STATE_LY9X_M1_INC);
+ break;
+ case GB_LCD_STATE_LY9X_M1_INC: /* Increment scanline counter */
+ gb_increment_scanline(state);
+ state->m_lcd.delayed_line_irq = state->m_lcd.line_irq;
+ state->m_lcd.triggering_line_irq = ( ( CMPLINE == CURLINE ) && ( LCDSTAT & 0x40 ) ) ? 1 : 0;
+ state->m_lcd.line_irq = 0;
+ if ( ! state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq )
+ {
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ /* Reset LY==LYC STAT bit */
+ LCDSTAT &= 0xFB;
+ if ( state->m_lcd.current_line == 153 )
+ {
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1);
+ }
+ else
+ {
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
+ }
+ break;
+ case GB_LCD_STATE_LY00_M1: /* we stay in VBlank but current line counter should already be incremented */
+ /* Check LY=LYC for line #153 */
+ if ( state->m_lcd.delayed_line_irq )
+ {
+ if ( state->m_lcd.triggering_line_irq )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ state->m_lcd.delayed_line_irq = state->m_lcd.delayed_line_irq | state->m_lcd.line_irq;
+ if ( CURLINE == CMPLINE )
+ {
+ LCDSTAT |= 0x04;
+ }
+ gb_increment_scanline(state);
+ state->m_lcd.triggering_line_irq = ( ( CMPLINE == CURLINE ) && ( LCDSTAT & 0x40 ) ) ? 1 : 0;
+ state->m_lcd.line_irq = 0;
+ LCDSTAT &= 0xFB;
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4/*8*/), GB_LCD_STATE_LY00_M1_1);
+ break;
+ case GB_LCD_STATE_LY00_M1_1:
+ if ( ! state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq )
+ {
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_2);
+ break;
+ case GB_LCD_STATE_LY00_M1_2: /* Rest of line #0 during VBlank */
+ if ( state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq )
+ {
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ if ( CURLINE == CMPLINE )
+ {
+ LCDSTAT |= 0x04;
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(444), GB_LCD_STATE_LY00_M0);
+ break;
+ case GB_LCD_STATE_LY00_M0: /* The STAT register seems to go to 0 for about 4 cycles */
+ /* Set Mode 0 lcdstat */
+ state->m_lcd.mode = 0;
+ LCDSTAT = ( LCDSTAT & 0xFC );
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY00_M2);
+ break;
+ }
+ }
+ else
+ {
+ gb_increment_scanline(state);
+ if ( state->m_lcd.current_line < 144 )
+ {
+ (*state->update_scanline)( machine );
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(456));
+ }
+}
+
+static TIMER_CALLBACK(gbc_lcd_timer_proc)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ static const int sprite_cycles[] = { 0, 8, 20, 32, 44, 52, 64, 76, 88, 96, 108 };
+
+ state->m_lcd.state = param;
+
+ if ( LCDCONT & 0x80 )
+ {
+ switch( state->m_lcd.state )
+ {
+ case GB_LCD_STATE_LYXX_PRE_M0: /* Just before switching to mode 0 */
+ state->m_lcd.mode = 0;
+ if ( LCDSTAT & 0x08 )
+ {
+ if ( ! state->m_lcd.mode_irq )
+ {
+ if ( ! state->m_lcd.line_irq && ! state->m_lcd.delayed_line_irq )
+ {
+ state->m_lcd.mode_irq = 1;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ else
+ {
+ state->m_lcd.mode_irq = 0;
+ }
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0);
+ break;
+ case GB_LCD_STATE_LYXX_M0: /* Switch to mode 0 */
+ /* update current scanline */
+ (*state->update_scanline)( machine );
+ /* Increment the number of window lines drawn if enabled */
+ if ( state->m_lcd.layer[1].enabled )
+ {
+ state->m_lcd.window_lines_drawn++;
+ }
+ state->m_lcd.previous_line = state->m_lcd.current_line;
+ /* Set Mode 0 lcdstate */
+ state->m_lcd.mode = 0;
+ LCDSTAT &= 0xFC;
+ state->m_lcd.oam_locked = UNLOCKED;
+ state->m_lcd.vram_locked = UNLOCKED;
+ /*
+ There seems to a kind of feature in the Game Boy hardware when the lowest bits of the
+ SCROLLX register equals 3 or 7, then the delayed M0 irq is triggered 4 cycles later
+ than usual.
+ The SGB probably has the same bug.
+ */
+ state->m_lcd.triggering_mode_irq = ( LCDSTAT & 0x08 ) ? 1 : 0;
+ if ( ( SCROLLX & 0x03 ) == 0x03 )
+ {
+ state->m_lcd.scrollx_adjust += 4;
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_SCX3);
+ break;
+ }
+ case GB_LCD_STATE_LYXX_M0_SCX3:
+ /* Generate lcd interrupt if requested */
+ if ( ! state->m_lcd.mode_irq && state->m_lcd.triggering_mode_irq &&
+ ( ( ! state->m_lcd.line_irq && state->m_lcd.delayed_line_irq ) || ! ( LCDSTAT & 0x40 ) ) )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ state->m_lcd.triggering_mode_irq = 0;
+ }
+ if ( ( SCROLLX & 0x03 ) == 0x03 )
+ {
+ state->m_lcd.pal_locked = UNLOCKED;
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_GBC_PAL);
+ break;
+ case GB_LCD_STATE_LYXX_M0_GBC_PAL:
+ state->m_lcd.pal_locked = UNLOCKED;
+ /* Check for HBLANK DMA */
+ if( state->m_lcd.hdma_enabled )
+ {
+ gbc_hdma(machine, 0x10);
+// cpunum_set_reg( 0, LR35902_DMA_CYCLES, 36 );
+ }
+ else
+ {
+ state->m_lcd.hdma_possible = 1;
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(192 - state->m_lcd.scrollx_adjust - state->m_lcd.sprite_cycles), GB_LCD_STATE_LYXX_M0_PRE_INC);
+ break;
+ case GB_LCD_STATE_LYXX_M0_PRE_INC: /* Just before incrementing the line counter go to mode 2 internally */
+ state->m_lcd.cmp_line = CMPLINE;
+ if ( CURLINE < 143 )
+ {
+ state->m_lcd.mode = 2;
+ if ( LCDSTAT & 0x20 )
+ {
+ if ( ! state->m_lcd.mode_irq )
+ {
+ if ( ! state->m_lcd.line_irq && ! state->m_lcd.delayed_line_irq )
+ {
+ state->m_lcd.mode_irq = 1;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ else
+ {
+ state->m_lcd.mode_irq = 0;
+ }
+ }
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_INC);
+ break;
+ case GB_LCD_STATE_LYXX_M0_INC: /* Increment LY, stay in M0 for 4 more cycles */
+ gb_increment_scanline(state);
+ state->m_lcd.delayed_line_irq = state->m_lcd.line_irq;
+ state->m_lcd.triggering_line_irq = ( ( state->m_lcd.cmp_line == CURLINE ) && ( LCDSTAT & 0x40 ) ) ? 1 : 0;
+ state->m_lcd.line_irq = 0;
+ if ( ! state->m_lcd.mode_irq && ! state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq && ! ( LCDSTAT & 0x20 ) )
+ {
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.hdma_possible = 0;
+ /* Check if we're going into VBlank next */
+ if ( CURLINE == 144 )
+ {
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
+ }
+ else
+ {
+ /* Internally switch to mode 2 */
+ state->m_lcd.mode = 2;
+ /* Generate lcd interrupt if requested */
+ if ( ! state->m_lcd.mode_irq && ( LCDSTAT & 0x20 ) &&
+ ( ( ! state->m_lcd.triggering_line_irq && ! state->m_lcd.delayed_line_irq ) || ! ( LCDSTAT & 0x40 ) ) )
+ {
+ state->m_lcd.mode_irq = 1;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M2);
+ }
+ break;
+ case GB_LCD_STATE_LY00_M2: /* Switch to mode 2 on line #0 */
+ /* Set Mode 2 lcdstate */
+ state->m_lcd.mode = 2;
+ LCDSTAT = ( LCDSTAT & 0xFC ) | 0x02;
+ state->m_lcd.oam_locked = LOCKED;
+ /* Generate lcd interrupt if requested */
+ if ( ( LCDSTAT & 0x20 ) && ! state->m_lcd.line_irq )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ /* Check for regular compensation of x-scroll register */
+ state->m_lcd.scrollx_adjust = ( SCROLLX & 0x04 ) ? 4 : 0;
+ /* Mode 2 lasts approximately 80 clock cycles */
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
+ break;
+ case GB_LCD_STATE_LYXX_M2: /* Switch to mode 2 */
+ /* Update STAT register to the correct state */
+ LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
+ state->m_lcd.oam_locked = LOCKED;
+ /* Generate lcd interrupt if requested */
+ if ( ( state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq && ! ( LCDSTAT & 0x20 ) ) ||
+ ( !state->m_lcd.mode_irq && ! state->m_lcd.line_irq && ! state->m_lcd.delayed_line_irq && ( LCDSTAT & 0x20 ) ) )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ /* Check if LY==LYC STAT bit should be set */
+ if ( CURLINE == CMPLINE )
+ {
+ LCDSTAT |= 0x04;
+ }
+ else
+ {
+ LCDSTAT &= ~0x04;
+ }
+ /* Check for regular compensation of x-scroll register */
+ state->m_lcd.scrollx_adjust = ( SCROLLX & 0x04 ) ? 4 : 0;
+ /* Mode 2 last for approximately 80 clock cycles */
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
+ break;
+ case GB_LCD_STATE_LYXX_M3: /* Switch to mode 3 */
+ gb_select_sprites(state);
+ state->m_lcd.sprite_cycles = sprite_cycles[ state->m_lcd.sprCount ];
+ /* Set Mode 3 lcdstate */
+ state->m_lcd.mode = 3;
+ LCDSTAT = (LCDSTAT & 0xFC) | 0x03;
+ state->m_lcd.vram_locked = LOCKED;
+ state->m_lcd.pal_locked = LOCKED;
+ /* Check for compensations of x-scroll register */
+ /* Mode 3 lasts for approximately 172+cycles needed to handle sprites clock cycles */
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(168 + state->m_lcd.scrollx_adjust + state->m_lcd.sprite_cycles), GB_LCD_STATE_LYXX_PRE_M0);
+ state->m_lcd.start_x = -1;
+ break;
+ case GB_LCD_STATE_LY9X_M1: /* Switch to or stay in mode 1 */
+ if ( CURLINE == 144 )
+ {
+ /* Trigger VBlank interrupt */
+ cputag_set_input_line( machine, "maincpu", VBL_INT, ASSERT_LINE );
+ /* Set VBlank lcdstate */
+ state->m_lcd.mode = 1;
+ LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
+ /* Trigger LCD interrupt if requested */
+ if ( LCDSTAT & 0x10 )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ /* Check if LY==LYC STAT bit should be set */
+ if ( CURLINE == CMPLINE )
+ {
+ LCDSTAT |= 0x04;
+ }
+ else
+ {
+ LCDSTAT &= ~0x04;
+ }
+ if ( state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(452), GB_LCD_STATE_LY9X_M1_INC);
+ break;
+ case GB_LCD_STATE_LY9X_M1_INC: /* Increment scanline counter */
+ gb_increment_scanline(state);
+ state->m_lcd.delayed_line_irq = state->m_lcd.line_irq;
+ state->m_lcd.triggering_line_irq = ( ( CMPLINE == CURLINE ) && ( LCDSTAT & 0x40 ) ) ? 1 : 0;
+ state->m_lcd.line_irq = 0;
+ if ( ! state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq )
+ {
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ if ( state->m_lcd.current_line == 153 )
+ {
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1);
+ }
+ else
+ {
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
+ }
+ break;
+ case GB_LCD_STATE_LY00_M1: /* we stay in VBlank but current line counter should already be incremented */
+ /* Check LY=LYC for line #153 */
+ if ( state->m_lcd.delayed_line_irq )
+ {
+ if ( state->m_lcd.triggering_line_irq )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ state->m_lcd.delayed_line_irq = state->m_lcd.delayed_line_irq | state->m_lcd.line_irq;
+ if ( CURLINE == CMPLINE )
+ {
+ LCDSTAT |= 0x04;
+ }
+ else
+ {
+ LCDSTAT &= ~0x04;
+ }
+ gb_increment_scanline(state);
+ state->m_lcd.triggering_line_irq = ( ( CMPLINE == CURLINE ) && ( LCDSTAT & 0x40 ) ) ? 1 : 0;
+ state->m_lcd.line_irq = 0;
+ LCDSTAT &= 0xFB;
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_1);
+ break;
+ case GB_LCD_STATE_LY00_M1_1:
+ if ( ! state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq )
+ {
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_2);
+ break;
+ case GB_LCD_STATE_LY00_M1_2: /* Rest of line #0 during VBlank */
+ if ( state->m_lcd.delayed_line_irq && state->m_lcd.triggering_line_irq )
+ {
+ state->m_lcd.line_irq = state->m_lcd.triggering_line_irq;
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ if ( CURLINE == CMPLINE )
+ {
+ LCDSTAT |= 0x04;
+ }
+ else
+ {
+ LCDSTAT &= ~0x04;
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(444), GB_LCD_STATE_LY00_M0);
+ break;
+ case GB_LCD_STATE_LY00_M0: /* The STAT register seems to go to 0 for about 4 cycles */
+ /* Set Mode 0 lcdstat */
+ state->m_lcd.mode = 0;
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(4), GB_LCD_STATE_LY00_M2);
+ break;
+ }
+ }
+ else
+ {
+ gb_increment_scanline(state);
+ if ( state->m_lcd.current_line < 144 )
+ {
+ (*state->update_scanline)( machine );
+ }
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(456));
+ }
+}
+
+static void gb_lcd_switch_on( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ state->m_lcd.current_line = 0;
+ state->m_lcd.previous_line = 153;
+ state->m_lcd.window_lines_drawn = 0;
+ state->m_lcd.line_irq = 0;
+ state->m_lcd.delayed_line_irq = 0;
+ state->m_lcd.mode = 0;
+ state->m_lcd.oam_locked = LOCKED; /* TODO: Investigate whether this OAM locking is correct. */
+ /* Check for LY=LYC coincidence */
+ if ( CURLINE == CMPLINE )
+ {
+ LCDSTAT |= 0x04;
+ /* Generate lcd interrupt if requested */
+ if ( LCDSTAT & 0x40 )
+ {
+ cputag_set_input_line( machine, "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ state->m_lcd.state = GB_LCD_STATE_LY00_M2;
+ state->m_lcd.lcd_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
+}
+
+READ8_MEMBER(gb_state::gb_video_r)
+{
+ return m_lcd.gb_vid_regs[offset];
+}
+
+READ8_MEMBER(gb_state::gb_vram_r)
+{
+ return ( m_lcd.vram_locked == LOCKED ) ? 0xFF : m_lcd.gb_vram_ptr[offset];
+}
+
+WRITE8_MEMBER(gb_state::gb_vram_w)
+{
+ if ( m_lcd.vram_locked == LOCKED )
+ {
+ return;
+ }
+ m_lcd.gb_vram_ptr[offset] = data;
+}
+
+READ8_MEMBER(gb_state::gb_oam_r)
+{
+ return ( m_lcd.oam_locked == LOCKED ) ? 0xFF : m_lcd.gb_oam->base()[offset];
+}
+
+WRITE8_MEMBER(gb_state::gb_oam_w)
+{
+ if ( m_lcd.oam_locked == LOCKED || offset >= 0xa0 )
+ {
+ return;
+ }
+ m_lcd.gb_oam->base()[offset] = data;
+}
+
+WRITE8_MEMBER(gb_state::gb_video_w)
+{
+ gb_state *state = machine().driver_data<gb_state>();
+ switch (offset)
+ {
+ case 0x00: /* LCDC - LCD Control */
+ m_lcd.gb_chrgen = m_lcd.gb_vram->base() + ((data & 0x10) ? 0x0000 : 0x0800);
+ m_lcd.gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80;
+ m_lcd.gb_bgdtab = m_lcd.gb_vram->base() + ((data & 0x08) ? 0x1C00 : 0x1800 );
+ m_lcd.gb_wndtab = m_lcd.gb_vram->base() + ((data & 0x40) ? 0x1C00 : 0x1800 );
+ /* if LCD controller is switched off, set STAT and LY to 00 */
+ if ( ! ( data & 0x80 ) )
+ {
+ LCDSTAT &= ~0x03;
+ CURLINE = 0;
+ m_lcd.oam_locked = UNLOCKED;
+ m_lcd.vram_locked = UNLOCKED;
+ }
+ /* If LCD is being switched on */
+ if ( !( LCDCONT & 0x80 ) && ( data & 0x80 ) )
+ {
+ gb_lcd_switch_on(machine());
+ }
+ break;
+ case 0x01: /* STAT - LCD Status */
+ data = 0x80 | (data & 0x78) | (LCDSTAT & 0x07);
+ /*
+ Check for the STAT bug:
+ Writing to STAT when the LCD controller is active causes a STAT
+ interrupt to be triggered.
+ */
+ if ( LCDCONT & 0x80 )
+ {
+ /* Triggers seen so far:
+ - 0x40 -> 0x00 - trigger
+ - 0x00 -> 0x08 - trigger
+ - 0x08 -> 0x00 - don't trigger
+ - 0x00 -> 0x20 (mode 3) - trigger
+ - 0x00 -> 0x60 (mode 2) - don't trigger
+ - 0x20 -> 0x60 (mode 3) - trigger
+ - 0x20 -> 0x40 (mode 3) - trigger
+ - 0x40 -> 0x20 (mode 2) - don't trigger
+ - 0x40 -> 0x08 (mode 0) - don't trigger
+ - 0x00 -> 0x40 - trigger only if LY==LYC
+ - 0x20 -> 0x00/0x08/0x10/0x20/0x40 (mode 2, after m2int) - don't trigger
+ - 0x20 -> 0x00/0x08/0x10/0x20/0x40 (mode 3, after m2int) - don't trigger
+ */
+ if ( ! m_lcd.mode_irq && ( ( m_lcd.mode == 1 ) ||
+ ( ( LCDSTAT & 0x40 ) && ! ( data & 0x68 ) ) ||
+ ( ! ( LCDSTAT & 0x40 ) && ( data & 0x40 ) && ( LCDSTAT & 0x04 ) ) ||
+ ( ! ( LCDSTAT & 0x48 ) && ( data & 0x08 ) ) ||
+ ( ( LCDSTAT & 0x60 ) == 0x00 && ( data & 0x60 ) == 0x20 ) ||
+ ( ( LCDSTAT & 0x60 ) == 0x20 && ( data & 0x40 ) )
+ ) )
+ {
+ cputag_set_input_line( machine(), "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ /*
+ - 0x20 -> 0x08/0x18/0x28/0x48 (mode 0, after m2int) - trigger
+ - 0x20 -> 0x00/0x10/0x20/0x40 (mode 0, after m2int) - trigger (stat bug)
+ - 0x00 -> 0xXX (mode 0) - trigger stat bug
+ */
+ if ( m_lcd.mode_irq && m_lcd.mode == 0 )
+ {
+ cputag_set_input_line( machine(), "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ break;
+ case 0x04: /* LY - LCD Y-coordinate */
+ return;
+ case 0x05: /* LYC */
+ if ( CMPLINE != data )
+ {
+ if ( CURLINE == data )
+ {
+ if ( m_lcd.state != GB_LCD_STATE_LYXX_M0_INC && m_lcd.state != GB_LCD_STATE_LY9X_M1_INC )
+ {
+ LCDSTAT |= 0x04;
+ /* Generate lcd interrupt if requested */
+ if ( LCDSTAT & 0x40 )
+ {
+ cputag_set_input_line( machine(), "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ }
+ else
+ {
+ LCDSTAT &= 0xFB;
+ m_lcd.triggering_line_irq = 0;
+ }
+ }
+ break;
+ case 0x06: /* DMA - DMA Transfer and Start Address */
+ {
+ UINT8 *P = m_lcd.gb_oam->base();
+ offset = (UINT16) data << 8;
+ for (data = 0; data < 0xA0; data++)
+ *P++ = space.read_byte(offset++);
+ }
+ return;
+ case 0x07: /* BGP - Background Palette */
+ (*update_scanline)(machine());
+ m_lcd.gb_bpal[0] = data & 0x3;
+ m_lcd.gb_bpal[1] = (data & 0xC) >> 2;
+ m_lcd.gb_bpal[2] = (data & 0x30) >> 4;
+ m_lcd.gb_bpal[3] = (data & 0xC0) >> 6;
+ break;
+ case 0x08: /* OBP0 - Object Palette 0 */
+// (*update_scanline)( machine );
+ m_lcd.gb_spal0[0] = data & 0x3;
+ m_lcd.gb_spal0[1] = (data & 0xC) >> 2;
+ m_lcd.gb_spal0[2] = (data & 0x30) >> 4;
+ m_lcd.gb_spal0[3] = (data & 0xC0) >> 6;
+ break;
+ case 0x09: /* OBP1 - Object Palette 1 */
+// (*update_scanline)( machine );
+ m_lcd.gb_spal1[0] = data & 0x3;
+ m_lcd.gb_spal1[1] = (data & 0xC) >> 2;
+ m_lcd.gb_spal1[2] = (data & 0x30) >> 4;
+ m_lcd.gb_spal1[3] = (data & 0xC0) >> 6;
+ break;
+ case 0x02: /* SCY - Scroll Y */
+ case 0x03: /* SCX - Scroll X */
+ (*update_scanline)(machine());
+ case 0x0A: /* WY - Window Y position */
+ case 0x0B: /* WX - Window X position */
+ break;
+ default: /* Unknown register, no change */
+ return;
+ }
+ m_lcd.gb_vid_regs[ offset ] = data;
+}
+
+READ8_MEMBER(gb_state::gbc_video_r)
+{
+ switch( offset )
+ {
+ case 0x11: /* FF51 */
+ case 0x12: /* FF52 */
+ case 0x13: /* FF53 */
+ case 0x14: /* FF54 */
+ return 0xFF;
+ case 0x29: /* FF69 */
+ case 0x2B: /* FF6B */
+ if ( m_lcd.pal_locked == LOCKED )
+ {
+ return 0xFF;
+ }
+ break;
+ }
+ return m_lcd.gb_vid_regs[offset];
+}
+
+WRITE8_MEMBER(gb_state::gbc_video_w)
+{
+ gb_state *state = machine().driver_data<gb_state>();
+ switch( offset )
+ {
+ case 0x00: /* LCDC - LCD Control */
+ m_lcd.gb_chrgen = m_lcd.gb_vram->base() + ((data & 0x10) ? 0x0000 : 0x0800);
+ m_lcd.gbc_chrgen = m_lcd.gb_vram->base() + ((data & 0x10) ? 0x2000 : 0x2800);
+ m_lcd.gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80;
+ m_lcd.gb_bgdtab = m_lcd.gb_vram->base() + ((data & 0x08) ? 0x1C00 : 0x1800);
+ m_lcd.gbc_bgdtab = m_lcd.gb_vram->base() + ((data & 0x08) ? 0x3C00 : 0x3800);
+ m_lcd.gb_wndtab = m_lcd.gb_vram->base() + ((data & 0x40) ? 0x1C00 : 0x1800);
+ m_lcd.gbc_wndtab = m_lcd.gb_vram->base() + ((data & 0x40) ? 0x3C00 : 0x3800);
+ /* if LCD controller is switched off, set STAT to 00 */
+ if ( ! ( data & 0x80 ) )
+ {
+ LCDSTAT &= ~0x03;
+ CURLINE = 0;
+ m_lcd.oam_locked = UNLOCKED;
+ m_lcd.vram_locked = UNLOCKED;
+ m_lcd.pal_locked = UNLOCKED;
+ }
+ /* If LCD is being switched on */
+ if ( !( LCDCONT & 0x80 ) && ( data & 0x80 ) )
+ {
+ gb_lcd_switch_on(machine());
+ }
+ break;
+ case 0x01: /* STAT - LCD Status */
+ data = 0x80 | (data & 0x78) | (LCDSTAT & 0x07);
+ if ( LCDCONT & 0x80 )
+ {
+ /*
+ - 0x20 -> 0x08/0x18/0x28/0x48 (mode 0, after m2int) - trigger
+ */
+ if ( m_lcd.mode_irq && m_lcd.mode == 0 && ( LCDSTAT & 0x28 ) == 0x20 && ( data & 0x08 ) )
+ {
+ cputag_set_input_line( machine(), "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ /* Check if line irqs are being disabled */
+ if ( ! ( data & 0x40 ) )
+ {
+ m_lcd.delayed_line_irq = 0;
+ }
+ /* Check if line irqs are being enabled */
+ if ( ! ( LCDSTAT & 0x40 ) && ( data & 0x40 ) )
+ {
+ if ( CMPLINE == CURLINE )
+ {
+ m_lcd.line_irq = 1;
+ cputag_set_input_line( machine(), "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ }
+ break;
+ case 0x05: /* LYC */
+ if ( CMPLINE != data )
+ {
+ if ( ( m_lcd.state != GB_LCD_STATE_LYXX_M0_PRE_INC && CURLINE == data ) ||
+ ( m_lcd.state == GB_LCD_STATE_LYXX_M0_INC && m_lcd.triggering_line_irq ) )
+ {
+ LCDSTAT |= 0x04;
+ /* Generate lcd interrupt if requested */
+ if ( LCDSTAT & 0x40 )
+ {
+ cputag_set_input_line( machine(), "maincpu", LCD_INT, ASSERT_LINE );
+ }
+ }
+ else
+ {
+ LCDSTAT &= 0xFB;
+ m_lcd.triggering_line_irq = 0;
+ m_lcd.cmp_line = data;
+ }
+ }
+ break;
+ case 0x07: /* BGP - GB background palette */
+ (*update_scanline)(machine());
+ m_lcd.gb_bpal[0] = data & 0x3;
+ m_lcd.gb_bpal[1] = (data & 0xC) >> 2;
+ m_lcd.gb_bpal[2] = (data & 0x30) >> 4;
+ m_lcd.gb_bpal[3] = (data & 0xC0) >> 6;
+ break;
+ case 0x08: /* OBP0 - GB Object 0 palette */
+ m_lcd.gb_spal0[0] = data & 0x3;
+ m_lcd.gb_spal0[1] = (data & 0xC) >> 2;
+ m_lcd.gb_spal0[2] = (data & 0x30) >> 4;
+ m_lcd.gb_spal0[3] = (data & 0xC0) >> 6;
+ break;
+ case 0x09: /* OBP1 - GB Object 1 palette */
+ m_lcd.gb_spal1[0] = data & 0x3;
+ m_lcd.gb_spal1[1] = (data & 0xC) >> 2;
+ m_lcd.gb_spal1[2] = (data & 0x30) >> 4;
+ m_lcd.gb_spal1[3] = (data & 0xC0) >> 6;
+ break;
+ case 0x0c: /* Undocumented register involved in selecting gb/gbc mode */
+ logerror( "Write to undocumented register: %X = %X\n", offset, data );
+ break;
+ case 0x0F: /* VBK - VRAM bank select */
+ m_lcd.gb_vram_ptr = m_lcd.gb_vram->base() + ( data & 0x01 ) * 0x2000;
+ data |= 0xFE;
+ break;
+ case 0x11: /* HDMA1 - HBL General DMA - Source High */
+ break;
+ case 0x12: /* HDMA2 - HBL General DMA - Source Low */
+ data &= 0xF0;
+ break;
+ case 0x13: /* HDMA3 - HBL General DMA - Destination High */
+ data &= 0x1F;
+ break;
+ case 0x14: /* HDMA4 - HBL General DMA - Destination Low */
+ data &= 0xF0;
+ break;
+ case 0x15: /* HDMA5 - HBL General DMA - Mode, Length */
+ if( !(data & 0x80) )
+ {
+ if( m_lcd.hdma_enabled )
+ {
+ m_lcd.hdma_enabled = 0;
+ data = HDMA5 & 0x80;
+ }
+ else
+ {
+ /* General DMA */
+ gbc_hdma( machine(), ((data & 0x7F) + 1) * 0x10 );
+// cpunum_set_reg( 0, LR35902_DMA_CYCLES, 4 + ( ( ( data & 0x7F ) + 1 ) * 32 ) );
+ data = 0xff;
+ }
+ }
+ else
+ {
+ /* H-Blank DMA */
+ m_lcd.hdma_enabled = 1;
+ data &= 0x7f;
+ m_lcd.gb_vid_regs[offset] = data;
+ /* Check if HDMA should be immediately performed */
+ if ( m_lcd.hdma_possible )
+ {
+ gbc_hdma( machine(), 0x10 );
+// cpunum_set_reg( 0, LR35902_DMA_CYCLES, 36 );
+ m_lcd.hdma_possible = 0;
+ }
+ }
+ break;
+ case 0x28: /* BCPS - Background palette specification */
+ GBCBCPS = data;
+ if (data & 0x01)
+ GBCBCPD = m_lcd.cgb_bpal[( data >> 1 ) & 0x1F] >> 8;
+ else
+ GBCBCPD = m_lcd.cgb_bpal[( data >> 1 ) & 0x1F] & 0xFF;
+ break;
+ case 0x29: /* BCPD - background palette data */
+ if ( m_lcd.pal_locked == LOCKED )
+ {
+ return;
+ }
+ GBCBCPD = data;
+ if (GBCBCPS & 0x01)
+ m_lcd.cgb_bpal[( GBCBCPS >> 1 ) & 0x1F] = ((data << 8) | (m_lcd.cgb_bpal[( GBCBCPS >> 1 ) & 0x1F] & 0xFF)) & 0x7FFF;
+ else
+ m_lcd.cgb_bpal[( GBCBCPS >> 1 ) & 0x1F] = ((m_lcd.cgb_bpal[( GBCBCPS >> 1 ) & 0x1F] & 0xFF00) | data) & 0x7FFF;
+ if( GBCBCPS & 0x80 )
+ {
+ GBCBCPS++;
+ GBCBCPS &= 0xBF;
+ }
+ break;
+ case 0x2A: /* OCPS - Object palette specification */
+ GBCOCPS = data;
+ if (data & 0x01)
+ GBCOCPD = m_lcd.cgb_spal[( data >> 1 ) & 0x1F] >> 8;
+ else
+ GBCOCPD = m_lcd.cgb_spal[( data >> 1 ) & 0x1F] & 0xFF;
+ break;
+ case 0x2B: /* OCPD - Object palette data */
+ if ( m_lcd.pal_locked == LOCKED )
+ {
+ return;
+ }
+ GBCOCPD = data;
+ if (GBCOCPS & 0x01)
+ m_lcd.cgb_spal[( GBCOCPS >> 1 ) & 0x1F] = ((data << 8) | (m_lcd.cgb_spal[( GBCOCPS >> 1 ) & 0x1F] & 0xFF)) & 0x7FFF;
+ else
+ m_lcd.cgb_spal[( GBCOCPS >> 1 ) & 0x1F] = ((m_lcd.cgb_spal[( GBCOCPS >> 1 ) & 0x1F] & 0xFF00) | data) & 0x7FFF;
+ if( GBCOCPS & 0x80 )
+ {
+ GBCOCPS++;
+ GBCOCPS &= 0xBF;
+ }
+ break;
+ /* Undocumented registers */
+ case 0x2C:
+ /* bit 0 can be read/written */
+ logerror( "Write to undocumented register: %X = %X\n", offset, data );
+ data = 0xFE | ( data & 0x01 );
+ if ( data & 0x01 )
+ {
+ m_lcd.gbc_mode = 0;
+ }
+ break;
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ /* whole byte can be read/written */
+ logerror( "Write to undocumented register: %X = %X\n", offset, data );
+ break;
+ case 0x35:
+ /* bit 4-6 can be read/written */
+ logerror( "Write to undocumented register: %X = %X\n", offset, data );
+ data = 0x8F | ( data & 0x70 );
+ break;
+ case 0x36:
+ case 0x37:
+ logerror( "Write to undocumented register: %X = %X\n", offset, data );
+ return;
+ default:
+ /* we didn't handle the write, so pass it to the GB handler */
+ gb_video_w( space, offset, data );
+ return;
+ }
+
+ m_lcd.gb_vid_regs[offset] = data;
+}
+
+
+UINT8 *gb_get_vram_ptr(running_machine &machine)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ return state->m_lcd.gb_vram_ptr;
+}
+
diff --git a/src/mess/video/gba.c b/src/mess/video/gba.c
new file mode 100644
index 00000000000..b0500ddc11a
--- /dev/null
+++ b/src/mess/video/gba.c
@@ -0,0 +1,1811 @@
+ /***************************************************************************
+
+ gba.c
+
+ File to handle emulation of the video hardware of the Game Boy Advance
+
+ By R. Belmont, MooglyGuy, Harmony
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/gba.h"
+
+#define VERBOSE_LEVEL (0)
+
+INLINE void verboselog(running_machine &machine, int n_level, const char *s_fmt, ...)
+{
+ if( VERBOSE_LEVEL >= n_level )
+ {
+ va_list v;
+ char buf[ 32768 ];
+ va_start( v, s_fmt );
+ vsprintf( buf, s_fmt, v );
+ va_end( v );
+ logerror( "%08x: %s", cpu_get_pc(machine.device("maincpu")), buf );
+ }
+}
+
+static const int coeff[32] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
+};
+
+/* Drawing functions */
+static void draw_roz_bitmap_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, INT32 X, INT32 Y, INT32 PA, INT32 PB, INT32 PC, INT32 PD, INT32 *currentx, INT32 *currenty, int changed, int depth);
+static void draw_roz_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, INT32 X, INT32 Y, INT32 PA, INT32 PB, INT32 PC, INT32 PD, INT32 *currentx, INT32 *currenty, int changed);
+static void draw_bg_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, UINT32 hofs, UINT32 vofs);
+static void draw_gba_oam_window(gba_state *state, running_machine &machine, UINT32 *scanline, int y);
+static void draw_gba_oam(gba_state *state, running_machine &machine, UINT32 *scanline, int y);
+static void invalid_gba_draw_function(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int aux);
+
+/* Utility functions */
+INLINE int is_in_window(gba_state *state, int x, int window);
+INLINE UINT32 alpha_blend_pixel(UINT32 color0, UINT32 color1, int ca, int cb);
+INLINE UINT32 increase_brightness(UINT32 color, int coeff_);
+INLINE UINT32 decrease_brightness(UINT32 color, int coeff_);
+
+#include "gbamode0.c"
+#include "gbamode1.c"
+#include "gbamode2.c"
+#include "gbam345.c"
+
+static void (*const gba_draw_scanline_modes[8][3])(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int aux) =
+{
+ /* All modes have three sub-modes: No effects, effects, and windowed effects. */
+ { /* Mode 0: 4 non-rotatable tilemaps and 1 OAM layer */
+ &draw_mode0_scanline,
+ &draw_mode0_scanline_nowindow,
+ &draw_mode0_scanline_all
+ },
+ { /* Mode 1: 2 non-rotatable tilemaps, 1 rotozoomable tilemap, and 1 OAM layer */
+ &draw_mode1_scanline,
+ &draw_mode1_scanline_nowindow,
+ &draw_mode1_scanline_all
+ },
+ { /* Mode 2: 2 rotozoomable tilemaps, and 1 OAM layer */
+ &draw_mode2_scanline,
+ &draw_mode2_scanline_nowindow,
+ &draw_mode2_scanline_all
+ },
+ { /* Mode 3: 1 rotatable 8bpp bitmap and one OAM layer */
+ &draw_roz_bitmap_mode_scanline,
+ &draw_roz_bitmap_mode_scanline_nowindow,
+ &draw_roz_bitmap_mode_scanline_all
+ },
+ { /* Mode 4: 1 rotatable 16bpp bitmap and one OAM layer */
+ &draw_roz_bitmap_mode_scanline,
+ &draw_roz_bitmap_mode_scanline_nowindow,
+ &draw_roz_bitmap_mode_scanline_all
+ },
+ { /* Mode 5: 1 rotatable 4bpp bitmap and one OAM layer */
+ &draw_roz_bitmap_mode_scanline,
+ &draw_roz_bitmap_mode_scanline_nowindow,
+ &draw_roz_bitmap_mode_scanline_all
+ },
+ {
+ &invalid_gba_draw_function,
+ &invalid_gba_draw_function,
+ &invalid_gba_draw_function,
+ },
+ {
+ &invalid_gba_draw_function,
+ &invalid_gba_draw_function,
+ &invalid_gba_draw_function,
+ },
+};
+
+static void invalid_gba_draw_function(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int aux)
+{
+ fatalerror( "Invalid screen mode (6 or 7)!" );
+}
+
+static void draw_roz_bitmap_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, INT32 X, INT32 Y, INT32 PA, INT32 PB, INT32 PC, INT32 PD, INT32 *currentx, INT32 *currenty, int changed, int depth)
+{
+ UINT8 *src8 = (UINT8 *)state->m_gba_vram.target();
+ UINT16 *src16 = (UINT16 *)state->m_gba_vram.target();
+ UINT16 *palette = (UINT16 *)state->m_gba_pram.target();
+ INT32 sx = (depth == 4) ? 160 : 240;
+ INT32 sy = (depth == 4) ? 128 : 160;
+ UINT32 prio = ((ctrl & BGCNT_PRIORITY) << 25) + 0x1000000;
+ INT32 dx, dmx, dy, dmy, startx, starty;
+ INT32 rx, ry, pixx, pixy, x;
+
+ if ((depth == 8) && (state->m_DISPCNT & DISPCNT_FRAMESEL))
+ src8 += 0xa000;
+
+ if ((depth == 4) && (state->m_DISPCNT & DISPCNT_FRAMESEL))
+ src16 += 0xa000/2;
+
+ // sign extend roz parameters
+ if (X & 0x08000000) X |= 0xf0000000;
+ if (Y & 0x08000000) Y |= 0xf0000000;
+ if (PA & 0x8000) PA |= 0xffff0000;
+ if (PB & 0x8000) PB |= 0xffff0000;
+ if (PC & 0x8000) PC |= 0xffff0000;
+ if (PD & 0x8000) PD |= 0xffff0000;
+
+ // re-assign parameters for convenience's sake
+ dx = PA;
+ dmx = PB;
+ dy = PC;
+ dmy = PD;
+ startx = X;
+ starty = Y;
+
+ if(ypos == 0)
+ changed = 3;
+
+ if(changed & 1)
+ *currentx = startx;
+ else
+ *currentx += dmx;
+
+ if(changed & 2)
+ *currenty = starty;
+ else
+ *currenty += dmy;
+
+ rx = *currentx;
+ ry = *currenty;
+
+ if(ctrl & BGCNT_MOSAIC)
+ {
+ INT32 mosaic_line = ((state->m_MOSAIC & 0x00f0) >> 4) + 1;
+ INT32 tempy = (ypos / mosaic_line) * mosaic_line;
+ rx = startx + tempy*dmx;
+ ry = starty + tempy*dmy;
+ }
+
+ pixx = rx >> 8;
+ pixy = ry >> 8;
+
+ for(x = 0; x < 240; x++)
+ {
+ if(pixx < 0 || pixy < 0 || pixx >= sx || pixy >= sy)
+ {
+ scanline[x] = 0x80000000;
+ }
+ else
+ {
+ if (depth == 8)
+ {
+ UINT8 color = src8[pixy*sx + pixx];
+ scanline[x] = color ? (palette[color] | prio) : 0x80000000;
+ }
+ else
+ {
+ scanline[x] = src16[pixy*sx + pixx] | prio;
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+
+ pixx = rx >> 8;
+ pixy = ry >> 8;
+ }
+
+ if(ctrl & BGCNT_MOSAIC)
+ {
+ INT32 mosaicx = (state->m_MOSAIC & 0x0f) + 1;
+ if(mosaicx > 1)
+ {
+ INT32 m = 1;
+ for(x = 0; x < 239; x++)
+ {
+ scanline[x+1] = scanline[x];
+ m++;
+ if(m == mosaicx)
+ {
+ m = 1;
+ x++;
+ }
+ }
+ }
+ }
+}
+
+static void draw_roz_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, INT32 X, INT32 Y, INT32 PA, INT32 PB, INT32 PC, INT32 PD, INT32 *currentx, INT32 *currenty, int changed)
+{
+ UINT32 base, mapbase, size;
+ static const INT32 sizes[4] = { 128, 256, 512, 1024 };
+ INT32 cx, cy, x, pixx, pixy;
+ UINT8 *mgba_vram = (UINT8 *)state->m_gba_vram.target();
+ UINT32 tile;
+ UINT16 *pgba_pram = (UINT16 *)state->m_gba_pram.target();
+ UINT16 pixel;
+ UINT32 prio = ((ctrl & BGCNT_PRIORITY) << 25) + 0x1000000;
+
+ for(x = 0; x < 240; x++)
+ {
+ scanline[x] = 0x80000000;
+ }
+
+ if (state->m_DISPCNT & enablemask)
+ {
+ base = ((ctrl & BGCNT_CHARBASE) >> BGCNT_CHARBASE_SHIFT) * 0x4000; // VRAM base of tiles
+ mapbase = ((ctrl & BGCNT_SCREENBASE) >> BGCNT_SCREENBASE_SHIFT) * 0x800; // VRAM base of map
+ size = (ctrl & BGCNT_SCREENSIZE) >> BGCNT_SCREENSIZE_SHIFT; // size of map in submaps
+
+ // sign extend roz parameters
+ if (X & 0x08000000) X |= 0xf0000000;
+ if (Y & 0x08000000) Y |= 0xf0000000;
+ if (PA & 0x8000) PA |= 0xffff0000;
+ if (PB & 0x8000) PB |= 0xffff0000;
+ if (PC & 0x8000) PC |= 0xffff0000;
+ if (PD & 0x8000) PD |= 0xffff0000;
+
+ if(ypos == 0)
+ {
+ changed = 3;
+ }
+
+ if(changed & 1)
+ {
+ *currentx = X;
+ }
+ else
+ {
+ *currentx += PB;
+ }
+
+ if(changed & 2)
+ {
+ *currenty = Y;
+ }
+ else
+ {
+ *currenty += PD;
+ }
+
+ cx = *currentx;
+ cy = *currenty;
+
+ if(ctrl & BGCNT_MOSAIC)
+ {
+ int mosaicy = ((state->m_MOSAIC & 0xf0) >> 4) + 1;
+ int y = ypos % mosaicy;
+ cx -= y*PB;
+ cy -= y*PD;
+ }
+
+ pixx = cx >> 8;
+ pixy = cy >> 8;
+
+ if(ctrl & BGCNT_PALETTESET_WRAP)
+ {
+ pixx %= sizes[size];
+ pixy %= sizes[size];
+ if(pixx < 0)
+ {
+ pixx += sizes[size];
+ }
+ if(pixy < 0)
+ {
+ pixy += sizes[size];
+ }
+ }
+
+ if(ctrl & BGCNT_PALETTE256)
+ {
+ for(x = 0; x < 240; x++)
+ {
+ if(pixx < 0 || pixy < 0 || pixx >= sizes[size] || pixy >= sizes[size])
+ {
+ scanline[x] = 0x80000000;
+ }
+ else
+ {
+ int tilex = pixx & 7;
+ int tiley = pixy & 7;
+
+ tile = mgba_vram[mapbase + (pixx >> 3) + (pixy >> 3) * (sizes[size] >> 3)];
+ pixel = mgba_vram[base + (tile << 6) + (tiley << 3) + tilex];
+
+ // plot it
+ scanline[x] = pixel ? (pgba_pram[pixel] | prio) : 0x80000000;
+ }
+
+ cx += PA;
+ cy += PC;
+
+ pixx = cx >> 8;
+ pixy = cy >> 8;
+
+ if(ctrl & BGCNT_PALETTESET_WRAP)
+ {
+ pixx %= sizes[size];
+ pixy %= sizes[size];
+ if(pixx < 0)
+ {
+ pixx += sizes[size];
+ }
+ if(pixy < 0)
+ {
+ pixy += sizes[size];
+ }
+ }
+ }
+ }
+ else
+ {
+ for(x = 0; x < 240; x++)
+ {
+ if(pixx < 0 || pixy < 0 || pixx >= sizes[size] || pixy >= sizes[size])
+ {
+ scanline[x] = 0x80000000;
+ }
+ else
+ {
+ int tilex = pixx & 7;
+ int tiley = pixy & 7;
+
+ tile = mgba_vram[mapbase + (pixx >> 3) + (pixy >> 3) * (sizes[size] >> 3)];
+ pixel = mgba_vram[base + (tile << 6) + (tiley << 3) + tilex];
+
+ // plot it
+ scanline[x] = pixel ? (pgba_pram[pixel] | prio) : 0x80000000;
+ }
+
+ cx += PA;
+ cy += PC;
+
+ pixx = cx >> 8;
+ pixy = cy >> 8;
+
+ if(ctrl & BGCNT_PALETTESET_WRAP)
+ {
+ pixx %= sizes[size];
+ pixy %= sizes[size];
+ if(pixx < 0)
+ {
+ pixx += sizes[size];
+ }
+ if(pixy < 0)
+ {
+ pixy += sizes[size];
+ }
+ }
+ }
+ }
+
+ if(ctrl & BGCNT_MOSAIC)
+ {
+ int mosaicx = (state->m_MOSAIC & 0x0f) + 1;
+ if(mosaicx > 1)
+ {
+ int m = 1;
+ for(x = 0; x < 239; x++)
+ {
+ scanline[x+1] = scanline[x];
+ m++;
+ if(m == mosaicx)
+ {
+ m = 1;
+ x++;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void draw_bg_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, UINT32 hofs, UINT32 vofs)
+{
+ UINT8 *vram = (UINT8*)state->m_gba_vram.target();
+ UINT16 *palette = (UINT16*)state->m_gba_pram.target();
+ UINT8 *chardata = &vram[((ctrl & BGCNT_CHARBASE) >> BGCNT_CHARBASE_SHIFT) * 0x4000];
+ UINT16 *screendata = (UINT16*)&vram[((ctrl & BGCNT_SCREENBASE) >> BGCNT_SCREENBASE_SHIFT) * 0x800];
+ UINT32 priority = ((ctrl & BGCNT_PRIORITY) << 25) + 0x1000000;
+ INT32 width = 256;
+ INT32 height = 256;
+ INT32 maskx, masky, pixx, pixy;
+ UINT8 use_mosaic = (ctrl & BGCNT_MOSAIC) ? 1 : 0;
+ INT32 mosaicx = (state->m_MOSAIC & 0x000f) + 1;
+ INT32 mosaicy = ((state->m_MOSAIC & 0x00f0) >> 4) + 1;
+ INT32 stride;
+ INT32 x;
+
+ if(!(state->m_DISPCNT & enablemask))
+ {
+ for(x = 0; x < 240; x++)
+ {
+ scanline[x] = 0x80000000;
+ }
+
+ return;
+ }
+
+ switch((ctrl & BGCNT_SCREENSIZE) >> BGCNT_SCREENSIZE_SHIFT)
+ {
+ case 1:
+ width = 512;
+ break;
+ case 2:
+ height = 512;
+ break;
+ case 3:
+ width = 512;
+ height = 512;
+ break;
+ }
+
+ maskx = width - 1;
+ masky = height - 1;
+
+ pixx = hofs & maskx;
+ pixy = (vofs + ypos) & masky;
+
+ if(use_mosaic)
+ {
+ if((ypos % mosaicy) != 0)
+ {
+ mosaicy = (ypos / mosaicy) * mosaicy;
+ pixy = (vofs + mosaicy) & masky;
+ }
+ }
+
+ if(pixy > 255 && height > 256)
+ {
+ pixy &= 0x000000ff;
+ screendata += 0x400;
+ if(width > 256)
+ {
+ screendata += 0x400;
+ }
+ }
+
+ stride = (pixy >> 3) << 5;
+
+ if(ctrl & BGCNT_PALETTE256)
+ {
+ UINT16 *src = screendata + 0x400 * (pixx >> 8) + ((pixx & 255) >> 3) + stride;
+ for(x = 0; x < 240; x++)
+ {
+ UINT16 data = *src;
+ INT32 tile = data & TILEOBJ_TILE;
+ INT32 tilex = pixx & 7;
+ INT32 tiley = pixy & 7;
+ UINT8 color;
+
+ if(data & TILEOBJ_HFLIP)
+ {
+ tilex = 7 - tilex;
+ }
+ if(data & TILEOBJ_VFLIP)
+ {
+ tiley = 7 - tiley;
+ }
+
+ color = chardata[(tile << 6) + (tiley << 3) + tilex];
+
+ if(color)
+ {
+ scanline[x] = palette[color] | priority;
+ }
+ else
+ {
+ scanline[x] = 0x80000000;
+ }
+
+ if(data & TILEOBJ_HFLIP)
+ {
+ if(tilex == 0)
+ {
+ src++;
+ }
+ }
+ else if(tilex == 7)
+ {
+ src++;
+ }
+
+ pixx++;
+ if(pixx == 256)
+ {
+ if(width > 256)
+ {
+ src = screendata + 0x400 + stride;
+ }
+ else
+ {
+ src = screendata + stride;
+ pixx = 0;
+ }
+ }
+ else if(pixx >= width)
+ {
+ pixx = 0;
+ src = screendata + stride;
+ }
+ }
+ }
+ else
+ {
+ UINT16 *src = screendata + 0x400 * (pixx >> 8) + ((pixx & 255) >> 3) + stride;
+ for(x = 0; x < 240; x++)
+ {
+ UINT16 data = *src;
+ INT32 tile = data & TILEOBJ_TILE;
+ INT32 tilex = pixx & 7;
+ INT32 tiley = pixy & 7;
+ UINT8 color;
+ UINT8 palindex;
+
+ if(data & TILEOBJ_HFLIP)
+ {
+ tilex = 7 - tilex;
+ }
+ if(data & TILEOBJ_VFLIP)
+ {
+ tiley = 7 - tiley;
+ }
+
+ color = chardata[(tile << 5) + (tiley << 2) + (tilex >> 1)];
+
+ if(tilex & 1)
+ {
+ color >>= 4;
+ }
+ else
+ {
+ color &= 0x0f;
+ }
+
+ palindex = (data >> 8) & 0x00f0;
+ if(color)
+ {
+ scanline[x] = palette[palindex + color] | priority;
+ }
+ else
+ {
+ scanline[x] = 0x80000000;
+ }
+
+ if(data & TILEOBJ_HFLIP)
+ {
+ if(tilex == 0)
+ {
+ src++;
+ }
+ }
+ else if(tilex == 7)
+ {
+ src++;
+ }
+
+ pixx++;
+ if(pixx == 256)
+ {
+ if(width > 256)
+ {
+ src = screendata + 0x400 + stride;
+ }
+ else
+ {
+ src = screendata + stride;
+ pixx = 0;
+ }
+ }
+ else if(pixx >= width)
+ {
+ pixx = 0;
+ src = screendata + stride;
+ }
+ }
+ }
+
+ if(use_mosaic)
+ {
+ if(mosaicx > 1)
+ {
+ INT32 m = 1;
+ for(x = 0; x < 239; x++)
+ {
+ scanline[x+1] = scanline[x];
+ m++;
+ if(m == mosaicx)
+ {
+ m = 1;
+ x++;
+ }
+ }
+ }
+ }
+}
+
+static void draw_gba_oam_window(gba_state *state, running_machine &machine, UINT32 *scanline, int y)
+{
+ INT16 gba_oamindex;
+ UINT32 tilebytebase, tileindex, tiledrawindex;
+ UINT32 width, height;
+ UINT16 *pgba_oam = (UINT16 *)state->m_gba_oam.target();
+ int x = 0;
+ UINT8 *src = (UINT8*)state->m_gba_vram.target();
+
+ for(x = 0; x < 240; x++)
+ {
+ scanline[x] = 0x80000000;
+ }
+
+ if( state->m_DISPCNT & DISPCNT_OBJWIN_EN )
+ {
+ for( gba_oamindex = 127; gba_oamindex >= 0; gba_oamindex-- )
+ {
+ INT32 sx, sy;
+ UINT16 attr0, attr1, attr2;
+ INT32 cury;
+
+ attr0 = pgba_oam[(4*gba_oamindex)+0];
+ attr1 = pgba_oam[(4*gba_oamindex)+1];
+ attr2 = pgba_oam[(4*gba_oamindex)+2];
+
+ sx = (attr1 & OBJ_X_COORD);
+ sy = (attr0 & OBJ_Y_COORD);
+
+ if(sy > 160)
+ {
+ sy -= 256;
+ }
+
+ if ((attr0 & OBJ_MODE) != OBJ_MODE_WINDOW)
+ {
+ continue;
+ }
+ else
+ {
+ width = 0;
+ height = 0;
+ switch (attr0 & OBJ_SHAPE )
+ {
+ case OBJ_SHAPE_SQR:
+ switch(attr1 & OBJ_SIZE )
+ {
+ case OBJ_SIZE_8:
+ width = 1;
+ height = 1;
+ break;
+ case OBJ_SIZE_16:
+ width = 2;
+ height = 2;
+ break;
+ case OBJ_SIZE_32:
+ width = 4;
+ height = 4;
+ break;
+ case OBJ_SIZE_64:
+ width = 8;
+ height = 8;
+ break;
+ }
+ break;
+ case OBJ_SHAPE_HORIZ:
+ switch(attr1 & OBJ_SIZE )
+ {
+ case OBJ_SIZE_8:
+ width = 2;
+ height = 1;
+ break;
+ case OBJ_SIZE_16:
+ width = 4;
+ height = 1;
+ break;
+ case OBJ_SIZE_32:
+ width = 4;
+ height = 2;
+ break;
+ case OBJ_SIZE_64:
+ width = 8;
+ height = 4;
+ break;
+ }
+ break;
+ case OBJ_SHAPE_VERT:
+ switch(attr1 & OBJ_SIZE )
+ {
+ case OBJ_SIZE_8:
+ width = 1;
+ height = 2;
+ break;
+ case OBJ_SIZE_16:
+ width = 1;
+ height = 4;
+ break;
+ case OBJ_SIZE_32:
+ width = 2;
+ height = 4;
+ break;
+ case OBJ_SIZE_64:
+ width = 4;
+ height = 8;
+ break;
+ }
+ break;
+ default:
+ width = 0;
+ height = 0;
+ verboselog(machine, 0, "OAM error: Trying to draw OBJ with OBJ_SHAPE = 3!\n" );
+ break;
+ }
+
+ tiledrawindex = tileindex = (attr2 & OBJ_TILENUM);
+ tilebytebase = 0x10000; // the index doesn't change in the higher modes, we just ignore sprites that are out of range
+
+ if (attr0 & OBJ_ROZMODE_ROZ)
+ {
+ INT32 fx, fy, ax, ay, rx, ry;
+ INT16 dx, dy, dmx, dmy;
+ UINT8 color;
+
+ width *= 8;
+ height *= 8;
+
+ if ((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DISABLE)
+ {
+ continue;
+ }
+
+ fx = width;
+ fy = height;
+
+ if((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DBLROZ)
+ {
+ fx *= 2;
+ fy *= 2;
+ }
+
+ cury = y - sy;
+
+ if(cury >= 0 && cury < fy)
+ {
+ if(sx < 240 || ((sx + fx) & 0x1ff) < 240)
+ {
+ int rot = (attr1 & OBJ_SCALE_PARAM) >> OBJ_SCALE_PARAM_SHIFT;
+ dx = (INT16)pgba_oam[(rot << 4)+3];
+ dmx = (INT16)pgba_oam[(rot << 4)+7];
+ dy = (INT16)pgba_oam[(rot << 4)+11];
+ dmy = (INT16)pgba_oam[(rot << 4)+15];
+
+ rx = (width << 7) - (fx >> 1)*dx - (fy >> 1)*dmx + cury * dmx;
+ ry = (height << 7) - (fx >> 1)*dy - (fy >> 1)*dmy + cury * dmy;
+
+ if((attr0 & OBJ_PALMODE) == OBJ_PALMODE_256)
+ {
+ int inc = 32;
+ if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
+ {
+ continue;
+ }
+ if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
+ {
+ inc = sx >> 2;
+ }
+ else
+ {
+ tiledrawindex &= 0x3fe;
+ }
+ for(x = 0; x < fx; x++)
+ {
+ ax = rx >> 8;
+ ay = ry >> 8;
+
+ if(ax < 0 || ax >= sx || ay < 0 || ay >= sy)
+ {
+ }
+ else
+ {
+ color = src[tilebytebase + ((((tiledrawindex + (ay >> 3) * inc) << 5) + ((ay & 0x07) << 3) + ((ax >> 3) << 6) + (ax & 0x07)) & 0x7fff)];
+
+ if(color)
+ {
+ scanline[sx] = 1;
+ }
+ }
+
+ sx = (sx + 1) & 0x1ff;
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ int inc = 32;
+ if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
+ {
+ continue;
+ }
+ if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
+ {
+ inc = sx >> 3;
+ }
+ for(x = 0; x < fx; x++)
+ {
+ ax = rx >> 8;
+ ay = ry >> 8;
+
+ if(ax < 0 || ax >= sx || ay < 0 || ay >= sy)
+ {
+ }
+ else
+ {
+ color = src[tilebytebase + ((((tiledrawindex + (ay >> 3) * inc) << 5) + ((ay & 0x07) << 2) + ((ax >> 3) << 5) + ((ax & 0x07) >> 1)) & 0x7fff)];
+
+ if(ax & 1)
+ {
+ color >>= 4;
+ }
+ else
+ {
+ color &= 0x0f;
+ }
+
+ if(color)
+ {
+ scanline[sx] = 1;
+ }
+ }
+
+ sx = (sx + 1) & 0x1ff;
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ INT32 ax;
+ int cury_ = y - sy;
+
+ width *= 8;
+ height *= 8;
+
+ if(cury_ >= 0 && cury_ < height)
+ {
+ if( ( (sx < 240) || ( ( (sx + width) & 0x1ff ) < 240 ) ) && (attr0 & OBJ_ROZMODE_DISABLE) == 0)
+ {
+ if((attr0 & OBJ_PALMODE) == OBJ_PALMODE_256)
+ {
+ int inc = 32;
+ int address = 0;
+ if(attr1 & OBJ_VFLIP)
+ {
+ cury_ = height - cury_ - 1;
+ }
+ if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
+ {
+ continue;
+ }
+
+ if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
+ {
+ inc = width >> 2;
+ }
+ else
+ {
+ tiledrawindex &= 0x3fe;
+ }
+
+ ax = 0;
+ if(attr1 & OBJ_HFLIP)
+ {
+ ax = width - 1;
+ }
+
+ address = 0x10000 + ((((tiledrawindex + (cury_ >> 3) * inc) << 5) + ((cury_ & 7) << 3) + ((ax >> 3) << 6) + (ax & 7)) & 0x7fff);
+
+ if(attr1 & OBJ_HFLIP)
+ {
+ ax = 7;
+ }
+
+ for(x = 0; x < width; x++)
+ {
+ if(sx < 240)
+ {
+ UINT8 color = src[address];
+
+ if(color)
+ {
+ scanline[sx] = 1;
+ }
+ }
+
+ sx = (sx + 1) & 0x1ff;
+
+ if(attr1 & OBJ_HFLIP)
+ {
+ ax--;
+ address--;
+ if(ax == -1)
+ {
+ address -= 56;
+ ax = 7;
+ }
+ if(address < 0x10000)
+ {
+ address += 0x8000;
+ }
+ }
+ else
+ {
+ ax++;
+ address++;
+ if(ax == 8)
+ {
+ address += 56;
+ ax = 0;
+ }
+ if(address > 0x17fff)
+ {
+ address -= 0x8000;
+ }
+ }
+ }
+ }
+ else
+ {
+ int inc = 32;
+ UINT32 address;
+ if(attr1 & OBJ_VFLIP)
+ {
+ cury_ = height - cury_ - 1;
+ }
+ if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
+ {
+ continue;
+ }
+
+ if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
+ {
+ inc = width >> 3;
+ }
+
+ ax = 0;
+ if(attr1 & OBJ_HFLIP)
+ {
+ ax = width - 1;
+ }
+
+ address = 0x10000 + ((((tiledrawindex + (cury_ >> 3) * inc) << 5) + ((cury_ & 0x07) << 2) + ((ax >> 3) << 5) + ((ax & 0x07) >> 1)) & 0x7fff);
+ if(attr1 & OBJ_HFLIP)
+ {
+ ax = 7;
+ for(x = width - 1; x >= 0; x--)
+ {
+ if(sx < 240)
+ {
+ UINT8 color = src[address];
+ if(x & 1)
+ {
+ color >>= 4;
+ }
+ else
+ {
+ color &= 0x0f;
+ }
+
+ if(color)
+ {
+ scanline[sx] = 1;
+ }
+ }
+
+ sx = (sx + 1) & 0x1ff;
+ ax--;
+ if((x & 1) == 0)
+ {
+ address--;
+ }
+ if(ax == -1)
+ {
+ ax = 7;
+ address -= 28;
+ }
+ if(address < 0x10000)
+ {
+ address += 0x8000;
+ }
+ }
+ }
+ else
+ {
+ for(x = 0; x < width; x++)
+ {
+ if(sx < 240)
+ {
+ UINT8 color = src[address];
+
+ if(x & 1)
+ {
+ color >>= 4;
+ }
+ else
+ {
+ color &= 0x0f;
+ }
+
+ if(color)
+ {
+ scanline[sx] = 1;
+ }
+ }
+
+ sx = (sx + 1) & 0x1ff;
+ ax++;
+ if(x & 1)
+ {
+ address++;
+ }
+ if(ax == 8)
+ {
+ address += 28;
+ ax = 0;
+ }
+ if(address > 0x17fff)
+ {
+ address -= 0x8000;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void draw_gba_oam(gba_state *state, running_machine &machine, UINT32 *scanline, int y)
+{
+ INT16 gba_oamindex;
+ INT32 mosaiccnt = 0;
+ INT32 mosaicy = ((state->m_MOSAIC & 0xf000) >> 12) + 1;
+ INT32 mosaicx = ((state->m_MOSAIC & 0x0f00) >> 8) + 1;
+ UINT32 tileindex, tiledrawindex; //, tilebytebase
+ UINT8 width, height;
+ UINT16 *pgba_oam = (UINT16 *)state->m_gba_oam.target();
+ UINT8 *src = (UINT8 *)state->m_gba_vram.target();
+ UINT16 *palette = (UINT16*)state->m_gba_pram.target();
+ int x = 0;
+
+ for(x = 0; x < 240; x++)
+ {
+ scanline[x] = 0x80000000;
+ }
+
+ if( state->m_DISPCNT & DISPCNT_OBJ_EN )
+ {
+ for( gba_oamindex = 0; gba_oamindex < 128; gba_oamindex++ )
+ {
+ UINT16 attr0, attr1, attr2;
+ INT32 cury;
+ UINT32 prio;
+ UINT32 priority;
+
+ attr0 = pgba_oam[(4*gba_oamindex)+0];
+ attr1 = pgba_oam[(4*gba_oamindex)+1];
+ attr2 = pgba_oam[(4*gba_oamindex)+2];
+ priority = (attr2 & OBJ_PRIORITY) >> OBJ_PRIORITY_SHIFT;
+ prio = (priority << 25) | ((attr0 & OBJ_MODE) << 6);
+
+ if ((attr0 & OBJ_MODE) != OBJ_MODE_WINDOW)
+ {
+ width = 0;
+ height = 0;
+ switch (attr0 & OBJ_SHAPE)
+ {
+ case OBJ_SHAPE_SQR:
+ switch(attr1 & OBJ_SIZE )
+ {
+ case OBJ_SIZE_8:
+ width = 1;
+ height = 1;
+ break;
+ case OBJ_SIZE_16:
+ width = 2;
+ height = 2;
+ break;
+ case OBJ_SIZE_32:
+ width = 4;
+ height = 4;
+ break;
+ case OBJ_SIZE_64:
+ width = 8;
+ height = 8;
+ break;
+ }
+ break;
+ case OBJ_SHAPE_HORIZ:
+ switch(attr1 & OBJ_SIZE )
+ {
+ case OBJ_SIZE_8:
+ width = 2;
+ height = 1;
+ break;
+ case OBJ_SIZE_16:
+ width = 4;
+ height = 1;
+ break;
+ case OBJ_SIZE_32:
+ width = 4;
+ height = 2;
+ break;
+ case OBJ_SIZE_64:
+ width = 8;
+ height = 4;
+ break;
+ }
+ break;
+ case OBJ_SHAPE_VERT:
+ switch(attr1 & OBJ_SIZE )
+ {
+ case OBJ_SIZE_8:
+ width = 1;
+ height = 2;
+ break;
+ case OBJ_SIZE_16:
+ width = 1;
+ height = 4;
+ break;
+ case OBJ_SIZE_32:
+ width = 2;
+ height = 4;
+ break;
+ case OBJ_SIZE_64:
+ width = 4;
+ height = 8;
+ break;
+ }
+ break;
+ default:
+ width = 0;
+ height = 0;
+ verboselog(machine, 0, "OAM error: Trying to draw OBJ with OBJ_SHAPE = 3!\n" );
+ break;
+ }
+
+ tiledrawindex = tileindex = (attr2 & OBJ_TILENUM);
+// tilebytebase = 0x10000; // the index doesn't change in the higher modes, we just ignore sprites that are out of range
+
+ if (attr0 & OBJ_ROZMODE_ROZ)
+ {
+ INT32 sx, sy;
+ INT32 fx, fy, rx, ry;
+ INT16 dx, dy, dmx, dmy;
+
+ width *= 8;
+ height *= 8;
+
+ if ((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DISABLE)
+ {
+ continue;
+ }
+
+ sx = (attr1 & OBJ_X_COORD);
+ sy = (attr0 & OBJ_Y_COORD);
+
+ if(sy > 160)
+ {
+ sy -= 256;
+ }
+
+ fx = width;
+ fy = height;
+
+ if((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DBLROZ)
+ {
+ fx *= 2;
+ fy *= 2;
+ }
+
+ cury = y - sy;
+
+ if(cury >= 0 && cury < fy)
+ {
+ if(sx < 240 || ((sx + fx) & 0x1ff) < 240)
+ {
+ INT32 oamparam = (attr1 & OBJ_SCALE_PARAM) >> OBJ_SCALE_PARAM_SHIFT;
+
+ dx = (INT16)pgba_oam[(oamparam << 4)+3];
+ dmx = (INT16)pgba_oam[(oamparam << 4)+7];
+ dy = (INT16)pgba_oam[(oamparam << 4)+11];
+ dmy = (INT16)pgba_oam[(oamparam << 4)+15];
+
+ if(attr0 & OBJ_MOSAIC)
+ {
+ cury -= (cury % mosaicy);
+ }
+
+ rx = (width << 7) - (fx >> 1)*dx - (fy >> 1)*dmx + cury*dmx;
+ ry = (height << 7) - (fx >> 1)*dy - (fy >> 1)*dmy + cury*dmy;
+
+ if((attr0 & OBJ_PALMODE) == OBJ_PALMODE_256)
+ {
+ INT32 inc = 32;
+
+ if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
+ {
+ continue;
+ }
+
+ if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
+ {
+ inc = width >> 2;
+ }
+ else
+ {
+ tiledrawindex &= 0x3fe;
+ }
+
+ for(x = 0; x < fx; x++)
+ {
+ INT32 pixx = rx >> 8;
+ INT32 pixy = ry >> 8;
+
+ if(!(pixx < 0 || pixx >= width || pixy < 0 || pixy >= height || sx >= 240))
+ {
+ UINT8 color = src[0x10000 + ((((tiledrawindex + (pixy >> 3) * inc) << 5) + ((pixy & 7) << 3) + ((pixx >> 3) << 6) + (pixx & 7)) & 0x7fff)];
+ if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
+ {
+ scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+ else if(color != 0 && prio < (scanline[sx] & 0xff000000))
+ {
+ scanline[sx] = palette[256 + color] | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+
+ if(attr0 & OBJ_MOSAIC)
+ {
+ mosaiccnt++;
+ if(mosaiccnt == mosaicx)
+ {
+ mosaiccnt = 0;
+ }
+ }
+ }
+
+ sx++;
+ sx &= 0x1ff;
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ INT32 inc = 32;
+ INT32 palentry = (attr2 >> 8) & 0xf0;
+
+ if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
+ {
+ continue;
+ }
+
+ if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
+ {
+ inc = width >> 3;
+ }
+
+ for(x = 0; x < fx; x++)
+ {
+ INT32 pixx = rx >> 8;
+ INT32 pixy = ry >> 8;
+
+ if(!(pixx < 0 || pixx >= width || pixy < 0 || pixy >= height || sx >= 240))
+ {
+ UINT8 color = src[0x10000 + ((((tiledrawindex + (pixy >> 3) * inc) << 5) + ((pixy & 7) << 2) + ((pixx >> 3) << 5) + ((pixx & 7) >> 1)) & 0x7fff)];
+
+ if(pixx & 1)
+ {
+ color >>= 4;
+ }
+ else
+ {
+ color &= 0x0f;
+ }
+
+ if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
+ {
+ scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+ else if(color != 0 && prio < (scanline[sx] & 0xff000000))
+ {
+ scanline[sx] = palette[256 + palentry + color] | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+ }
+
+ if(attr0 & OBJ_MOSAIC)
+ {
+ mosaiccnt++;
+ if(mosaiccnt == mosaicx)
+ {
+ mosaiccnt = 0;
+ }
+ }
+
+ sx++;
+
+ sx &= 0x1ff;
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ INT32 sx, sy;
+ INT32 vflip = (attr1 & OBJ_VFLIP) ? 1 : 0;
+ INT32 hflip = (attr1 & OBJ_HFLIP) ? 1 : 0;
+
+ width *= 8;
+ height *= 8;
+
+ if ((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DISABLE)
+ {
+ continue;
+ }
+
+ sx = (attr1 & OBJ_X_COORD);
+ sy = (attr0 & OBJ_Y_COORD);
+
+ if(sy > 160)
+ {
+ sy -= 256;
+ }
+
+ cury = y - sy;
+ if(cury >= 0 && cury < height)
+ {
+ if(sx < 240 || ((sx + width) & 0x1ff) < 240)
+ {
+ if((attr0 & OBJ_PALMODE) == OBJ_PALMODE_256)
+ {
+ INT32 pixx;
+ INT32 inc = 32;
+ INT32 address = 0;
+
+ if(vflip)
+ {
+ cury = height - cury - 1;
+ }
+
+ if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
+ {
+ continue;
+ }
+
+ if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
+ {
+ inc = width >> 2;
+ }
+ else
+ {
+ tiledrawindex &= 0x3fe;
+ }
+
+ pixx = 0;
+ if(hflip)
+ {
+ pixx = width - 1;
+ }
+
+ if(attr0 & OBJ_MOSAIC)
+ {
+ cury -= (cury % mosaicy);
+ }
+
+ address = 0x10000 + ((((tiledrawindex + (cury >> 3) * inc) << 5) + ((cury & 7) << 3) + ((pixx >> 3) << 6) + (pixx & 7)) & 0x7fff);
+
+ if(hflip)
+ {
+ pixx = 7;
+ }
+
+ for(x = 0; x < width; x++)
+ {
+ if(sx < 240)
+ {
+ UINT8 color = src[address];
+ if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
+ {
+ scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+ else if(color != 0 && prio < (scanline[sx] & 0xff000000))
+ {
+ scanline[sx] = palette[256 + color] | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+ }
+
+ if(attr0 & OBJ_MOSAIC)
+ {
+ mosaiccnt++;
+ if(mosaiccnt == mosaicx)
+ {
+ mosaiccnt = 0;
+ }
+ }
+
+ sx++;
+ sx &= 0x1ff;
+
+ if(hflip)
+ {
+ pixx--;
+ address--;
+ if(pixx == -1)
+ {
+ address -= 56;
+ pixx = 7;
+ }
+ if(address < 0x10000)
+ {
+ address += 0x8000;
+ }
+ }
+ else
+ {
+ pixx++;
+ address++;
+ if(pixx == 8)
+ {
+ address += 56;
+ pixx = 0;
+ }
+ if(address > 0x17fff)
+ {
+ address -= 0x8000;
+ }
+ }
+ }
+ }
+ else
+ {
+ INT32 pixx;
+ INT32 inc = 32;
+ UINT32 address = 0;
+
+ if(vflip)
+ {
+ cury = height - cury - 1;
+ }
+
+ if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
+ {
+ continue;
+ }
+
+ if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
+ {
+ inc = width >> 3;
+ }
+
+ pixx = 0;
+ if(hflip)
+ {
+ pixx = width - 1;
+ }
+
+ if(attr0 & OBJ_MOSAIC)
+ {
+ cury -= (cury % mosaicy);
+ }
+
+ address = 0x10000 + ((((tiledrawindex + (cury >> 3) * inc) << 5) + ((cury & 7) << 2) + ((pixx >> 3) << 5) + ((pixx & 7) >> 1)) & 0x7fff);
+
+ if(hflip)
+ {
+ pixx = 7;
+ for(x = width - 1; x >= 0; x--)
+ {
+ if(sx < 240)
+ {
+ UINT8 color = src[address];
+ UINT8 palentry = (attr2 >> 8) & 0xf0;
+
+ if(x & 1)
+ {
+ color >>= 4;
+ }
+ else
+ {
+ color &= 0x0f;
+ }
+
+ if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
+ {
+ scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+ else if(color != 0 && prio < (scanline[sx] & 0xff000000))
+ {
+ scanline[sx] = palette[256 + palentry + color] | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+ }
+
+ sx++;
+ sx &= 0x1ff;
+
+ pixx--;
+ if(!(x & 1))
+ {
+ address--;
+ }
+ if(pixx == -1)
+ {
+ address -= 28;
+ pixx = 7;
+ }
+ if(address < 0x10000)
+ {
+ address += 0x8000;
+ }
+ }
+ }
+ else
+ {
+ for(x = 0; x < width; x++)
+ {
+ if(sx < 240)
+ {
+ UINT8 color = src[address];
+ UINT8 palentry = (attr2 >> 8) & 0xf0;
+
+ if(x & 1)
+ {
+ color >>= 4;
+ }
+ else
+ {
+ color &= 0x0f;
+ }
+
+ if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
+ {
+ scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+ else if(color != 0 && prio < (scanline[sx] & 0xff000000))
+ {
+ scanline[sx] = palette[256 + palentry + color] | prio;
+ if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
+ {
+ scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
+ }
+ }
+ }
+
+ if(attr0 & OBJ_MOSAIC)
+ {
+ mosaiccnt++;
+ if(mosaiccnt == mosaicx)
+ {
+ mosaiccnt = 0;
+ }
+ }
+
+ sx++;
+ sx &= 0x1ff;
+
+ pixx++;
+ if(x & 1)
+ {
+ address++;
+ }
+ if(pixx == 8)
+ {
+ address += 28;
+ pixx = 0;
+ }
+ if(address > 0x17fff)
+ {
+ address -= 0x8000;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+INLINE int is_in_window(gba_state *state, int x, int window)
+{
+ int x0 = state->m_WIN0H >> 8;
+ int x1 = state->m_WIN0H & 0x00ff;
+
+ if(window == 1)
+ {
+ x0 = state->m_WIN1H >> 8;
+ x1 = state->m_WIN1H & 0x00ff;
+ }
+
+ if(x0 <= x1)
+ {
+ if(x >= x0 && x < x1)
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ if(x >= x0 || x < x1)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+INLINE UINT32 alpha_blend_pixel(UINT32 color0, UINT32 color1, int ca, int cb)
+{
+ if(color0 < 0x80000000)
+ {
+ int r0 = (color0 >> 0) & 0x1f;
+ int g0 = (color0 >> 5) & 0x1f;
+ int b0 = (color0 >> 10) & 0x1f;
+ int r1 = (color1 >> 0) & 0x1f;
+ int g1 = (color1 >> 5) & 0x1f;
+ int b1 = (color1 >> 10) & 0x1f;
+ int r = ((r0 * ca) >> 4) + ((r1 * cb) >> 4);
+ int g = ((g0 * ca) >> 4) + ((g1 * cb) >> 4);
+ int b = ((b0 * ca) >> 4) + ((b1 * cb) >> 4);
+
+ if(r > 0x1f) r = 0x1f;
+ if(g > 0x1f) g = 0x1f;
+ if(b > 0x1f) b = 0x1f;
+
+ return (color0 & 0xffff0000) | (b << 10) | (g << 5) | r;
+ }
+ return color0;
+}
+
+INLINE UINT32 increase_brightness(UINT32 color, int coeff_)
+{
+ int r = (color >> 0) & 0x1f;
+ int g = (color >> 5) & 0x1f;
+ int b = (color >> 10) & 0x1f;
+
+ r += ((0x1f - r) * coeff_) >> 4;
+ g += ((0x1f - g) * coeff_) >> 4;
+ b += ((0x1f - b) * coeff_) >> 4;
+
+ if(r > 0x1f) r = 0x1f;
+ if(g > 0x1f) g = 0x1f;
+ if(b > 0x1f) b = 0x1f;
+
+ return (color & 0xffff0000) | (b << 10) | (g << 5) | r;
+}
+
+INLINE UINT32 decrease_brightness(UINT32 color, int coeff_)
+{
+ int r = (color >> 0) & 0x1f;
+ int g = (color >> 5) & 0x1f;
+ int b = (color >> 10) & 0x1f;
+
+ r -= (r * coeff_) >> 4;
+ g -= (g * coeff_) >> 4;
+ b -= (b * coeff_) >> 4;
+
+ if(r < 0) r = 0;
+ if(g < 0) g = 0;
+ if(b < 0) b = 0;
+
+ return (color & 0xffff0000) | (b << 10) | (g << 5) | r;
+}
+
+void gba_draw_scanline(running_machine &machine, int y)
+{
+ gba_state *state = machine.driver_data<gba_state>();
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ UINT16 *scanline = &bitmap.pix16(y);
+ int i, x;
+ UINT8 submode = 0;
+ int bpp = 0;
+
+ // forced blank
+ if (state->m_DISPCNT & DISPCNT_BLANK)
+ {
+ // forced blank is white
+ for (i = 0; i < 240; i++)
+ {
+ scanline[i] = 0x7fff;
+ }
+ return;
+ }
+
+ if(!state->m_fxOn && !state->m_windowOn && !(state->m_DISPCNT & DISPCNT_OBJWIN_EN))
+ {
+ submode = 0;
+ }
+ else if(state->m_fxOn && !state->m_windowOn && !(state->m_DISPCNT & DISPCNT_OBJWIN_EN))
+ {
+ submode = 1;
+ }
+ else
+ {
+ submode = 2;
+ }
+
+ //printf( "mode = %d, %d\n", state->m_DISPCNT & 7, submode );
+
+ switch(state->m_DISPCNT & 7)
+ {
+ case 3:
+ bpp = 16;
+ break;
+ case 4:
+ bpp = 8;
+ break;
+ case 5:
+ bpp = 4;
+ break;
+ }
+
+ gba_draw_scanline_modes[state->m_DISPCNT & 7][submode](machine, state, y, &state->m_xferscan[0][1024], &state->m_xferscan[1][1024], &state->m_xferscan[2][1024], &state->m_xferscan[3][1024], &state->m_xferscan[4][1024], &state->m_xferscan[5][1024], &state->m_xferscan[6][1024], bpp);
+
+ for(x = 0; x < 240; x++)
+ {
+ scanline[x] = state->m_xferscan[6][1024 + x] & 0x7fff;
+ }
+
+ return;
+}
+
+void gba_state::video_start()
+{
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+}
+
+UINT32 gba_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
diff --git a/src/mess/video/gbam345.c b/src/mess/video/gbam345.c
new file mode 100644
index 00000000000..a7540eca05d
--- /dev/null
+++ b/src/mess/video/gbam345.c
@@ -0,0 +1,399 @@
+ /***************************************************************************
+
+ gbam345.c
+
+ Handles GBA rendering for modes 3, 4, and 5.
+
+ By R. Belmont & Harmony
+
+***************************************************************************/
+
+static void draw_roz_bitmap_mode_scanline(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+
+ draw_roz_bitmap_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2X, state->m_BG2Y, state->m_BG2PA, state->m_BG2PB, state->m_BG2PC, state->m_BG2PD, &state->m_gfxBG2X, &state->m_gfxBG2Y, state->m_gfxBG2Changed, bpp);
+ draw_gba_oam(state, machine, lineOBJ, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+
+ if(line2[x] < color)
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if(top == 0x10 && (color & 0x00010000) != 0)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if(line2[x] < back)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+
+ lineMix[x] = color;
+ }
+ state->m_gfxBG2Changed = 0;
+}
+
+static void draw_roz_bitmap_mode_scanline_nowindow(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+ int effect = state->m_BLDCNT & BLDCNT_SFX;
+
+ draw_roz_bitmap_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2X, state->m_BG2Y, state->m_BG2PA, state->m_BG2PB, state->m_BG2PC, state->m_BG2PD, &state->m_gfxBG2X, &state->m_gfxBG2Y, state->m_gfxBG2Changed, bpp);
+ draw_gba_oam(state, machine, lineOBJ, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+
+ if(line2[x] < color)
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if((color & 0x00010000) == 0)
+ {
+ switch(effect)
+ {
+ case BLDCNT_SFX_NONE:
+ break;
+ case BLDCNT_SFX_ALPHA:
+ if(state->m_BLDCNT & top)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if(line2[x] < back)
+ {
+ if(top != 0x04)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+ }
+
+ if((UINT8)(lineOBJ[x] >> 24) < (UINT8)(back >> 24))
+ {
+ if(top != 0x10)
+ {
+ back = lineOBJ[x];
+ top2 = 0x10;
+ }
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ }
+ break;
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ else
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if(line2[x] < back)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ lineMix[x] = color;
+ }
+ state->m_gfxBG2Changed = 0;
+}
+
+static void draw_roz_bitmap_mode_scanline_all(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+ int inWindow0 = 0;
+ int inWindow1 = 0;
+ UINT8 inWin0Mask = state->m_WININ & 0x00ff;
+ UINT8 inWin1Mask = state->m_WININ >> 8;
+ UINT8 outMask = state->m_WINOUT & 0x00ff;
+
+ if(state->m_DISPCNT & DISPCNT_WIN0_EN)
+ {
+ UINT8 v0 = state->m_WIN0V >> 8;
+ UINT8 v1 = state->m_WIN0V & 0x00ff;
+ inWindow0 = ((v0 == v1) && (v0 >= 0xe8)) ? 1 : 0;
+ if(v1 >= v0)
+ {
+ inWindow0 |= (y >= v0 && y < v1) ? 1 : 0;
+ }
+ else
+ {
+ inWindow0 |= (y >= v0 || y < v1) ? 1 : 0;
+ }
+ }
+
+ if(state->m_DISPCNT & DISPCNT_WIN1_EN)
+ {
+ UINT8 v0 = state->m_WIN1V >> 8;
+ UINT8 v1 = state->m_WIN1V & 0x00ff;
+ inWindow1 = ((v0 == v1) && (v0 >= 0xe8)) ? 1 : 0;
+ if(v1 >= v0)
+ {
+ inWindow1 |= (y >= v0 && y < v1) ? 1 : 0;
+ }
+ else
+ {
+ inWindow1 |= (y >= v0 || y < v1) ? 1 : 0;
+ }
+ }
+
+ draw_roz_bitmap_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2X, state->m_BG2Y, state->m_BG2PA, state->m_BG2PB, state->m_BG2PC, state->m_BG2PD, &state->m_gfxBG2X, &state->m_gfxBG2Y, state->m_gfxBG2Changed, bpp);
+ draw_gba_oam(state, machine, lineOBJ, y);
+ draw_gba_oam_window(state, machine, lineOBJWin, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+ UINT8 mask = outMask;
+
+ if((lineOBJWin[x] & 0x80000000) == 0)
+ {
+ mask = state->m_WINOUT >> 8;
+ }
+
+ if(inWindow1)
+ {
+ if(is_in_window(state, x, 1))
+ {
+ mask = inWin1Mask;
+ }
+ }
+
+ if(inWindow0)
+ {
+ if(is_in_window(state, x, 0))
+ {
+ mask = inWin0Mask;
+ }
+ }
+
+ if((mask & 0x04) != 0 && (line2[x] < color))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((mask & 0x10) != 0 && (UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if((mask & 0x20) != 0)
+ {
+ if((color & 0x00010000) == 0)
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_NONE:
+ break;
+ case BLDCNT_SFX_ALPHA:
+ {
+ if(top & state->m_BLDCNT)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+ if((mask & 0x04) != 0 && (line2[x] < back))
+ {
+ if(top != 0x04)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+ }
+
+ if((mask & 0x10) != 0 && ((UINT8)(lineOBJ[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x10)
+ {
+ back = lineOBJ[x];
+ top2 = 0x10;
+ }
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ }
+ break;
+ }
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ else
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((mask & 0x04) != 0 && (line2[x] < back))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ }
+ else if(color & 0x00010000)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((mask & 0x04) != 0 && (line2[x] < back))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ lineMix[x] = color;
+ }
+ state->m_gfxBG2Changed = 0;
+}
diff --git a/src/mess/video/gbamode0.c b/src/mess/video/gbamode0.c
new file mode 100644
index 00000000000..cc168264abe
--- /dev/null
+++ b/src/mess/video/gbamode0.c
@@ -0,0 +1,585 @@
+ /***************************************************************************
+
+ gbamode0.c
+
+ Handles GBA mode 0 screen rendering
+
+ By R. Belmont & Harmony
+
+***************************************************************************/
+
+static void draw_mode0_scanline(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+
+ draw_bg_scanline(state, line0, y, DISPCNT_BG0_EN, state->m_BG0CNT, state->m_BG0HOFS, state->m_BG0VOFS);
+ draw_bg_scanline(state, line1, y, DISPCNT_BG1_EN, state->m_BG1CNT, state->m_BG1HOFS, state->m_BG1VOFS);
+ draw_bg_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2HOFS, state->m_BG2VOFS);
+ draw_bg_scanline(state, line3, y, DISPCNT_BG3_EN, state->m_BG3CNT, state->m_BG3HOFS, state->m_BG3VOFS);
+ draw_gba_oam(state, machine, lineOBJ, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+
+ if(line0[x] < color)
+ {
+ color = line0[x];
+ top = 0x01;
+ }
+
+ if((UINT8)(line1[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line1[x];
+ top = 0x02;
+ }
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((UINT8)(line3[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line3[x];
+ top = 0x08;
+ }
+
+ if((UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if(top == 0x10 && (color & 0x00010000) != 0)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+
+ if((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+
+ lineMix[x] = color;
+ }
+}
+
+static void draw_mode0_scanline_nowindow(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+ int effect = state->m_BLDCNT & BLDCNT_SFX;
+
+ draw_bg_scanline(state, line0, y, DISPCNT_BG0_EN, state->m_BG0CNT, state->m_BG0HOFS, state->m_BG0VOFS);
+ draw_bg_scanline(state, line1, y, DISPCNT_BG1_EN, state->m_BG1CNT, state->m_BG1HOFS, state->m_BG1VOFS);
+ draw_bg_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2HOFS, state->m_BG2VOFS);
+ draw_bg_scanline(state, line3, y, DISPCNT_BG3_EN, state->m_BG3CNT, state->m_BG3HOFS, state->m_BG3VOFS);
+ draw_gba_oam(state, machine, lineOBJ, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+
+ if(line0[x] < color)
+ {
+ color = line0[x];
+ top = 0x01;
+ }
+
+ if(line1[x] < (color & 0xff000000))
+ {
+ color = line1[x];
+ top = 0x02;
+ }
+
+ if(line2[x] < (color & 0xff000000))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if(line3[x] < (color & 0xff000000))
+ {
+ color = line3[x];
+ top = 0x08;
+ }
+
+ if(lineOBJ[x] < (color & 0xff000000))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if((color & 0x00010000) == 0)
+ {
+ switch(effect)
+ {
+ case BLDCNT_SFX_NONE:
+ break;
+ case BLDCNT_SFX_ALPHA:
+ if(state->m_BLDCNT & top)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if(line0[x] < back)
+ {
+ if(top != 0x01)
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+ }
+
+ if(line1[x] < (back & 0xff000000))
+ {
+ if(top != 0x02)
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+ }
+
+ if(line2[x] < (back & 0xff000000))
+ {
+ if(top != 0x04)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+ }
+
+ if(line3[x] < (back & 0xff000000))
+ {
+ if(top != 0x08)
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+ }
+
+ if(lineOBJ[x] < (back & 0xff000000))
+ {
+ if(top != 0x10)
+ {
+ back = lineOBJ[x];
+ top2 = 0x10;
+ }
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ }
+ break;
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ else
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if(line0[x] < back)
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+
+ if(line1[x] < (back & 0xff000000))
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+
+ if(line2[x] < (back & 0xff000000))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if(line3[x] < (back & 0xff000000))
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ lineMix[x] = color;
+ }
+}
+
+static void draw_mode0_scanline_all(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+ int inWindow0 = 0;
+ int inWindow1 = 0;
+ UINT8 inWin0Mask = state->m_WININ & 0x00ff;
+ UINT8 inWin1Mask = state->m_WININ >> 8;
+ UINT8 outMask = state->m_WINOUT & 0x00ff;
+
+ if(state->m_DISPCNT & DISPCNT_WIN0_EN)
+ {
+ UINT8 v0 = state->m_WIN0V >> 8;
+ UINT8 v1 = state->m_WIN0V & 0x00ff;
+ inWindow0 = ((v0 == v1) && (v0 >= 0xe8)) ? 1 : 0;
+ if(v1 >= v0)
+ {
+ inWindow0 |= (y >= v0 && y < v1) ? 1 : 0;
+ }
+ else
+ {
+ inWindow0 |= (y >= v0 || y < v1) ? 1 : 0;
+ }
+ }
+
+ if(state->m_DISPCNT & DISPCNT_WIN1_EN)
+ {
+ UINT8 v0 = state->m_WIN1V >> 8;
+ UINT8 v1 = state->m_WIN1V & 0x00ff;
+ inWindow1 = ((v0 == v1) && (v0 >= 0xe8)) ? 1 : 0;
+ if(v1 >= v0)
+ {
+ inWindow1 |= (y >= v0 && y < v1) ? 1 : 0;
+ }
+ else
+ {
+ inWindow1 |= (y >= v0 || y < v1) ? 1 : 0;
+ }
+ }
+
+ draw_bg_scanline(state, line0, y, DISPCNT_BG0_EN, state->m_BG0CNT, state->m_BG0HOFS, state->m_BG0VOFS);
+ draw_bg_scanline(state, line1, y, DISPCNT_BG1_EN, state->m_BG1CNT, state->m_BG1HOFS, state->m_BG1VOFS);
+ draw_bg_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2HOFS, state->m_BG2VOFS);
+ draw_bg_scanline(state, line3, y, DISPCNT_BG3_EN, state->m_BG3CNT, state->m_BG3HOFS, state->m_BG3VOFS);
+ draw_gba_oam(state, machine, lineOBJ, y);
+ draw_gba_oam_window(state, machine, lineOBJWin, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+ UINT8 mask = outMask;
+
+ if((lineOBJWin[x] & 0x80000000) == 0)
+ {
+ mask = state->m_WINOUT >> 8;
+ }
+
+ if(inWindow1)
+ {
+ if(is_in_window(state, x, 1))
+ {
+ mask = inWin1Mask;
+ }
+ }
+
+ if(inWindow0)
+ {
+ if(is_in_window(state, x, 0))
+ {
+ mask = inWin0Mask;
+ }
+ }
+
+ if((mask & 0x01) != 0 && (line0[x] < color))
+ {
+ color = line0[x];
+ top = 0x01;
+ }
+
+ if((mask & 0x02) != 0 && ((UINT8)(line1[x] >> 24) < (UINT8)(color >> 24)))
+ {
+ color = line1[x];
+ top = 0x02;
+ }
+
+ if((mask & 0x04) != 0 && ((UINT8)(line2[x] >> 24) < (UINT8)(color >> 24)))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((mask & 0x08) != 0 && ((UINT8)(line3[x] >> 24) < (UINT8)(color >> 24)))
+ {
+ color = line3[x];
+ top = 0x08;
+ }
+
+ if((mask & 0x10) != 0 && ((UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24)))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if((mask & 0x20) != 0)
+ {
+ if((color & 0x00010000) == 0)
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_NONE:
+ break;
+ case BLDCNT_SFX_ALPHA:
+ {
+ if(top & state->m_BLDCNT)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+ if((mask & 0x01) != 0 && ((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x01)
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+ }
+
+ if((mask & 0x02) != 0 && ((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x02)
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+ }
+
+ if((mask & 0x04) != 0 && ((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x04)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+ }
+
+ if((mask & 0x08) != 0 && ((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x08)
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+ }
+
+ if((mask & 0x10) != 0 && ((UINT8)(lineOBJ[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x10)
+ {
+ back = lineOBJ[x];
+ top2 = 0x10;
+ }
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ }
+ break;
+ }
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ else
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((mask & 0x01) != 0 && ((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+
+ if((mask & 0x02) != 0 && ((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+
+ if((mask & 0x04) != 0 && ((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if((mask & 0x08) != 0 && ((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ }
+ else if(color & 0x00010000)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((mask & 0x01) != 0 && ((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+
+ if((mask & 0x02) != 0 && ((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+
+ if((mask & 0x04) != 0 && ((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if((mask & 0x08) != 0 && ((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ lineMix[x] = color;
+ }
+}
diff --git a/src/mess/video/gbamode1.c b/src/mess/video/gbamode1.c
new file mode 100644
index 00000000000..1aa4db4afb3
--- /dev/null
+++ b/src/mess/video/gbamode1.c
@@ -0,0 +1,525 @@
+ /***************************************************************************
+
+ gbamode1.c
+
+ Handles GBA mode 1 screen rendering
+
+ By R. Belmont & Harmony
+
+***************************************************************************/
+
+static void draw_mode1_scanline(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+
+ draw_bg_scanline(state, line0, y, DISPCNT_BG0_EN, state->m_BG0CNT, state->m_BG0HOFS, state->m_BG0VOFS);
+ draw_bg_scanline(state, line1, y, DISPCNT_BG1_EN, state->m_BG1CNT, state->m_BG1HOFS, state->m_BG1VOFS);
+ draw_roz_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2X, state->m_BG2Y, state->m_BG2PA, state->m_BG2PB, state->m_BG2PC, state->m_BG2PD, &state->m_gfxBG2X, &state->m_gfxBG2Y, state->m_gfxBG2Changed);
+ draw_gba_oam(state, machine, lineOBJ, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+
+ if(line0[x] < color)
+ {
+ color = line0[x];
+ top = 0x01;
+ }
+
+ if((UINT8)(line1[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line1[x];
+ top = 0x02;
+ }
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if(top == 0x10 && (color & 0x00010000) != 0)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+
+ if((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+
+ lineMix[x] = color;
+ }
+ state->m_gfxBG2Changed = 0;
+}
+
+static void draw_mode1_scanline_nowindow(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+ int effect = state->m_BLDCNT & BLDCNT_SFX;
+
+ draw_bg_scanline(state, line0, y, DISPCNT_BG0_EN, state->m_BG0CNT, state->m_BG0HOFS, state->m_BG0VOFS);
+ draw_bg_scanline(state, line1, y, DISPCNT_BG1_EN, state->m_BG1CNT, state->m_BG1HOFS, state->m_BG1VOFS);
+ draw_roz_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2X, state->m_BG2Y, state->m_BG2PA, state->m_BG2PB, state->m_BG2PC, state->m_BG2PD, &state->m_gfxBG2X, &state->m_gfxBG2Y, state->m_gfxBG2Changed);
+ draw_gba_oam(state, machine, lineOBJ, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+
+ if(line0[x] < color)
+ {
+ color = line0[x];
+ top = 0x01;
+ }
+
+ if(line1[x] < (color & 0xff000000))
+ {
+ color = line1[x];
+ top = 0x02;
+ }
+
+ if(line2[x] < (color & 0xff000000))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if(lineOBJ[x] < (color & 0xff000000))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if((color & 0x00010000) == 0)
+ {
+ switch(effect)
+ {
+ case BLDCNT_SFX_NONE:
+ break;
+ case BLDCNT_SFX_ALPHA:
+ if(state->m_BLDCNT & top)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24))
+ {
+ if(top != 0x01)
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+ }
+
+ if((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24))
+ {
+ if(top != 0x02)
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+ }
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24))
+ {
+ if(top != 0x04)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+ }
+
+ if((UINT8)(lineOBJ[x] >> 24) < (UINT8)(back >> 24))
+ {
+ if(top != 0x10)
+ {
+ back = lineOBJ[x];
+ top2 = 0x10;
+ }
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ }
+ break;
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ else
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+
+ if((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ lineMix[x] = color;
+ }
+ state->m_gfxBG2Changed = 0;
+}
+
+static void draw_mode1_scanline_all(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+ int inWindow0 = 0;
+ int inWindow1 = 0;
+ UINT8 inWin0Mask = state->m_WININ & 0x00ff;
+ UINT8 inWin1Mask = state->m_WININ >> 8;
+ UINT8 outMask = state->m_WINOUT & 0x00ff;
+
+ if(state->m_DISPCNT & DISPCNT_WIN0_EN)
+ {
+ UINT8 v0 = state->m_WIN0V >> 8;
+ UINT8 v1 = state->m_WIN0V & 0x00ff;
+ inWindow0 = ((v0 == v1) && (v0 >= 0xe8)) ? 1 : 0;
+ if(v1 >= v0)
+ {
+ inWindow0 |= (y >= v0 && y < v1) ? 1 : 0;
+ }
+ else
+ {
+ inWindow0 |= (y >= v0 || y < v1) ? 1 : 0;
+ }
+ }
+
+ if(state->m_DISPCNT & DISPCNT_WIN1_EN)
+ {
+ UINT8 v0 = state->m_WIN1V >> 8;
+ UINT8 v1 = state->m_WIN1V & 0x00ff;
+ inWindow1 = ((v0 == v1) && (v0 >= 0xe8)) ? 1 : 0;
+ if(v1 >= v0)
+ {
+ inWindow1 |= (y >= v0 && y < v1) ? 1 : 0;
+ }
+ else
+ {
+ inWindow1 |= (y >= v0 || y < v1) ? 1 : 0;
+ }
+ }
+
+ draw_bg_scanline(state, line0, y, DISPCNT_BG0_EN, state->m_BG0CNT, state->m_BG0HOFS, state->m_BG0VOFS);
+ draw_bg_scanline(state, line1, y, DISPCNT_BG1_EN, state->m_BG1CNT, state->m_BG1HOFS, state->m_BG1VOFS);
+ draw_roz_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2X, state->m_BG2Y, state->m_BG2PA, state->m_BG2PB, state->m_BG2PC, state->m_BG2PD, &state->m_gfxBG2X, &state->m_gfxBG2Y, state->m_gfxBG2Changed);
+ draw_gba_oam(state, machine, lineOBJ, y);
+ draw_gba_oam_window(state, machine, lineOBJWin, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+ UINT8 mask = outMask;
+
+ if((lineOBJWin[x] & 0x80000000) == 0)
+ {
+ mask = state->m_WINOUT >> 8;
+ }
+
+ if(inWindow1)
+ {
+ if(is_in_window(state, x, 1))
+ {
+ mask = inWin1Mask;
+ }
+ }
+
+ if(inWindow0)
+ {
+ if(is_in_window(state, x, 0))
+ {
+ mask = inWin0Mask;
+ }
+ }
+
+ if((mask & 0x01) != 0 && (line0[x] < color))
+ {
+ color = line0[x];
+ top = 0x01;
+ }
+
+ if((mask & 0x02) != 0 && ((UINT8)(line1[x] >> 24) < (UINT8)(color >> 24)))
+ {
+ color = line1[x];
+ top = 0x02;
+ }
+
+ if((mask & 0x04) != 0 && ((UINT8)(line2[x] >> 24) < (UINT8)(color >> 24)))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((mask & 0x10) != 0 && ((UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24)))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if((mask & 0x20) != 0)
+ {
+ if((color & 0x00010000) == 0)
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_NONE:
+ break;
+ case BLDCNT_SFX_ALPHA:
+ {
+ if(top & state->m_BLDCNT)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+ if((mask & 0x01) != 0 && ((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x01)
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+ }
+
+ if((mask & 0x02) != 0 && ((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x02)
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+ }
+
+ if((mask & 0x04) != 0 && ((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x04)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+ }
+
+ if((mask & 0x10) != 0 && ((UINT8)(lineOBJ[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x10)
+ {
+ back = lineOBJ[x];
+ top2 = 0x10;
+ }
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ }
+ break;
+ }
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ else
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((mask & 0x01) != 0 && ((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+
+ if((mask & 0x02) != 0 && ((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+
+ if((mask & 0x04) != 0 && ((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ }
+ else if(color & 0x00010000)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((mask & 0x01) != 0 && ((UINT8)(line0[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line0[x];
+ top2 = 0x01;
+ }
+
+ if((mask & 0x02) != 0 && ((UINT8)(line1[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line1[x];
+ top2 = 0x02;
+ }
+
+ if((mask & 0x04) != 0 && ((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ lineMix[x] = color;
+ }
+ state->m_gfxBG2Changed = 0;
+}
diff --git a/src/mess/video/gbamode2.c b/src/mess/video/gbamode2.c
new file mode 100644
index 00000000000..5b2f6e08781
--- /dev/null
+++ b/src/mess/video/gbamode2.c
@@ -0,0 +1,465 @@
+ /***************************************************************************
+
+ gbamode2.c
+
+ Handles GBA mode 2 screen rendering
+
+ By R. Belmont & Harmony
+
+***************************************************************************/
+
+static void draw_mode2_scanline(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+
+ draw_roz_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2X, state->m_BG2Y, state->m_BG2PA, state->m_BG2PB, state->m_BG2PC, state->m_BG2PD, &state->m_gfxBG2X, &state->m_gfxBG2Y, state->m_gfxBG2Changed);
+ draw_roz_scanline(state, line3, y, DISPCNT_BG3_EN, state->m_BG3CNT, state->m_BG3X, state->m_BG3Y, state->m_BG3PA, state->m_BG3PB, state->m_BG3PC, state->m_BG3PD, &state->m_gfxBG3X, &state->m_gfxBG3Y, state->m_gfxBG3Changed);
+ draw_gba_oam(state, machine, lineOBJ, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((UINT8)(line3[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line3[x];
+ top = 0x08;
+ }
+
+ if((UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if(top == 0x10 && (color & 0x00010000) != 0)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+
+ lineMix[x] = color;
+ }
+ state->m_gfxBG2Changed = 0;
+ state->m_gfxBG3Changed = 0;
+}
+
+static void draw_mode2_scanline_nowindow(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+ int effect = state->m_BLDCNT & BLDCNT_SFX;
+
+ draw_roz_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2X, state->m_BG2Y, state->m_BG2PA, state->m_BG2PB, state->m_BG2PC, state->m_BG2PD, &state->m_gfxBG2X, &state->m_gfxBG2Y, state->m_gfxBG2Changed);
+ draw_roz_scanline(state, line3, y, DISPCNT_BG3_EN, state->m_BG3CNT, state->m_BG3X, state->m_BG3Y, state->m_BG3PA, state->m_BG3PB, state->m_BG3PC, state->m_BG3PD, &state->m_gfxBG3X, &state->m_gfxBG3Y, state->m_gfxBG3Changed);
+ draw_gba_oam(state, machine, lineOBJ, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((UINT8)(line3[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line3[x];
+ top = 0x08;
+ }
+
+ if((UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if((color & 0x00010000) == 0)
+ {
+ switch(effect)
+ {
+ case BLDCNT_SFX_NONE:
+ break;
+ case BLDCNT_SFX_ALPHA:
+ if(state->m_BLDCNT & top)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24))
+ {
+ if(top != 0x04)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+ }
+
+ if((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24))
+ {
+ if(top != 0x08)
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+ }
+
+ if((UINT8)(lineOBJ[x] >> 24) < (UINT8)(back >> 24))
+ {
+ if(top != 0x10)
+ {
+ back = lineOBJ[x];
+ top2 = 0x10;
+ }
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ }
+ break;
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ else
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((UINT8)(line2[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24))
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ lineMix[x] = color;
+ }
+ state->m_gfxBG2Changed = 0;
+ state->m_gfxBG3Changed = 0;
+}
+
+static void draw_mode2_scanline_all(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int bpp)
+{
+ int x = 0;
+ UINT32 backdrop = ((UINT16*)state->m_gba_pram.target())[0] | 0x30000000;
+ int inWindow0 = 0;
+ int inWindow1 = 0;
+ UINT8 inWin0Mask = state->m_WININ & 0x00ff;
+ UINT8 inWin1Mask = state->m_WININ >> 8;
+ UINT8 outMask = state->m_WINOUT & 0x00ff;
+
+ if(state->m_DISPCNT & DISPCNT_WIN0_EN)
+ {
+ UINT8 v0 = state->m_WIN0V >> 8;
+ UINT8 v1 = state->m_WIN0V & 0x00ff;
+ inWindow0 = ((v0 == v1) && (v0 >= 0xe8)) ? 1 : 0;
+ if(v1 >= v0)
+ {
+ inWindow0 |= (y >= v0 && y < v1) ? 1 : 0;
+ }
+ else
+ {
+ inWindow0 |= (y >= v0 || y < v1) ? 1 : 0;
+ }
+ }
+
+ if(state->m_DISPCNT & DISPCNT_WIN1_EN)
+ {
+ UINT8 v0 = state->m_WIN1V >> 8;
+ UINT8 v1 = state->m_WIN1V & 0x00ff;
+ inWindow1 = ((v0 == v1) && (v0 >= 0xe8)) ? 1 : 0;
+ if(v1 >= v0)
+ {
+ inWindow1 |= (y >= v0 && y < v1) ? 1 : 0;
+ }
+ else
+ {
+ inWindow1 |= (y >= v0 || y < v1) ? 1 : 0;
+ }
+ }
+
+ draw_roz_scanline(state, line2, y, DISPCNT_BG2_EN, state->m_BG2CNT, state->m_BG2X, state->m_BG2Y, state->m_BG2PA, state->m_BG2PB, state->m_BG2PC, state->m_BG2PD, &state->m_gfxBG2X, &state->m_gfxBG2Y, state->m_gfxBG2Changed);
+ draw_roz_scanline(state, line3, y, DISPCNT_BG3_EN, state->m_BG3CNT, state->m_BG3X, state->m_BG3Y, state->m_BG3PA, state->m_BG3PB, state->m_BG3PC, state->m_BG3PD, &state->m_gfxBG3X, &state->m_gfxBG3Y, state->m_gfxBG3Changed);
+ draw_gba_oam(state, machine, lineOBJ, y);
+ draw_gba_oam_window(state, machine, lineOBJWin, y);
+
+ for(x = 0; x < 240; x++)
+ {
+ UINT32 color = backdrop;
+ UINT8 top = 0x20;
+ UINT8 mask = outMask;
+
+ if((lineOBJWin[x] & 0x80000000) == 0)
+ {
+ mask = state->m_WINOUT >> 8;
+ }
+
+ if(inWindow1)
+ {
+ if(is_in_window(state, x, 1))
+ {
+ mask = inWin1Mask;
+ }
+ }
+
+ if(inWindow0)
+ {
+ if(is_in_window(state, x, 0))
+ {
+ mask = inWin0Mask;
+ }
+ }
+
+ if((mask & 0x04) != 0 && (line2[x] < color))
+ {
+ color = line2[x];
+ top = 0x04;
+ }
+
+ if((mask & 0x08) != 0 && (UINT8)(line3[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = line3[x];
+ top = 0x08;
+ }
+
+ if((mask & 0x10) != 0 && (UINT8)(lineOBJ[x] >> 24) < (UINT8)(color >> 24))
+ {
+ color = lineOBJ[x];
+ top = 0x10;
+ }
+
+ if((mask & 0x20) != 0)
+ {
+ if((color & 0x00010000) == 0)
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_NONE:
+ break;
+ case BLDCNT_SFX_ALPHA:
+ {
+ if(top & state->m_BLDCNT)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+ if((mask & 0x04) != 0 && (line2[x] < back))
+ {
+ if(top != 0x04)
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+ }
+
+ if((mask & 0x08) != 0 && ((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x08)
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+ }
+
+ if((mask & 0x10) != 0 && ((UINT8)(lineOBJ[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ if(top != 0x10)
+ {
+ back = lineOBJ[x];
+ top2 = 0x10;
+ }
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ }
+ break;
+ }
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ else
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((mask & 0x04) != 0 && (line2[x] < back))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if((mask & 0x08) != 0 && ((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ }
+ else if(color & 0x00010000)
+ {
+ UINT32 back = backdrop;
+ UINT8 top2 = 0x20;
+
+ if((mask & 0x04) != 0 && (line2[x] < back ))
+ {
+ back = line2[x];
+ top2 = 0x04;
+ }
+
+ if((mask & 0x08) != 0 && ((UINT8)(line3[x] >> 24) < (UINT8)(back >> 24)))
+ {
+ back = line3[x];
+ top2 = 0x08;
+ }
+
+ if(top2 & (state->m_BLDCNT >> BLDCNT_TP2_SHIFT))
+ {
+ color = alpha_blend_pixel(color, back, coeff[state->m_BLDALPHA & 0x1f], coeff[(state->m_BLDALPHA >> 8) & 0x1f]);
+ }
+ else
+ {
+ switch(state->m_BLDCNT & BLDCNT_SFX)
+ {
+ case BLDCNT_SFX_LIGHTEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = increase_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ case BLDCNT_SFX_DARKEN:
+ if(top & state->m_BLDCNT)
+ {
+ color = decrease_brightness(color, coeff[state->m_BLDY & 0x1f]);
+ }
+ break;
+ }
+ }
+ }
+ lineMix[x] = color;
+ }
+ state->m_gfxBG2Changed = 0;
+ state->m_gfxBG3Changed = 0;
+}
diff --git a/src/mess/video/gf4500.c b/src/mess/video/gf4500.c
new file mode 100644
index 00000000000..e85f4b7fc5d
--- /dev/null
+++ b/src/mess/video/gf4500.c
@@ -0,0 +1,172 @@
+/*
+
+ NVIDIA GoForce 4500
+
+ (c) 2010 Tim Schuerewegen
+
+*/
+
+#include "emu.h"
+
+#define VERBOSE_LEVEL ( 0 )
+
+INLINE void ATTR_PRINTF(3,4) verboselog( running_machine &machine, int n_level, const char *s_fmt, ...)
+{
+ if (VERBOSE_LEVEL >= n_level)
+ {
+ va_list v;
+ char buf[32768];
+ va_start( v, s_fmt);
+ vsprintf( buf, s_fmt, v);
+ va_end( v);
+ logerror( "%s: %s", machine.describe_context( ), buf);
+ }
+}
+
+#define BIT(x,n) (((x)>>(n))&1)
+#define BITS(x,m,n) (((x)>>(n))&(((UINT32)1<<((m)-(n)+1))-1))
+
+#define GF4500_FRAMEBUF_OFFSET 0x20000
+
+static struct {
+ UINT32 *data;
+ int screen_x;
+ int screen_y;
+ int screen_x_max;
+ int screen_y_max;
+ int screen_x_min;
+ int screen_y_min;
+ bitmap_rgb32 bitmap;
+} gf4500;
+
+static void gf4500_init( running_machine &machine)
+{
+ gf4500.data = auto_alloc_array( machine, UINT32, 0x140000 / 4);
+ gf4500.screen_x = gf4500.screen_y = 0;
+ gf4500.screen_x_max = gf4500.screen_y_max = gf4500.screen_x_min = gf4500.screen_y_min = 0;
+ machine.primary_screen->register_screen_bitmap(gf4500.bitmap);
+}
+
+static void gf4500_vram_write16( UINT16 data)
+{
+ if ((gf4500.screen_x < gf4500.screen_x_max) && (gf4500.screen_y < gf4500.screen_y_max))
+ {
+ UINT16 *vram = (UINT16 *)((UINT8 *)gf4500.data + GF4500_FRAMEBUF_OFFSET + (((gf4500.screen_y_min + gf4500.screen_y) * (320 + 1)) + (gf4500.screen_x_min + gf4500.screen_x)) * 2);
+ *vram = data;
+ gf4500.screen_x++;
+ }
+}
+
+static rgb_t gf4500_get_color_16( UINT16 data)
+{
+ UINT8 r, g, b;
+ r = BITS( data, 15, 11) << 3;
+ g = BITS( data, 10, 5) << 2;
+ b = BITS( data, 4, 0) << 3;
+ return MAKE_RGB( r, g, b);
+}
+
+static void gf4500_render_screen( running_machine &machine, bitmap_rgb32 &bitmap)
+{
+ UINT16 *vram = (UINT16 *)(gf4500.data + GF4500_FRAMEBUF_OFFSET / 4);
+ int x, y;
+ for (y = 0; y < 240; y++)
+ {
+ UINT32 *scanline = &bitmap.pix32(y);
+ for (x = 0; x < 320; x++)
+ {
+ *scanline++ = gf4500_get_color_16( *vram++);
+ }
+ vram += 1;
+ }
+}
+
+READ32_HANDLER( gf4500_r )
+{
+ UINT32 data = gf4500.data[offset];
+ switch (offset)
+ {
+ case 0x4C / 4 :
+ {
+ data = 0x00145000;
+ }
+ break;
+ }
+ if ((offset < (GF4500_FRAMEBUF_OFFSET / 4)) || (offset >= ((GF4500_FRAMEBUF_OFFSET + (321 * 240 * 2)) / 4)))
+ {
+ verboselog( space->machine(), 9, "(GFO) %08X -> %08X\n", 0x34000000 + (offset << 2), data);
+ }
+ return data;
+}
+
+WRITE32_HANDLER( gf4500_w )
+{
+ COMBINE_DATA(&gf4500.data[offset]);
+ if ((offset < (GF4500_FRAMEBUF_OFFSET / 4)) || (offset >= ((GF4500_FRAMEBUF_OFFSET + (321 * 240 * 2)) / 4)))
+ {
+ verboselog( space->machine(), 9, "(GFO) %08X <- %08X\n", 0x34000000 + (offset << 2), data);
+ }
+ switch (offset)
+ {
+ case 0x300 / 4 :
+ {
+ gf4500.screen_x = gf4500.screen_y = 0;
+ }
+ break;
+ case 0x304 / 4 :
+ {
+ gf4500.screen_x_max = (data >> 0) & 0xFFFF;
+ gf4500.screen_y_max = (data >> 16) & 0xFFFF;
+ if (gf4500.screen_x_max & 1) gf4500.screen_x_min++;
+ //if (screen_y_max & 1) screen_y_min++;
+ }
+ break;
+ case 0x308 / 4 :
+ {
+ gf4500.screen_x_min = (data >> 0) & 0xFFFF;
+ gf4500.screen_y_min = (data >> 16) & 0xFFFF;
+ if (gf4500.screen_x_min & 1) gf4500.screen_x_min--;
+ //if (screen_y_min & 1) screen_y_min--;
+ }
+ break;
+ }
+ if ((offset >= (0x200 / 4)) && (offset < (0x280 / 4)))
+ {
+
+// 'maincpu' (02996998): (GFO) 34000304 <- 00F00140
+// 'maincpu' (029969A8): (GFO) 34000308 <- 00000000
+// 'maincpu' (029969B4): (GFO) 34000324 <- 00000000
+// 'maincpu' (029969C4): (GFO) 34000328 <- 40000282
+// 'maincpu' (029969D4): (GFO) 34000300 <- 001022CC
+//
+// 'maincpu' (01DCC55C): (GFO) 34000024 -> 00000000
+// 'maincpu' (02996A24): (GFO) 34000200 <- AE9FAE9F
+//
+// 'maincpu' (02996A24): (GFO) 3400027C <- AE9FAE9F
+//
+// 'maincpu' (01DCC55C): (GFO) 34000024 -> 00000000
+// 'maincpu' (02996A24): (GFO) 34000200 <- AE9FAE9F
+// ...
+// 'maincpu' (02996A24): (GFO) 3400027C <- AE9FAE9F
+
+ gf4500_vram_write16( (data >> 0) & 0xFFFF);
+ gf4500_vram_write16( (data >> 16) & 0xFFFF);
+ if (gf4500.screen_x >= gf4500.screen_x_max)
+ {
+ gf4500.screen_x = 0;
+ gf4500.screen_y++;
+ }
+ }
+}
+
+VIDEO_START( gf4500 )
+{
+ gf4500_init( machine);
+}
+
+SCREEN_UPDATE_RGB32( gf4500 )
+{
+ gf4500_render_screen( screen.machine(), gf4500.bitmap);
+ copybitmap(bitmap, gf4500.bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
diff --git a/src/mess/video/gf4500.h b/src/mess/video/gf4500.h
new file mode 100644
index 00000000000..126161696f0
--- /dev/null
+++ b/src/mess/video/gf4500.h
@@ -0,0 +1,18 @@
+/*
+
+ NVIDIA GoForce 4500
+
+ (c) 2010 Tim Schuerewegen
+
+*/
+
+#ifndef __GF4500_H__
+#define __GF4500_H__
+
+READ32_HANDLER( gf4500_r );
+WRITE32_HANDLER( gf4500_w );
+
+VIDEO_START( gf4500 );
+SCREEN_UPDATE_RGB32( gf4500 );
+
+#endif /* __GF4500_H__ */
diff --git a/src/mess/video/gime.c b/src/mess/video/gime.c
new file mode 100644
index 00000000000..99b0f0048c7
--- /dev/null
+++ b/src/mess/video/gime.c
@@ -0,0 +1,2044 @@
+/*********************************************************************
+
+ gime.c
+
+ Implementation of CoCo GIME (Graphics Interrupt Memory Enhancement)
+ video chip.
+
+ Mid frame raster effects (source John Kowalski)
+
+ Here are the things that get changed mid-frame:
+
+ - Palette registers ($FFB0-$FFBF)
+ - Horizontal resolution (switches between 256 and 320 pixels, $FF99)
+ - Horizontal scroll position (bits 0-6 $FF9F)
+ - Horizontal virtual screen (bit 7 $FF9F)
+ - Pixel height (bits 0-2 $FF98)
+ - Border color ($FF9A)
+
+ On the positive side, you don't have to worry about registers
+ $FF9D/$FF9E being changed mid-frame. Even if they are changed
+ mid-frame, they have no effect on the displayed image. The video
+ address only gets latched at the top of the frame.
+
+
+ TIMING
+
+ We divide a single frame into five regions
+
+ Region Scanlines (on 192) Field Sync (before right border)
+ ------ ------------------ --------------------------------
+ Top Border 25 1
+ Body 192 1
+ Bottom Border 26 1
+ Vertical Retrace 6 0
+ Vertical Blanking 13 (or 13.5) 1
+
+ Horizontal sync appears to be low only during retrace/blanking but
+ field sync switches as soon as the last body pixel is displayed
+
+ Note that the GIME trailing edges field sync after the bottom
+ border; this is different than the MC6847
+
+**********************************************************************
+
+ SOFTWARE FOR TIMING TESTING
+
+ Various CoCo 3 programs can "stress test" timing in various ways
+
+ COLOR3: This program was in Rainbow January 1987. It will synchronize
+ with field sync by polling bit 7 of $FF03 (PIA0) (specifically, it polls
+ until the rising edge of writes to PIA0 CB1). This causes the loop to
+ be broken out at the top of vblank. COLOR3 also synchronizes on
+ horizontal sync through PIA0; it counts 70 hsyncs to get to a point 32
+ scanlines into the body.
+
+ DEMO: This SockMaster demo has a main loop that adjusts GIME registers
+ and shuffles some graphics bytes. From a timing perspective, the
+ critical piece is a SYNC with PIA field sync (specifically, it SYNCs
+ with the trailing edge of writes to PIA0 CB1). DEMO does not attempt
+ to synchronize on horizontal sync; it relies on CPU timing.
+
+ MOON: SockMaster demo. Uses GIME interrupts; FIRQ gets TMR interrupts
+ and IRQ gets VBORD interrupts. Since it does not use the PIA field
+ sync, it can be used to demonstrate how the GIME's VBORD interrupt
+ is distinct.
+
+ BOINK: SockMaster demo. Like DEMO, it SYNCs on the trailing edge
+ of PIA field sync. Also uses non standard $FF99 LPF mode. If
+ BOINK "wobbles vertically", it suggests that the main loop is not
+ executing within a single field sync. BOINK also makes extensive
+ use of $FF9F scrolling with bit 7 cleared.
+
+ CRYSTAL CITY: Jeremy Spiller game. The intro uses an attribute-less
+ GIME text mode
+
+**********************************************************************/
+
+
+#include "emu.h"
+#include "video/gime.h"
+#include "machine/6883sam.h"
+#include "machine/cococart.h"
+#include "machine/ram.h"
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define USE_HORIZONTAL_CLIP false
+#define GIME_TYPE_1987 0
+#define NO_ATTRIBUTE 0x80
+
+#define LOG_INT_MASKING 0
+#define LOG_GIME 0
+#define LOG_TIMER 0
+
+
+
+//**************************************************************************
+// DEVICE SETUP
+//**************************************************************************
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+gime_base_device::gime_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata)
+ : mc6847_friend_device(mconfig, type, name, tag, owner, clock, fontdata, true, 263, 25+192+26+3)
+{
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void gime_base_device::device_start(void)
+{
+ /* get the config */
+ const gime_interface *config = (const gime_interface *) static_config();
+ assert(config);
+
+ /* find the RAM device - make sure that it is started */
+ m_ram = machine().device<ram_device>(config->m_ram_tag);
+ if (!m_ram->started())
+ throw device_missing_dependencies();
+
+ /* find the CART device - make sure that it is started */
+ m_cart_device = machine().device<cococart_slot_device>(config->m_ext_tag);
+ if (!m_cart_device->started())
+ throw device_missing_dependencies();
+
+ /* find the CPU device - make sure that it is started */
+ m_cpu = machine().device<cpu_device>(config->m_maincpu_tag);
+ if (!m_cpu->started())
+ throw device_missing_dependencies();
+
+ /* inherited device_start - need to do this after checking dependencies */
+ super::device_start();
+
+ /* initialize variables */
+ memset(m_scanlines, 0, sizeof(m_scanlines));
+ m_interrupt_value = 0x00;
+ m_irq = 0x00;
+ m_firq = 0x00;
+
+ /* allocate timer */
+ m_gime_clock_timer = timer_alloc(TIMER_GIME_CLOCK);
+
+ /* resolve callbacks */
+ m_res_out_hsync_func.resolve(config->m_out_hsync_func, *this);
+ m_res_out_fsync_func.resolve(config->m_out_fsync_func, *this);
+ m_res_out_irq_func.resolve(config->m_out_irq_func, *this);
+ m_res_out_firq_func.resolve(config->m_out_firq_func, *this);
+ m_res_in_floating_bus_func.resolve(config->m_in_floating_bus_func, *this);
+
+ /* set up ROM/RAM pointers */
+ m_rom = machine().root_device().memregion(config->m_maincpu_tag)->base();
+ m_cart_rom = m_cart_device->get_cart_base();
+
+ /* populate palettes */
+ for (int color = 0; color < 64; color++)
+ {
+ m_composite_palette[color] = get_composite_color(color);
+ m_composite_bw_palette[color] = black_and_white(m_composite_palette[color]);
+ m_rgb_palette[color] = get_rgb_color(color);
+ }
+
+ /* set up save states */
+ save_pointer(NAME(m_gime_registers), ARRAY_LENGTH(m_gime_registers));
+ save_pointer(NAME(m_mmu), ARRAY_LENGTH(m_mmu));
+ save_item(NAME(m_sam_state));
+ save_item(NAME(m_ff22_value));
+ save_item(NAME(m_interrupt_value));
+ save_item(NAME(m_irq));
+ save_item(NAME(m_firq));
+ save_item(NAME(m_timer_value));
+ save_item(NAME(m_is_blinking));
+}
+
+
+
+//-------------------------------------------------
+// get_composite_color
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE gime_base_device::pixel_t gime_base_device::get_composite_color(int color)
+{
+ /* CMP colors
+ *
+ * These colors are of the format IICCCC, where II is the intensity and
+ * CCCC is the base color. There is some weirdness because intensity
+ * is often different for each base color.
+ *
+ * The code below is based on an algorithm specified in the following
+ * CoCo BASIC program was used to approximate composite colors.
+ * (Program by SockMaster):
+ *
+ * 10 POKE65497,0:DIMR(63),G(63),B(63):WIDTH80:PALETTE0,0:PALETTE8,54:CLS1
+ * 20 SAT=92:CON=70:BRI=-50:L(0)=0:L(1)=47:L(2)=120:L(3)=255
+ * 30 W=.4195456981879*1.01:A=W*9.2:S=A+W*5:D=S+W*5:P=0:FORH=0TO3:P=P+1
+ * 40 BRI=BRI+CON:FORG=1TO15:R(P)=COS(A)*SAT+BRI
+ * 50 G(P)=(COS(S)*SAT)*1+BRI:B(P)=(COS(D)*SAT)*1+BRI:P=P+1
+ * 55 A=A+W:S=S+W:D=D+W:NEXT:R(P-16)=L(H):G(P-16)=L(H):B(P-16)=L(H)
+ * 60 NEXT:R(63)=R(48):G(63)=G(48):B(63)=B(48)
+ * 70 FORH=0TO63STEP1:R=INT(R(H)):G=INT(G(H)):B=INT(B(H)):IFR<0THENR=0
+ * 80 IFG<0THENG=0
+ * 90 IFB<0THENB=0
+ * 91 IFR>255THENR=255
+ * 92 IFG>255THENG=255
+ * 93 IFB>255THENB=255
+ * 100 PRINTRIGHT$(STR$(H),2);" $";:R=R+256:G=G+256:B=B+256
+ * 110 PRINTRIGHT$(HEX$(R),2);",$";RIGHT$(HEX$(G),2);",$";RIGHT$(HEX$(B),2)
+ * 115 IF(H AND15)=15 THENIFINKEY$=""THEN115ELSEPRINT
+ * 120 NEXT
+ *
+ * At one point, we used a different SockMaster program, but the colors
+ * produced were too dark for people's taste
+ *
+ * 10 POKE65497,0:DIMR(63),G(63),B(63):WIDTH80:PALETTE0,0:PALETTE8,54:CLS1
+ * 20 SAT=92:CON=53:BRI=-16:L(0)=0:L(1)=47:L(2)=120:L(3)=255
+ * 30 W=.4195456981879*1.01:A=W*9.2:S=A+W*5:D=S+W*5:P=0:FORH=0TO3:P=P+1
+ * 40 BRI=BRI+CON:FORG=1TO15:R(P)=COS(A)*SAT+BRI
+ * 50 G(P)=(COS(S)*SAT)*.50+BRI:B(P)=(COS(D)*SAT)*1.9+BRI:P=P+1
+ * 55 A=A+W:S=S+W:D=D+W:NEXT:R(P-16)=L(H):G(P-16)=L(H):B(P-16)=L(H)
+ * 60 NEXT:R(63)=R(48):G(63)=G(48):B(63)=B(48)
+ * 70 FORH=0TO63STEP1:R=INT(R(H)):G=INT(G(H)):B=INT(B(H)):IFR<0THENR=0
+ * 80 IFG<0THENG=0
+ * 90 IFB<0THENB=0
+ * 91 IFR>255THENR=255
+ * 92 IFG>255THENG=255
+ * 93 IFB>255THENB=255
+ * 100 PRINTRIGHT$(STR$(H),2);" $";:R=R+256:G=G+256:B=B+256
+ * 110 PRINTRIGHT$(HEX$(R),2);",$";RIGHT$(HEX$(G),2);",$";RIGHT$(HEX$(B),2)
+ * 115 IF(H AND15)=15 THENIFINKEY$=""THEN115ELSEPRINT
+ * 120 NEXT
+ */
+
+ double saturation, brightness, contrast;
+ int offset;
+ double w;
+ int r, g, b;
+
+ switch(color)
+ {
+ case 0:
+ r = g = b = 0;
+ break;
+
+ case 16:
+ r = g = b = 47;
+ break;
+
+ case 32:
+ r = g = b = 120;
+ break;
+
+ case 48:
+ case 63:
+ r = g = b = 255;
+ break;
+
+ default:
+ w = .4195456981879*1.01;
+ contrast = 70;
+ saturation = 92;
+ brightness = -50;
+ brightness += ((color / 16) + 1) * contrast;
+ offset = (color % 16) - 1 + (color / 16)*15;
+ r = cos(w*(offset + 9.2)) * saturation + brightness;
+ g = cos(w*(offset + 14.2)) * saturation + brightness;
+ b = cos(w*(offset + 19.2)) * saturation + brightness;
+
+ if (r < 0)
+ r = 0;
+ else if (r > 255)
+ r = 255;
+
+ if (g < 0)
+ g = 0;
+ else if (g > 255)
+ g = 255;
+
+ if (b < 0)
+ b = 0;
+ else if (b > 255)
+ b = 255;
+ break;
+ }
+ return (pixel_t) ((r << 16) | (g << 8) | (b << 0));
+}
+
+
+
+//-------------------------------------------------
+// get_rgb_color
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE gime_base_device::pixel_t gime_base_device::get_rgb_color(int color)
+{
+ return (((color >> 4) & 2) | ((color >> 2) & 1)) * 0x550000
+ | (((color >> 3) & 2) | ((color >> 1) & 1)) * 0x005500
+ | (((color >> 2) & 2) | ((color >> 0) & 1)) * 0x000055;
+}
+
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void gime_base_device::device_reset(void)
+{
+ /* Tepolt verifies that the GIME registers are all cleared on initialization */
+ memset(m_gime_registers, 0, sizeof(m_gime_registers));
+
+ /* initialize MMU */
+ for (int i = 0; i < 8; i++)
+ m_mmu[i] = m_mmu[i + 8] = 56 + i;
+
+ /* initialize palette */
+ memset(m_palette_rotated, 0, sizeof(m_palette_rotated));
+ m_palette_rotated_position = 0;
+ m_palette_rotated_position_used = false;
+
+ /* clear SAM state */
+ m_sam_state = 0x0000;
+
+ /* clear interrupts */
+ m_interrupt_value = 0x00;
+ m_irq = 0x00;
+ m_firq = 0x00;
+ m_is_blinking = false;
+
+ update_memory();
+ reset_timer();
+}
+
+
+
+//-------------------------------------------------
+// device_pre_save - device-specific pre save
+//-------------------------------------------------
+
+void gime_base_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_GIME_CLOCK:
+ timer_elapsed();
+ break;
+
+ default:
+ super::device_timer(timer, id, param, ptr);
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post load
+//-------------------------------------------------
+
+void gime_base_device::device_post_load()
+{
+ super::device_post_load();
+ update_memory();
+}
+
+
+
+//-------------------------------------------------
+// device_input_ports
+//-------------------------------------------------
+
+ioport_constructor gime_base_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(mc6847_artifacting);
+}
+
+
+
+//**************************************************************************
+// TIMER
+//
+// The CoCo 3 had a timer that had would activate when first written to, and
+// would decrement over and over again until zero was reached, and at that
+// point, would flag an interrupt. At this point, the timer starts back up
+// again.
+//
+// I am deducing that the timer interrupt line was asserted if the timer was
+// zero and unasserted if the timer was non-zero. Since we never truly track
+// the timer, we just use timer callback (coco3_timer_callback() asserts the
+// line)
+//
+// Most CoCo 3 docs, including the specs that Tandy released, say that the
+// high speed timer is 70ns (half of the speed of the main clock crystal).
+// However, it seems that this is in error, and the GIME timer is really a
+// 280ns timer (one eighth the speed of the main clock crystal. Gault's
+// FAQ agrees with this
+//
+//**************************************************************************
+
+//-------------------------------------------------
+// timer_type
+//-------------------------------------------------
+
+gime_base_device::timer_type_t gime_base_device::timer_type(void)
+{
+ // wraps the GIME register access and returns an enumeration
+ return (m_gime_registers[0x01] & 0x20) ? GIME_TIMER_CLOCK : GIME_TIMER_HBORD;
+}
+
+
+
+//-------------------------------------------------
+// timer_type_string
+//-------------------------------------------------
+
+const char *gime_base_device::timer_type_string(void)
+{
+ const char *result;
+ switch(timer_type())
+ {
+ case GIME_TIMER_CLOCK:
+ result = "CLOCK";
+ break;
+ case GIME_TIMER_HBORD:
+ result = "HBORD";
+ break;
+ default:
+ fatalerror("Should not get here");
+ break;
+ }
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// timer_elapsed
+//-------------------------------------------------
+
+void gime_base_device::timer_elapsed(void)
+{
+ /* reset the timer; give her another run! */
+ reset_timer();
+
+ /* change the blinking value - note that we don't have to use update_value() */
+ m_is_blinking = !m_is_blinking;
+
+ /* twiddle the timer interrupt */
+ set_interrupt_value(INTERRUPT_TMR, true);
+ set_interrupt_value(INTERRUPT_TMR, false);
+}
+
+
+
+//-------------------------------------------------
+// reset_timer
+//-------------------------------------------------
+
+void gime_base_device::reset_timer(void)
+{
+ /* value is from 0-4095 */
+ m_timer_value = ((m_gime_registers[0x04] & 0x0F) * 0x100) | m_gime_registers[0x05];
+
+ /* depending on the GIME type, cannonicalize the value */
+ if (m_timer_value > 0)
+ {
+ if (GIME_TYPE_1987)
+ m_timer_value += 1; /* the 1987 GIME reset to the value plus one */
+ else
+ m_timer_value += 2; /* the 1986 GIME reset to the value plus two */
+ }
+
+ attotime duration;
+ if ((timer_type() == GIME_TIMER_CLOCK) && (m_timer_value > 0))
+ {
+ /* we're starting a countdown on the GIME clock timer */
+ attotime current_time = machine().time();
+ UINT64 current_tick = current_time.as_ticks(m_clock);
+ duration = attotime::from_ticks(current_tick + m_timer_value, m_clock) - current_time;
+ }
+ else
+ {
+ /* either the timer is off, or were not using the GIME clock timer */
+ duration = attotime::never;
+ }
+ m_gime_clock_timer->adjust(duration);
+
+ if (LOG_TIMER)
+ logerror("%s: reset_timer(): timer_type=%s value=%d\n", describe_context(), timer_type_string(), m_timer_value);
+}
+
+
+
+//**************************************************************************
+// MEMORY AND REGISTERS
+//**************************************************************************
+
+//-------------------------------------------------
+// update_memory
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void gime_base_device::update_memory(void)
+{
+ for (int bank = 0; bank <= 8; bank++)
+ {
+ update_memory(bank);
+ }
+}
+
+
+
+//-------------------------------------------------
+// update_memory
+//-------------------------------------------------
+
+void gime_base_device::update_memory(int bank)
+{
+ static const char *rbanks[] = { "rbank0", "rbank1", "rbank2", "rbank3", "rbank4", "rbank5", "rbank6", "rbank7", "rbank8" };
+ static const char *wbanks[] = { "wbank0", "wbank1", "wbank2", "wbank3", "wbank4", "wbank5", "wbank6", "wbank7", "wbank8" };
+
+ /* look up the bank tags */
+ assert((bank >= 0) && (bank < ARRAY_LENGTH(rbanks)) && (bank < ARRAY_LENGTH(wbanks)));
+ const char *rbank = rbanks[bank];
+ const char *wbank = wbanks[bank];
+
+ /* bank 8 is really $FE00-$FEFF; it is weird so adjust for it */
+ offs_t offset;
+ bool force_ram;
+ bool enable_mmu = (m_gime_registers[0] & 0x40) ? true : false;
+ if (bank == 8)
+ {
+ bank = 7;
+ offset = 0x1E00;
+ force_ram = true;
+ enable_mmu = enable_mmu && !(m_gime_registers[0] & 0x08);
+ }
+ else
+ {
+ offset = 0x0000;
+ force_ram = false;
+ }
+
+ /* is the MMU enabled at $FF90? */
+ int block;
+ if (enable_mmu)
+ {
+ /* check TR register at $FF91 */
+ bank += (m_gime_registers[1] & 0x01) ? 8 : 0;
+
+ /* perform the MMU lookup */
+ block = m_mmu[bank];
+
+ /* also check $FF9B - relevant for the 2-8 MB upgrade */
+ block |= ((UINT32) ((m_gime_registers[11] >> 4) & 0x03)) << 8;
+ }
+ else
+ {
+ /* the MMU is not enabled */
+ block = bank + 56;
+ }
+
+ /* are we actually in ROM? */
+ UINT8 *memory;
+ bool is_read_only;
+ if (((block & 0x3F) >= 0x3C) && !(m_sam_state & SAM_STATE_TY) && !force_ram)
+ {
+ /* we're in ROM */
+ static const UINT8 rom_map[4][4] =
+ {
+ { 0, 1, 6, 7 },
+ { 0, 1, 6, 7 },
+ { 0, 1, 2, 3 },
+ { 4, 5, 6, 7 }
+ };
+
+ /* look up the block in the ROM map */
+ block = rom_map[m_gime_registers[0] & 3][(block & 0x3F) - 0x3C];
+
+ /* are we in onboard ROM or cart ROM? */
+ UINT8 *rom_ptr = (block & 4) ? m_cart_rom : m_rom;
+ /* TODO: make this unmapped */
+ if (rom_ptr==NULL) rom_ptr = m_rom;
+ /* perform the look up */
+ memory = &rom_ptr[(block & 3) * 0x2000];
+ is_read_only = true;
+ }
+ else
+ {
+ /* we're in RAM */
+ memory = memory_pointer(block * 0x2000);
+ is_read_only = false;
+ }
+
+ /* compensate for offset */
+ memory += offset;
+
+ /* set the banks */
+ machine().root_device().membank(rbank)->set_base(memory);
+ machine().root_device().membank(wbank)->set_base(is_read_only ? m_dummy_bank : memory);
+}
+
+
+
+//-------------------------------------------------
+// memory_pointer
+//-------------------------------------------------
+
+UINT8 *gime_base_device::memory_pointer(UINT32 address)
+{
+ return &m_ram->pointer()[address % m_ram->size()];
+}
+
+
+
+//-------------------------------------------------
+// update_cart_rom
+//-------------------------------------------------
+
+void gime_base_device::update_cart_rom(void)
+{
+ m_cart_rom = m_cart_device->get_cart_base();
+ update_memory();
+}
+
+
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+UINT8 gime_base_device::read(offs_t offset)
+{
+ UINT8 data = 0x00;
+
+ switch(offset & 0xF0)
+ {
+ case 0x00:
+ data = read_gime_register(offset);
+ break;
+
+ case 0x10:
+ data = read_mmu_register(offset);
+ break;
+
+ case 0x20:
+ data = read_palette_register(offset);
+ break;
+ }
+
+ return data;
+}
+
+
+
+//-------------------------------------------------
+// read_gime_register
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE UINT8 gime_base_device::read_gime_register(offs_t offset)
+{
+ offset &= 0x0F;
+
+ UINT8 result;
+ switch(offset)
+ {
+ case 2: /* Read pending IRQs */
+ result = m_irq;
+ if (result != 0x00)
+ {
+ m_irq = 0x00;
+ recalculate_irq();
+ }
+ break;
+
+ case 3: /* Read pending FIRQs */
+ result = m_firq;
+ if (result != 0x00)
+ {
+ m_firq = 0x00;
+ recalculate_firq();
+ }
+ break;
+
+ case 4: /* Timer MSB/LSB; these arn't readable */
+ case 5:
+ /* JK tells me that these values are indeterminate; and $7E appears
+ * to be the value most commonly returned
+ */
+ result = 0x7E;
+ break;
+
+ default:
+ result = m_gime_registers[offset];
+ break;
+ }
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// read_mmu_register
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE UINT8 gime_base_device::read_mmu_register(offs_t offset)
+{
+ return (m_mmu[offset & 0x0F] & 0x3F);
+}
+
+
+
+//-------------------------------------------------
+// read_palette_register
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE UINT8 gime_base_device::read_palette_register(offs_t offset)
+{
+ // Bits 7/6 are floating, and behave oddly. On a real CoCo 3
+ //
+ // POKE&HFFB1,255:PRINTPEEK(&HFFB1) returns 127.
+ // POKE&HFFB1,0:PRINTPEEK(&HFFB1) returns 64
+ //
+ // This is because of the floating bus
+ return m_palette_rotated[m_palette_rotated_position][offset & 0x0F]
+ | (read_floating_bus() & 0xC0);
+}
+
+
+
+//-------------------------------------------------
+// read_floating_bus
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE UINT8 gime_base_device::read_floating_bus(void)
+{
+ return m_res_in_floating_bus_func.isnull()
+ ? 0
+ : m_res_in_floating_bus_func(0);
+}
+
+
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void gime_base_device::write(offs_t offset, UINT8 data)
+{
+ switch(offset & 0xF0)
+ {
+ case 0x00:
+ write_gime_register(offset & 0x0F, data);
+ break;
+
+ case 0x10:
+ write_mmu_register(offset & 0x0F, data);
+ break;
+
+ case 0x20:
+ write_palette_register(offset & 0x0F, data & 0x3F);
+ break;
+
+ case 0x30:
+ case 0x40:
+ write_sam_register(offset - 0x30);
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// write_gime_register
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void gime_base_device::write_gime_register(offs_t offset, UINT8 data)
+{
+ // this is needed for writes to FF95
+ bool timer_was_off = (m_gime_registers[0x04] == 0x00) && (m_gime_registers[0x05] == 0x00);
+
+ // sanity check input
+ offset &= 0x0F;
+
+ // perform logging
+ if (LOG_GIME)
+ logerror("%s: CoCo3 GIME: $%04x <== $%02x\n", describe_context(), offset + 0xff90, data);
+
+ // make the change, and track the difference
+ UINT8 xorval = m_gime_registers[offset] ^ data;
+ m_gime_registers[offset] = data;
+
+ switch(offset)
+ {
+ case 0x00:
+ // $FF90 Initialization register 0
+ // Bit 7 COCO 1=CoCo compatible mode
+ // Bit 6 MMUEN 1=MMU enabled
+ // Bit 5 IEN 1 = GIME chip IRQ enabled
+ // Bit 4 FEN 1 = GIME chip FIRQ enabled
+ // Bit 3 MC3 1 = RAM at FEXX is constant
+ // Bit 2 MC2 1 = standard SCS (Spare Chip Select)
+ // Bit 1 MC1 ROM map control
+ // Bit 0 MC0 ROM map control
+ if (xorval & 0x4B)
+ update_memory();
+ break;
+
+ case 0x01:
+ // $FF91 Initialization register 1
+ // Bit 7 Unused
+ // Bit 6 Unused
+ // Bit 5 TINS Timer input select; 1 = 280 nsec, 0 = 63.5 usec
+ // Bit 4 Unused
+ // Bit 3 Unused
+ // Bit 2 Unused
+ // Bit 1 Unused
+ // Bit 0 TR Task register select
+ if (xorval & 0x01)
+ update_memory();
+
+ // I'm not sure about this one; as written this code will reset the timer
+ // with the _original_ value. This is probably not correct.
+ if (xorval & 0x20)
+ reset_timer();
+ break;
+
+ case 0x02:
+ // $FF92 Interrupt request enable register
+ // Bit 7 Unused
+ // Bit 6 Unused
+ // Bit 5 TMR Timer interrupt
+ // Bit 4 HBORD Horizontal border interrupt
+ // Bit 3 VBORD Vertical border interrupt
+ // ! Bit 2 EI2 Serial data interrupt
+ // Bit 1 EI1 Keyboard interrupt
+ // Bit 0 EI0 Cartridge interrupt
+ if (LOG_INT_MASKING)
+ {
+ logerror("%s: GIME IRQ: Interrupts { %s%s%s%s%s%s} enabled\n",
+ describe_context(),
+ (data & 0x20) ? "TMR " : "",
+ (data & 0x10) ? "HBORD " : "",
+ (data & 0x08) ? "VBORD " : "",
+ (data & 0x04) ? "EI2 " : "",
+ (data & 0x02) ? "EI1 " : "",
+ (data & 0x01) ? "EI0 " : "");
+ }
+ break;
+
+ case 0x03:
+ // $FF93 Fast interrupt request enable register
+ // Bit 7 Unused
+ // Bit 6 Unused
+ // Bit 5 TMR Timer interrupt
+ // Bit 4 HBORD Horizontal border interrupt
+ // Bit 3 VBORD Vertical border interrupt
+ // ! Bit 2 EI2 Serial data interrupt
+ // Bit 1 EI1 Keyboard interrupt
+ // Bit 0 EI0 Cartridge interrupt
+ if (LOG_INT_MASKING)
+ {
+ logerror("%s: GIME FIRQ: Interrupts { %s%s%s%s%s%s} enabled\n",
+ describe_context(),
+ (data & 0x20) ? "TMR " : "",
+ (data & 0x10) ? "HBORD " : "",
+ (data & 0x08) ? "VBORD " : "",
+ (data & 0x04) ? "EI2 " : "",
+ (data & 0x02) ? "EI1 " : "",
+ (data & 0x01) ? "EI0 " : "");
+ }
+ break;
+
+ case 0x04:
+ // $FF94 Timer register MSB
+ // Bits 4-7 Unused
+ // Bits 0-3 High order four bits of the timer
+ reset_timer();
+ break;
+
+ case 0x05:
+ // $FF95 Timer register LSB
+ // Bits 0-7 Low order eight bits of the timer
+ if (timer_was_off && (m_gime_registers[0x05] != 0x00))
+ {
+ // Writes to $FF95 do not cause the timer to reset, but MESS
+ // will invoke coco3_timer_reset() if $FF94/5 was previously
+ // $0000. The reason for this is because the timer is not
+ // actually off when $FF94/5 are loaded with $0000; rather it
+ // is continuously reloading the GIME's internal countdown
+ // register, even if it isn't causing interrupts to be raised.
+ //
+ // Failure to do this was the cause of bug #1065. Special
+ // thanks to John Kowalski for pointing me in the right
+ // direction
+ reset_timer();
+ }
+ break;
+
+ case 0x08:
+ // $FF98 Video Mode Register
+ // Bit 7 BP 0 = Text modes, 1 = Graphics modes
+ // Bit 6 Unused
+ // ! Bit 5 BPI Burst Phase Invert (Color Set)
+ // Bit 4 MOCH 1 = Monochrome on Composite
+ // ! Bit 3 H50 1 = 50 Hz power, 0 = 60 Hz power
+ // Bits 0-2 LPR Lines per row
+ break;
+
+ case 0x09:
+ // $FF99 Video Resolution Register
+ // Bit 7 Undefined
+ // Bits 5-6 LPF Lines per Field (Number of Rows)
+ // Bits 2-4 HRES Horizontal Resolution
+ // 000=16 bytes per row
+ // 001=20 bytes per row
+ // 010=32 bytes per row
+ // 011=40 bytes per row
+ // 100=64 bytes per row
+ // 101=80 bytes per row
+ // 110=128 bytes per row
+ // 111=160 bytes per row
+ // Bits 0-1 CRES Color Resolution
+ if (xorval & 0x60)
+ update_geometry();
+ break;
+
+ case 0x0A:
+ // $FF9A Border Register
+ // Bits 6,7 Unused
+ // Bits 0-5 BRDR Border color
+ break;
+
+ case 0x0C:
+ // $FF9C Vertical Scroll Register
+ // Bits 4-7 Reserved
+ // Bits 0-3 VSC Vertical Scroll bits
+ break;
+
+ case 0x0B:
+ // $FF9B Two/Eight Megabyte Upgrade register
+ //
+ // This variable is weird; it affects both the video position, but
+ // it also affects normal memory mapping. However, changing $FF9B
+ // alone won't affect the MMU; writes to $FFAx are required to "latch"
+ // in the $FF9B value.
+ //
+ // The reason that $FF9B is not mentioned in offical documentation
+ // is because it is only meaningful in CoCo 3's with the 2MB upgrade
+ break;
+
+ case 0x0D:
+ case 0x0E:
+ // $FF9B,$FF9D,$FF9E Vertical Offset Registers
+ //
+ // According to JK, if an odd value is placed in $FF9E on the 1986
+ // GIME, the GIME crashes
+ break;
+
+ case 0x0F:
+ // $FF9F Horizontal Offset Register
+ // Bit 7 HVEN Horizontal Virtual Enable
+ // Bits 0-6 X0-X6 Horizontal Offset Address
+ //
+ // Unline $FF9D-E, this value can be modified mid frame
+ //
+ // Note that the FF9F offset is shifted by one bit (e.g. - $FF9F=$03 will
+ // be a six byte offset). Also note that scanlines wrap at 256 byte boundaries
+ // without regard to bit 7.
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// write_mmu_register
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void gime_base_device::write_mmu_register(offs_t offset, UINT8 data)
+{
+ offset &= 0x0F;
+
+ // Check to see if the MMU register has changed. If we have more than 512k of RAM
+ // then we have to always update because this is the point at which the MMU makes
+ // decisions based off of $FF9B
+ if ((m_mmu[offset] != data) || (m_ram->size() > 512*1024))
+ {
+ m_mmu[offset] = data;
+ update_memory(offset & 0x07);
+ }
+}
+
+
+
+//-------------------------------------------------
+// write_palette_register
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void gime_base_device::write_palette_register(offs_t offset, UINT8 data)
+{
+ offset &= 0x0F;
+
+ /* has this entry changed? */
+ if (m_palette_rotated[m_palette_rotated_position][offset] != data)
+ {
+ /* do we need to rotate the palette? */
+ if (m_palette_rotated_position_used)
+ {
+ /* identify the new position */
+ UINT16 new_palette_rotated_position = (m_palette_rotated_position + 1) % ARRAY_LENGTH(m_palette_rotated);
+
+ /* copy the palette */
+ for (int i = 0; i < ARRAY_LENGTH(m_palette_rotated[0]); i++)
+ m_palette_rotated[new_palette_rotated_position][i] = m_palette_rotated[m_palette_rotated_position][i];
+
+ /* and advance */
+ m_palette_rotated_position = new_palette_rotated_position;
+ m_palette_rotated_position_used = false;
+ }
+
+ /* record the change */;
+ m_palette_rotated[m_palette_rotated_position][offset] = data;
+ }
+}
+
+
+
+//-------------------------------------------------
+// write_sam_register
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void gime_base_device::write_sam_register(offs_t offset)
+{
+ /* change the SAM state */
+ UINT16 xorval = alter_sam_state(offset);
+
+ /* $FFDE-F can trigger a memory update */
+ if (xorval & SAM_STATE_TY)
+ update_memory();
+
+ if (xorval & (SAM_STATE_R1|SAM_STATE_R0))
+ update_cpu_clock();
+}
+
+
+
+//-------------------------------------------------
+// interrupt_rising_edge
+//-------------------------------------------------
+
+void gime_base_device::interrupt_rising_edge(UINT8 interrupt)
+{
+ /* evaluate IRQ */
+ if ((m_gime_registers[0x00] & 0x20) && (m_gime_registers[0x02] & interrupt))
+ {
+ m_irq |= interrupt;
+ recalculate_irq();
+ }
+
+ /* evaluate FIRQ */
+ if ((m_gime_registers[0x00] & 0x10) && (m_gime_registers[0x03] & interrupt))
+ {
+ m_firq |= interrupt;
+ recalculate_firq();
+ }
+}
+
+
+
+//-------------------------------------------------
+// recalculate_irq
+//-------------------------------------------------
+
+void gime_base_device::recalculate_irq(void)
+{
+ if (!m_res_out_irq_func.isnull())
+ m_res_out_irq_func(irq_r());
+}
+
+
+
+//-------------------------------------------------
+// recalculate_firq
+//-------------------------------------------------
+
+void gime_base_device::recalculate_firq(void)
+{
+ if (!m_res_out_firq_func.isnull())
+ m_res_out_firq_func(firq_r());
+}
+
+
+
+//**************************************************************************
+// VIDEO STATE
+//**************************************************************************
+
+//-------------------------------------------------
+// get_video_base
+//
+// The purpose of the ff9d_mask and ff9e_mask is to mask out bits that are
+// ignored in lo-res mode. Specifically, $FF9D is masked with $E0, and
+// $FF9E is masked with $3F
+//
+// John Kowalski confirms this behavior
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE offs_t gime_base_device::get_video_base(void)
+{
+ offs_t result;
+ UINT8 ff9d_mask, ff9e_mask;
+
+ if (m_legacy_video)
+ {
+ /* legacy video gets the base address from the SAM addresses, and masks out GIME variables */
+ result = display_offset();
+ ff9d_mask = 0xE0;
+ ff9e_mask = 0x3F;
+ }
+ else
+ {
+ /* GIME video ignores the SAM addresses, relying on the GIME variables exclusively */
+ result = 0;
+ ff9d_mask = 0xFF;
+ ff9e_mask = 0xFF;
+ }
+
+ result += ((offs_t) (m_gime_registers[0x0E] & ff9e_mask) * 0x00008)
+ | ((offs_t) (m_gime_registers[0x0D] & ff9d_mask) * 0x00800)
+ | ((offs_t) (m_gime_registers[0x0B] & 0x0F) * 0x80000);
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// new_frame
+//-------------------------------------------------
+
+void gime_base_device::new_frame(void)
+{
+ /* call inherited function */
+ super::new_frame();
+
+ /* latch in legacy video value */
+ bool legacy_video_changed = update_value(&m_legacy_video, m_gime_registers[0] & 0x80 ? true : false);
+
+ /* latch in the video position */
+ m_video_position = get_video_base();
+ m_line_in_row = m_gime_registers[0x0C] & 0x0F;
+
+ /* update the geometry, as appropriate */
+ if (legacy_video_changed)
+ update_geometry();
+}
+
+
+
+//-------------------------------------------------
+// horizontal_sync_changed
+//-------------------------------------------------
+
+void gime_base_device::horizontal_sync_changed(bool line)
+{
+ set_interrupt_value(INTERRUPT_HBORD, line);
+
+ /* decrement timer if appropriate */
+ if ((timer_type() == GIME_TIMER_HBORD) && (m_timer_value > 0) && line)
+ {
+ if (--m_timer_value == 0)
+ timer_elapsed();
+ }
+
+}
+
+
+
+//-------------------------------------------------
+// enter_bottom_border
+//-------------------------------------------------
+
+void gime_base_device::enter_bottom_border(void)
+{
+ set_interrupt_value(INTERRUPT_VBORD, true);
+ set_interrupt_value(INTERRUPT_VBORD, false);
+}
+
+
+
+//-------------------------------------------------
+// update_border
+//-------------------------------------------------
+
+void gime_base_device::update_border(UINT16 physical_scanline)
+{
+ UINT8 border;
+ if (m_legacy_video)
+ {
+ /* legacy video */
+ switch(border_value(m_ff22_value, true))
+ {
+ case BORDER_COLOR_GREEN:
+ border = 0x12; /* green */
+ break;
+ case BORDER_COLOR_WHITE:
+ border = 0x3F; /* white */
+ break;
+ case BORDER_COLOR_BLACK:
+ border = 0x00; /* black */
+ break;
+ case BORDER_COLOR_ORANGE:
+ border = 0x26; /* orange */
+ break;
+ default:
+ fatalerror("Should not get here");
+ break;
+ }
+ }
+ else
+ {
+ /* get the border value from $FF9A */
+ border = m_gime_registers[0x0A] & 0x3F;
+ }
+ update_value(&m_scanlines[physical_scanline].m_border, border);
+}
+
+
+
+//-------------------------------------------------
+// record_border_scanline
+//-------------------------------------------------
+
+void gime_base_device::record_border_scanline(UINT16 physical_scanline)
+{
+ m_line_in_row = 0;
+ update_border(physical_scanline);
+ update_value(&m_scanlines[physical_scanline].m_line_in_row, (UINT8) ~0);
+}
+
+
+
+//-------------------------------------------------
+// get_lines_per_row
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE UINT16 gime_base_device::get_lines_per_row(void)
+{
+ UINT16 lines_per_row;
+ if (m_legacy_video)
+ {
+ switch(m_ff22_value & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0))
+ {
+ case 0:
+ case MODE_GM0:
+ case MODE_GM1:
+ case MODE_GM1|MODE_GM0:
+ case MODE_GM2:
+ case MODE_GM2|MODE_GM0:
+ case MODE_GM2|MODE_GM1:
+ case MODE_GM2|MODE_GM1|MODE_GM0:
+ lines_per_row = 12;
+ break;
+
+ case MODE_AG:
+ case MODE_AG|MODE_GM0:
+ case MODE_AG|MODE_GM1:
+ lines_per_row = 3;
+ break;
+
+ case MODE_AG|MODE_GM1|MODE_GM0:
+ case MODE_AG|MODE_GM2:
+ lines_per_row = 2;
+ break;
+
+ case MODE_AG|MODE_GM2|MODE_GM0:
+ case MODE_AG|MODE_GM2|MODE_GM1:
+ case MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0:
+ lines_per_row = 1;
+ break;
+
+ default:
+ fatalerror("Should not get here");
+ break;
+ }
+ }
+ else
+ {
+ switch(m_gime_registers[0x08] & 0x07)
+ {
+ case 0x00:
+ case 0x01:
+ lines_per_row = 1;
+ break;
+ case 0x02:
+ lines_per_row = 2;
+ break;
+ case 0x03:
+ lines_per_row = 8;
+ break;
+ case 0x04:
+ lines_per_row = 9;
+ break;
+ case 0x05:
+ lines_per_row = 10;
+ break;
+ case 0x06:
+ lines_per_row = 11;
+ break;
+ case 0x07:
+ lines_per_row = 0xFFFF;
+ break;
+ default:
+ fatalerror("Should not get here");
+ break;
+ }
+ }
+ return lines_per_row;
+}
+
+
+
+//-------------------------------------------------
+// record_scanline_res
+//-------------------------------------------------
+
+template<UINT8 xres, gime_base_device::get_data_func get_data, bool record_mode>
+ATTR_FORCE_INLINE UINT32 gime_base_device::record_scanline_res(int scanline)
+{
+ int column;
+ UINT32 base_offset = m_legacy_video ? 0 : (m_gime_registers[0x0F] & 0x7F) * 2;
+ UINT32 offset = 0;
+
+ /* main loop */
+ for (column = 0; column < xres; column++)
+ {
+ /* input data */
+ UINT8 data, mode;
+ offset += ((*this).*(get_data))(m_video_position + ((base_offset + offset) & 0xFF), &data, &mode);
+
+ /* and record the pertinent values */
+ if (record_mode)
+ update_value(&m_scanlines[scanline].m_mode[column], mode);
+ update_value(&m_scanlines[scanline].m_data[column], data);
+ update_value(&m_scanlines[scanline].m_palette[column], m_palette_rotated_position);
+ }
+
+ return offset;
+}
+
+
+
+//-------------------------------------------------
+// get_data_mc6847 - used for retrieving data/mode
+// in legacy video modes
+//-------------------------------------------------
+
+UINT32 gime_base_device::get_data_mc6847(UINT32 video_position, UINT8 *data, UINT8 *mode)
+{
+ *data = *memory_pointer(video_position);
+ *mode = (m_ff22_value & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0|MODE_CSS))
+ | ((*data & 0x80) == 0x80 ? MODE_AS : 0)
+ | ((*data & 0xC0) == 0x40 ? MODE_INV : 0);
+
+ // postprocess the mode to remove unnecessary flags
+ *mode = mc6847_friend_device::simplify_mode(*data, *mode);
+ return 1;
+}
+
+
+
+//-------------------------------------------------
+// get_data_without_attributes - used for
+// retrieving data/mode in GIME graphics or GIME
+// text modes without attributes
+//-------------------------------------------------
+
+UINT32 gime_base_device::get_data_without_attributes(UINT32 video_position, UINT8 *data, UINT8 *mode)
+{
+ *data = *memory_pointer(video_position);
+ *mode = NO_ATTRIBUTE;
+ return 1;
+}
+
+
+
+//-------------------------------------------------
+// get_data_with_attributes - used for retrieving
+// data/mode in GIME text modes with attributes
+//-------------------------------------------------
+
+UINT32 gime_base_device::get_data_with_attributes(UINT32 video_position, UINT8 *data, UINT8 *mode)
+{
+ *data = *memory_pointer(video_position + 0);
+ *mode = *memory_pointer(video_position + 1);
+
+ /* is the blink attribute specified? */
+ if (UNEXPECTED(*mode & 0x80))
+ {
+ /* if so - and we're blinking - then clear the character */
+ if (m_is_blinking)
+ {
+ *data = 0x20;
+ *mode &= ~0x40;
+ }
+
+ /* clear the blink bit */
+ *mode &= ~0x80;
+ }
+ return 2;
+}
+
+
+
+//-------------------------------------------------
+// record_body_scanline
+//-------------------------------------------------
+
+void gime_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline)
+{
+ /* update the border first */
+ update_border(physical_scanline);
+
+ /* set the line in row */
+ update_value(&m_scanlines[physical_scanline].m_line_in_row, m_line_in_row);
+
+ /* we're using this palette rotation */
+ m_palette_rotated_position_used = true;
+
+ UINT32 pitch = 0;
+ if (m_legacy_video)
+ {
+ /* legacy video */
+ update_value(&m_scanlines[physical_scanline].m_ff22_value, m_ff22_value);
+
+ switch(m_ff22_value & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0))
+ {
+ case MODE_AG:
+ case MODE_AG|MODE_GM0:
+ case MODE_AG|MODE_GM1|MODE_GM0:
+ case MODE_AG|MODE_GM2|MODE_GM0:
+ pitch = record_scanline_res<16, &gime_base_device::get_data_mc6847, true>(physical_scanline);
+ break;
+
+ case 0:
+ case MODE_GM0:
+ case MODE_GM1:
+ case MODE_GM1|MODE_GM0:
+ case MODE_GM2:
+ case MODE_GM2|MODE_GM0:
+ case MODE_GM2|MODE_GM1:
+ case MODE_GM2|MODE_GM1|MODE_GM0:
+ case MODE_AG|MODE_GM1:
+ case MODE_AG|MODE_GM2:
+ case MODE_AG|MODE_GM2|MODE_GM1:
+ case MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0:
+ pitch = record_scanline_res<32, &gime_base_device::get_data_mc6847, true>(physical_scanline);
+ break;
+
+ default:
+ /* should not get here */
+ fatalerror("Should not get here");
+ return;
+ }
+ }
+ else
+ {
+ /* CoCo 3 video */
+ update_value(&m_scanlines[physical_scanline].m_ff98_value, m_gime_registers[0x08]);
+ update_value(&m_scanlines[physical_scanline].m_ff99_value, m_gime_registers[0x09]);
+
+ /* is this graphics or text? */
+ if (m_gime_registers[0x08] & 0x80)
+ {
+ /* graphics */
+ switch(m_gime_registers[0x09] & 0x1C)
+ {
+ case 0x00: pitch = record_scanline_res< 16, &gime_base_device::get_data_without_attributes, false>(physical_scanline); break;
+ case 0x04: pitch = record_scanline_res< 20, &gime_base_device::get_data_without_attributes, false>(physical_scanline); break;
+ case 0x08: pitch = record_scanline_res< 32, &gime_base_device::get_data_without_attributes, false>(physical_scanline); break;
+ case 0x0C: pitch = record_scanline_res< 40, &gime_base_device::get_data_without_attributes, false>(physical_scanline); break;
+ case 0x10: pitch = record_scanline_res< 64, &gime_base_device::get_data_without_attributes, false>(physical_scanline); break;
+ case 0x14: pitch = record_scanline_res< 80, &gime_base_device::get_data_without_attributes, false>(physical_scanline); break;
+ case 0x18: pitch = record_scanline_res<128, &gime_base_device::get_data_without_attributes, false>(physical_scanline); break;
+ case 0x1C: pitch = record_scanline_res<160, &gime_base_device::get_data_without_attributes, false>(physical_scanline); break;
+ default:
+ fatalerror("Should not get here");
+ return;
+ }
+ }
+ else
+ {
+ /* text */
+ switch(m_gime_registers[0x09] & 0x15)
+ {
+ case 0x00: pitch = record_scanline_res< 32, &gime_base_device::get_data_without_attributes, true>(physical_scanline); break;
+ case 0x01: pitch = record_scanline_res< 32, &gime_base_device::get_data_with_attributes, true>(physical_scanline); break;
+ case 0x04: pitch = record_scanline_res< 40, &gime_base_device::get_data_without_attributes, true>(physical_scanline); break;
+ case 0x05: pitch = record_scanline_res< 40, &gime_base_device::get_data_with_attributes, true>(physical_scanline); break;
+ case 0x10: pitch = record_scanline_res< 64, &gime_base_device::get_data_without_attributes, true>(physical_scanline); break;
+ case 0x11: pitch = record_scanline_res< 64, &gime_base_device::get_data_with_attributes, true>(physical_scanline); break;
+ case 0x14: pitch = record_scanline_res< 80, &gime_base_device::get_data_without_attributes, true>(physical_scanline); break;
+ case 0x15: pitch = record_scanline_res< 80, &gime_base_device::get_data_with_attributes, true>(physical_scanline); break;
+ default:
+ fatalerror("Should not get here");
+ return;
+ }
+ }
+
+ /* is the GIME hoizontal virtual screen enabled? */
+ if (m_gime_registers[0x0F] & 0x80)
+ {
+ pitch = 256;
+ }
+ }
+
+ /* sanity checks */
+ assert(pitch > 0);
+
+ /* are we moving on to the next line? */
+ if (++m_line_in_row >= get_lines_per_row())
+ {
+ /* next row */
+ m_line_in_row = 0;
+ m_video_position += pitch;
+ }
+}
+
+
+
+//-------------------------------------------------
+// update_geometry
+//-------------------------------------------------
+
+void gime_base_device::update_geometry(void)
+{
+ UINT16 top_border_scanlines, body_scanlines;
+
+ switch(m_legacy_video ? 0x00 : (m_gime_registers[9] & 0x60))
+ {
+ case 0x00:
+ // 192 lines (and legacy video)
+ top_border_scanlines = 25;
+ body_scanlines = 192;
+ break;
+
+ case 0x20:
+ // 200 lines
+ top_border_scanlines = 23;
+ body_scanlines = 200;
+ break;
+
+ case 0x40:
+ // zero/infinite lines
+ //
+ // If specified within the border, the border will go forever. If specified within the body, the body will go forever. This
+ // suggests that there is a counter that counts scanlines, and we switch border <=> body when we hit some maximum count
+ top_border_scanlines = ~0;
+ body_scanlines = ~0;
+ break;
+
+ case 0x60:
+ // 225 lines
+ top_border_scanlines = 8;
+ body_scanlines = 225;
+ break;
+
+ default:
+ fatalerror("Should not get here");
+ break;
+ }
+
+ // bit 3 of $FF99 controls "wideness"
+ bool wide = !m_legacy_video && (m_gime_registers[9] & 0x08);
+
+ // set the geometry
+ set_geometry(top_border_scanlines, body_scanlines, wide);
+}
+
+
+
+//**************************************************************************
+// VIDEO BLITTING
+//**************************************************************************
+
+//-------------------------------------------------
+// emit_dummy_samples
+//-------------------------------------------------
+
+UINT32 gime_base_device::emit_dummy_samples(const scanline_record *scanline, int sample_start, int sample_count, pixel_t *pixels, const pixel_t *palette)
+{
+ fatalerror("Should not get here");
+ return 0;
+}
+
+
+
+//-------------------------------------------------
+// emit_mc6847_samples
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE UINT32 gime_base_device::emit_mc6847_samples(const scanline_record *scanline, int sample_start, int sample_count, pixel_t *pixels, const pixel_t *palette)
+{
+ return super::emit_mc6847_samples<2>(
+ scanline->m_mode[sample_start],
+ &scanline->m_data[sample_start],
+ sample_count,
+ pixels,
+ palette,
+ NULL,
+ sample_start,
+ scanline->m_line_in_row);
+}
+
+
+
+//-------------------------------------------------
+// emit_gime_graphics_samples
+//-------------------------------------------------
+
+template<int xscale, int bits_per_pixel>
+ATTR_FORCE_INLINE UINT32 gime_base_device::emit_gime_graphics_samples(const scanline_record *scanline, int sample_start, int sample_count, pixel_t *pixels, const pixel_t *palette)
+{
+ const UINT8 *data = &scanline->m_data[sample_start];
+ mc6847_friend_device::emit_graphics<bits_per_pixel, xscale>(data, sample_count, pixels, 0, palette);
+ return sample_count * (8 / bits_per_pixel) * xscale;
+}
+
+
+
+//-------------------------------------------------
+// emit_gime_text_samples
+//-------------------------------------------------
+
+template<int xscale>
+ATTR_FORCE_INLINE UINT32 gime_base_device::emit_gime_text_samples(const scanline_record *scanline, int sample_start, int sample_count, pixel_t *pixels, const pixel_t *palette)
+{
+ UINT8 attribute = scanline->m_mode[sample_start];
+ const UINT8 *data = &scanline->m_data[sample_start];
+
+ /* determine the background/foreground colors */
+ UINT8 bg = (attribute == NO_ATTRIBUTE) ? 0 : ((attribute >> 0) & 0x07) + 0x00;
+ UINT8 fg = (attribute == NO_ATTRIBUTE) ? 1 : ((attribute >> 3) & 0x07) + 0x08;
+
+ /* underline attribute */
+ int underline_line = -1;
+ if ((attribute != NO_ATTRIBUTE) && (attribute & 0x40))
+ {
+ /* to quote SockMaster:
+ *
+ * The underline attribute will light up the bottom scan line of the character
+ * if the lines are set to 8 or 9. Not appear at all when less, or appear on
+ * the 2nd to bottom scan line if set higher than 9. Further exception being
+ * the $x7 setting where the whole screen is filled with only one line of data
+ * - but it's glitched - the line repeats over and over again every 16 scan
+ * lines.. Nobody will use this mode, but that's what happens if you want to
+ * make things really authentic :)
+ */
+ switch(scanline->m_ff98_value & 0x07)
+ {
+ case 0x03:
+ underline_line = 7;
+ break;
+ case 0x04:
+ case 0x05:
+ underline_line = 8;
+ break;
+ case 0x06:
+ underline_line = 9;
+ break;
+ }
+ }
+
+ for (int i = 0; i < sample_count; i++)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ for (int k = 0; k < xscale; k++)
+ {
+ UINT8 font_byte = hires_font[data[i] & 0x7F][scanline->m_line_in_row];
+ bool bit = (scanline->m_line_in_row == underline_line) || ((font_byte >> (7 - j)) & 0x01);
+ pixels[(i * 8 + j) * xscale + k] = bit ? palette[fg] : palette[bg];
+ }
+ }
+ }
+ return sample_count * 8 * xscale;
+}
+
+
+
+//-------------------------------------------------
+// render_scanline
+//-------------------------------------------------
+
+template<int sample_count, gime_base_device::emit_samples_proc emit_samples>
+ATTR_FORCE_INLINE void gime_base_device::render_scanline(const scanline_record *scanline, pixel_t *pixels, int min_x, int max_x, palette_resolver *resolver)
+{
+ int left_border, right_border;
+ int x, x2, pixel_position;
+ pixel_t border_color = resolver->lookup(scanline->m_border);
+ const pixel_t *resolved_palette = NULL;
+
+ /* is this a wide video mode? */
+ bool wide = !m_legacy_video && (scanline->m_ff99_value & 0x04);
+
+ /* size up the borders */
+ if (sample_count > 0)
+ {
+ left_border = wide ? 0 : 64;
+ right_border = wide ? 640 : 512;
+ }
+ else
+ {
+ left_border = 640;
+ right_border = 640;
+ }
+
+ /* left border */
+ for (x = min_x; x < left_border; x++)
+ {
+ pixels[x] = border_color;
+ }
+
+ /* right border */
+ for (x = right_border; x <= max_x; x++)
+ {
+ pixels[x] = border_color;
+ }
+
+ /* offset the pixel counts depending on wide */
+ pixels += wide ? 0 : 64;
+
+ /* body */
+ x = 0;
+ pixel_position = 0;
+ while(x < sample_count)
+ {
+ /* determine how many bytes exist for which the mode is identical */
+ for (x2 = x + 1; (x2 < sample_count) && (scanline->m_mode[x] == scanline->m_mode[x2]) && (scanline->m_palette[x] == scanline->m_palette[x2]); x2++)
+ ;
+
+ /* resolve the palette */
+ resolved_palette = resolver->get_palette(scanline->m_palette[x]);
+
+ /* emit the samples, with a (hopefully) aggressively inlined function */
+ pixel_position += ((*this).*(emit_samples))(scanline, x, x2 - x, &pixels[pixel_position], resolved_palette);
+
+ /* update x */
+ x = x2;
+ }
+
+ /* artifacting */
+ if (m_legacy_video && (sample_count > 0))
+ {
+ m_artifacter.process_artifacts<2>(pixels, scanline->m_mode[0], resolved_palette);
+ }
+}
+
+
+
+//-------------------------------------------------
+// update_screen
+//-------------------------------------------------
+
+bool gime_base_device::update_screen(bitmap_rgb32 &bitmap, const rectangle &cliprect, const pixel_t *RESTRICT palette)
+{
+ int base_x = 64;
+ int min_x = USE_HORIZONTAL_CLIP ? cliprect.min_x : 0;
+ int max_x = USE_HORIZONTAL_CLIP ? cliprect.max_x : (base_x * 2 + 512 - 1);
+ int min_y = cliprect.min_y;
+ int max_y = cliprect.max_y;
+ palette_resolver resolver(this, palette);
+
+ /* if the video didn't change, indicate as much */
+ if (!has_video_changed())
+ return UPDATE_HAS_NOT_CHANGED;
+
+ for (int y = min_y; y <= max_y; y++)
+ {
+ const scanline_record *scanline = &m_scanlines[y];
+ pixel_t *RESTRICT pixels = bitmap_addr(bitmap, y, 0);
+
+ /* render the scanline */
+ if (m_scanlines[y].m_line_in_row == (UINT8) ~0)
+ {
+ /* this is a border scanline */
+ render_scanline<0, &gime_base_device::emit_dummy_samples>(scanline, pixels, min_x, max_x, &resolver);
+ }
+ else if (m_legacy_video)
+ {
+ /* this is a legacy body scanline */
+ switch(scanline->m_ff22_value & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0))
+ {
+ case MODE_AG:
+ case MODE_AG|MODE_GM0:
+ case MODE_AG|MODE_GM1|MODE_GM0:
+ case MODE_AG|MODE_GM2|MODE_GM0:
+ render_scanline<16, &gime_base_device::emit_mc6847_samples>(scanline, pixels, min_x, max_x, &resolver);
+ break;
+
+ default:
+ render_scanline<32, &gime_base_device::emit_mc6847_samples>(scanline, pixels, min_x, max_x, &resolver);
+ break;
+ }
+ }
+ else if (scanline->m_ff98_value & 0x80)
+ {
+ /* GIME graphics */
+ switch(scanline->m_ff99_value & 0x1F)
+ {
+ case 0x00: render_scanline< 16, &gime_base_device::emit_gime_graphics_samples< 4, 1> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x01: render_scanline< 16, &gime_base_device::emit_gime_graphics_samples< 8, 2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x02:
+ case 0x03: render_scanline< 16, &gime_base_device::emit_gime_graphics_samples<16, 4> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x04: render_scanline< 20, &gime_base_device::emit_gime_graphics_samples< 4, 1> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x05: render_scanline< 20, &gime_base_device::emit_gime_graphics_samples< 8, 2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x06:
+ case 0x07: render_scanline< 20, &gime_base_device::emit_gime_graphics_samples<16, 4> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x08: render_scanline< 32, &gime_base_device::emit_gime_graphics_samples< 2, 1> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x09: render_scanline< 32, &gime_base_device::emit_gime_graphics_samples< 4, 2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x0A:
+ case 0x0B: render_scanline< 32, &gime_base_device::emit_gime_graphics_samples< 8, 4> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x0C: render_scanline< 40, &gime_base_device::emit_gime_graphics_samples< 2, 1> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x0D: render_scanline< 40, &gime_base_device::emit_gime_graphics_samples< 4, 2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x0E:
+ case 0x0F: render_scanline< 40, &gime_base_device::emit_gime_graphics_samples< 8, 4> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x10: render_scanline< 64, &gime_base_device::emit_gime_graphics_samples< 1, 1> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x11: render_scanline< 64, &gime_base_device::emit_gime_graphics_samples< 2, 2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x12:
+ case 0x13: render_scanline< 64, &gime_base_device::emit_gime_graphics_samples< 4, 4> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x14: render_scanline< 80, &gime_base_device::emit_gime_graphics_samples< 1, 1> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x15: render_scanline< 80, &gime_base_device::emit_gime_graphics_samples< 2, 2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x16:
+ case 0x17: render_scanline< 80, &gime_base_device::emit_gime_graphics_samples< 4, 4> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x18:
+ case 0x19: render_scanline<128, &gime_base_device::emit_gime_graphics_samples< 1, 2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x1A:
+ case 0x1B: render_scanline<128, &gime_base_device::emit_gime_graphics_samples< 2, 4> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x1C:
+ case 0x1D: render_scanline<160, &gime_base_device::emit_gime_graphics_samples< 1, 2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x1E:
+ case 0x1F: render_scanline<160, &gime_base_device::emit_gime_graphics_samples< 2, 4> >(scanline, pixels, min_x, max_x, &resolver); break;
+ }
+ }
+ else
+ {
+ /* GIME text */
+ switch(scanline->m_ff99_value & 0x14)
+ {
+ case 0x00: render_scanline<32, &gime_base_device::emit_gime_text_samples<2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x04: render_scanline<40, &gime_base_device::emit_gime_text_samples<2> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x10: render_scanline<64, &gime_base_device::emit_gime_text_samples<1> >(scanline, pixels, min_x, max_x, &resolver); break;
+ case 0x14: render_scanline<80, &gime_base_device::emit_gime_text_samples<1> >(scanline, pixels, min_x, max_x, &resolver); break;
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+//-------------------------------------------------
+// update_composite
+//-------------------------------------------------
+
+bool gime_base_device::update_composite(bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ update_value(&m_displayed_rgb, false);
+ const pixel_t *palette = (m_gime_registers[0x08] & 0x10)
+ ? m_composite_bw_palette
+ : m_composite_palette;
+ return update_screen(bitmap, cliprect, palette);
+}
+
+
+
+//-------------------------------------------------
+// update_rgb
+//-------------------------------------------------
+
+bool gime_base_device::update_rgb(bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ update_value(&m_displayed_rgb, true);
+ return update_screen(bitmap, cliprect, m_rgb_palette);
+}
+
+
+
+//**************************************************************************
+// PALETTE RESOLVER MEMBER CLASS
+//**************************************************************************
+
+//-------------------------------------------------
+// palette_resolver::palette_resolver
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE gime_base_device::palette_resolver::palette_resolver(gime_base_device *gime, const pixel_t *palette)
+{
+ m_gime = gime;
+ m_palette = palette;
+ memset(m_resolved_palette, 0, sizeof(m_resolved_palette));
+ m_current_resolved_palette = -1;
+}
+
+
+
+//-------------------------------------------------
+// palette_resolver::get_palette
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE const gime_base_device::pixel_t *gime_base_device::palette_resolver::get_palette(UINT16 palette_rotation)
+{
+ if (UNEXPECTED(m_current_resolved_palette != palette_rotation))
+ {
+ for (int i = 0; i < 16; i++)
+ m_resolved_palette[i] = lookup(m_gime->m_palette_rotated[palette_rotation][i]);
+ m_current_resolved_palette = palette_rotation;
+ }
+ return m_resolved_palette;
+}
+
+
+
+//-------------------------------------------------
+// palette_resolver::lookup
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE gime_base_device::pixel_t gime_base_device::palette_resolver::lookup(UINT8 color)
+{
+ assert(color <= 63);
+ return m_palette[color];
+}
+
+
+
+//-------------------------------------------------
+// hires_font
+//-------------------------------------------------
+
+const UINT8 gime_base_device::hires_font[128][12] =
+{
+ { 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x10}, { 0x44, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00},
+ { 0x08, 0x10, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00}, { 0x10, 0x28, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00},
+ { 0x28, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00}, { 0x20, 0x10, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00},
+ { 0x10, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00}, { 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x10},
+ { 0x10, 0x28, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00}, { 0x28, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00},
+ { 0x20, 0x10, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00}, { 0x28, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00},
+ { 0x10, 0x28, 0x00, 0x30, 0x10, 0x10, 0x38, 0x00}, { 0x00, 0x18, 0x24, 0x38, 0x24, 0x24, 0x38, 0x40},
+ { 0x44, 0x10, 0x28, 0x44, 0x7C, 0x44, 0x44, 0x00}, { 0x10, 0x10, 0x28, 0x44, 0x7C, 0x44, 0x44, 0x00},
+ { 0x08, 0x10, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00}, { 0x00, 0x00, 0x68, 0x14, 0x3C, 0x50, 0x3C, 0x00},
+ { 0x3C, 0x50, 0x50, 0x78, 0x50, 0x50, 0x5C, 0x00}, { 0x10, 0x28, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00},
+ { 0x28, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00}, { 0x00, 0x00, 0x38, 0x4C, 0x54, 0x64, 0x38, 0x00},
+ { 0x10, 0x28, 0x00, 0x44, 0x44, 0x4C, 0x34, 0x00}, { 0x20, 0x10, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00},
+ { 0x38, 0x4C, 0x54, 0x54, 0x54, 0x64, 0x38, 0x00}, { 0x44, 0x38, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00},
+ { 0x28, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00}, { 0x38, 0x40, 0x38, 0x44, 0x38, 0x04, 0x38, 0x00},
+ { 0x08, 0x14, 0x10, 0x38, 0x10, 0x50, 0x3C, 0x00}, { 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00},
+ { 0x10, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x20, 0x40},
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00},
+ { 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00},
+ { 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00}, { 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00},
+ { 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00}, { 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00},
+ { 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00}, { 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00},
+ { 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00}, { 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00},
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20}, { 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00},
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00}, { 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00},
+ { 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00}, { 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00},
+ { 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00}, { 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00},
+ { 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00}, { 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00},
+ { 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00}, { 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00},
+ { 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00}, { 0x38, 0x44, 0x44, 0x38, 0x04, 0x04, 0x38, 0x00},
+ { 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00}, { 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20},
+ { 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00}, { 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00},
+ { 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00}, { 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00},
+ { 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00}, { 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00},
+ { 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00}, { 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00},
+ { 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00}, { 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00},
+ { 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00}, { 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00},
+ { 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00}, { 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00},
+ { 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00}, { 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00},
+ { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00}, { 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00},
+ { 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00}, { 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00},
+ { 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00}, { 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00},
+ { 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00}, { 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00},
+ { 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00}, { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00},
+ { 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00}, { 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00},
+ { 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00}, { 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00},
+ { 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00}, { 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00},
+ { 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00}, { 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00},
+ { 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00}, { 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00},
+ { 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00},
+ { 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00}, { 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00},
+ { 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00}, { 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00},
+ { 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00}, { 0x00, 0x00, 0x34, 0x4C, 0x4C, 0x34, 0x04, 0x38},
+ { 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00}, { 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x38, 0x00},
+ { 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x44, 0x38}, { 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00},
+ { 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00}, { 0x00, 0x00, 0x68, 0x54, 0x54, 0x54, 0x54, 0x00},
+ { 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00}, { 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00},
+ { 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40}, { 0x00, 0x00, 0x3C, 0x44, 0x44, 0x3C, 0x04, 0x04},
+ { 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00}, { 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00},
+ { 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00}, { 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00},
+ { 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00}, { 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00},
+ { 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00}, { 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38},
+ { 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00}, { 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00},
+ { 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00}, { 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00},
+ { 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00}
+};
+
+
+
+//**************************************************************************
+// VARIATIONS
+//**************************************************************************
+
+const device_type GIME_NTSC = &device_creator<gime_ntsc_device>;
+const device_type GIME_PAL = &device_creator<gime_pal_device>;
+
+
+
+//-------------------------------------------------
+// gime_ntsc_device
+//-------------------------------------------------
+
+gime_ntsc_device::gime_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : gime_base_device(mconfig, GIME_NTSC, "GIME_NTSC", tag, owner, clock, ntsc_round_fontdata8x12)
+{
+}
+
+
+
+//-------------------------------------------------
+// gime_pal_device
+//-------------------------------------------------
+
+gime_pal_device::gime_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : gime_base_device(mconfig, GIME_PAL, "GIME_PAL", tag, owner, clock, pal_round_fontdata8x12)
+{
+}
diff --git a/src/mess/video/gime.h b/src/mess/video/gime.h
new file mode 100644
index 00000000000..638f30a7151
--- /dev/null
+++ b/src/mess/video/gime.h
@@ -0,0 +1,297 @@
+/*********************************************************************
+
+ mc6847.h
+
+ Implementation of Motorola 6847 video hardware chip
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __GIME__
+#define __GIME__
+
+#include "video/mc6847.h"
+#include "machine/6883sam.h"
+#include "machine/ram.h"
+
+
+//**************************************************************************
+// GIME CONFIG/INTERFACE
+//**************************************************************************
+
+/* interface */
+typedef struct _gime_interface gime_interface;
+struct _gime_interface
+{
+ const char *m_screen_tag; /* screen we are acting on */
+ const char *m_maincpu_tag; /* tag of main CPU */
+ const char *m_ram_tag; /* tag of RAM device */
+ const char *m_ext_tag; /* tag of expansion device */
+
+ /* if specified, this gets called for every change of the HSYNC pin */
+ devcb_write_line m_out_hsync_func;
+
+ /* if specified, this gets called for every change of the FSYNC pin */
+ devcb_write_line m_out_fsync_func;
+
+ /* if specified, this gets called for every change of the IRQ pin */
+ devcb_write_line m_out_irq_func;
+
+ /* if specified, this gets called for every change of the FIRQ pin */
+ devcb_write_line m_out_firq_func;
+
+ /* if specified, this reads from the floating bugs */
+ devcb_read8 m_in_floating_bus_func;
+};
+
+
+
+//**************************************************************************
+// GIME CORE
+//**************************************************************************
+
+class cococart_slot_device;
+\
+class gime_base_device : public mc6847_friend_device, public sam6883_friend_device
+{
+public:
+ // read/write
+ DECLARE_READ8_MEMBER( read ) { return read(offset); }
+ DECLARE_WRITE8_MEMBER( write ) { write(offset, data); }
+
+ // used to turn on/off reading/writing to $FF40-$FF5F
+ bool spare_chip_select_enabled(void) { return m_gime_registers[0] & 0x04 ? true : false; }
+
+ // the GIME seems to intercept writes to $FF22 (not precisely sure how)
+ void ff22_write(UINT8 data) { m_ff22_value = data; }
+
+ // updates the cart ROM
+ void update_cart_rom(void);
+
+ /* updates the screen -- this will call begin_update(),
+ followed by update_row() reapeatedly and after all row
+ updating is complete, end_update() */
+ bool update_composite(bitmap_rgb32 &bitmap, const rectangle &cliprect);
+ bool update_rgb(bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ // interrupt outputs
+ bool firq_r(void) { return m_firq != 0x00; }
+ bool irq_r(void) { return m_irq != 0x00; }
+
+ // interrupt inputs
+ void set_il0(bool value) { set_interrupt_value(INTERRUPT_EI0, value); }
+ void set_il1(bool value) { set_interrupt_value(INTERRUPT_EI1, value); }
+ void set_il2(bool value) { set_interrupt_value(INTERRUPT_EI2, value); }
+
+protected:
+ gime_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata);
+
+ // device-level overrides
+ virtual void device_start(void);
+ virtual void device_reset(void);
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_post_load(void);
+ virtual ioport_constructor device_input_ports() const;
+
+ // other overrides
+ virtual void new_frame(void);
+ virtual void horizontal_sync_changed(bool line);
+ virtual void enter_bottom_border(void);
+ virtual void record_border_scanline(UINT16 physical_scanline);
+ virtual void record_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline);
+
+private:
+ typedef mc6847_friend_device super;
+
+ struct scanline_record
+ {
+ UINT8 m_border;
+ UINT8 m_line_in_row;
+ UINT8 m_ff22_value;
+ UINT8 m_ff98_value;
+ UINT8 m_ff99_value;
+ UINT8 m_mode[160];
+ UINT8 m_data[160];
+ UINT16 m_palette[160];
+ };
+
+ typedef UINT32 (gime_base_device::*get_data_func)(UINT32, UINT8 *, UINT8 *);
+
+ class palette_resolver
+ {
+ public:
+ palette_resolver(gime_base_device *gime, const pixel_t *palette);
+ const pixel_t *get_palette(UINT16 palette_rotation);
+ pixel_t lookup(UINT8 color);
+
+ private:
+ gime_base_device *m_gime;
+ const pixel_t *m_palette;
+ pixel_t m_resolved_palette[16];
+ int m_current_resolved_palette;
+ };
+
+ enum
+ {
+ INTERRUPT_TMR = 0x20,
+ INTERRUPT_HBORD = 0x10,
+ INTERRUPT_VBORD = 0x08,
+ INTERRUPT_EI2 = 0x04,
+ INTERRUPT_EI1 = 0x02,
+ INTERRUPT_EI0 = 0x01
+ };
+
+ typedef enum
+ {
+ GIME_TIMER_HBORD,
+ GIME_TIMER_CLOCK
+ } timer_type_t;
+
+ // timer constants
+ static const device_timer_id TIMER_GIME_CLOCK = 4;
+
+ // statics
+ static const UINT8 hires_font[128][12];
+
+ // callbacks
+ devcb_resolved_write_line m_res_out_irq_func;
+ devcb_resolved_write_line m_res_out_firq_func;
+ devcb_resolved_read8 m_res_in_floating_bus_func;
+
+ // device state
+ UINT8 m_gime_registers[16];
+ UINT8 m_mmu[16];
+ UINT8 m_ff22_value;
+ UINT8 m_interrupt_value;
+ UINT8 m_irq;
+ UINT8 m_firq;
+ UINT16 m_timer_value;
+ bool m_is_blinking;
+
+ // video state
+ bool m_legacy_video;
+ UINT32 m_video_position;
+ UINT8 m_line_in_row;
+ scanline_record m_scanlines[25+192+26];
+ bool m_displayed_rgb;
+
+ // palette state
+ UINT8 m_palette_rotated[1024][16];
+ UINT16 m_palette_rotated_position;
+ bool m_palette_rotated_position_used;
+
+ // incidentals
+ ram_device *m_ram;
+ emu_timer *m_gime_clock_timer;
+ cococart_slot_device *m_cart_device;
+ UINT8 *m_rom;
+ UINT8 *m_cart_rom;
+ pixel_t m_composite_palette[64];
+ pixel_t m_composite_bw_palette[64];
+ pixel_t m_rgb_palette[64];
+ UINT8 m_dummy_bank[0x2000];
+
+ // timer constants
+ static const device_timer_id TIMER_FRAME = 0;
+ static const device_timer_id TIMER_HSYNC_OFF = 1;
+ static const device_timer_id TIMER_HSYNC_ON = 2;
+ static const device_timer_id TIMER_FSYNC_OFF = 3;
+ static const device_timer_id TIMER_FSYNC_ON = 4;
+
+ // read/write
+ UINT8 read(offs_t offset);
+ UINT8 read_gime_register(offs_t offset);
+ UINT8 read_mmu_register(offs_t offset);
+ UINT8 read_palette_register(offs_t offset);
+ UINT8 read_floating_bus(void);
+ void write(offs_t offset, UINT8 data);
+ void write_gime_register(offs_t offset, UINT8 data);
+ void write_mmu_register(offs_t offset, UINT8 data);
+ void write_palette_register(offs_t offset, UINT8 data);
+ void write_sam_register(offs_t offset);
+
+ // memory
+ void update_memory(void);
+ void update_memory(int bank);
+ UINT8 *memory_pointer(UINT32 address);
+
+ // interrupts
+ void interrupt_rising_edge(UINT8 interrupt);
+ void recalculate_irq(void);
+ void recalculate_firq(void);
+
+ ATTR_FORCE_INLINE void set_interrupt_value(UINT8 interrupt, bool value)
+ {
+ /* save the old interrupt value */
+ UINT8 old_interrupt_value = m_interrupt_value;
+
+ /* update the interrupt value */
+ if (value)
+ m_interrupt_value |= interrupt;
+ else
+ m_interrupt_value &= ~interrupt;
+
+ /* was this a rising edge? */
+ if (value && ((old_interrupt_value & interrupt) == 0))
+ {
+ interrupt_rising_edge(interrupt);
+ }
+ }
+
+ // timer
+ timer_type_t timer_type(void);
+ const char *timer_type_string(void);
+ void reset_timer(void);
+ void timer_elapsed(void);
+
+ // video
+ bool update_screen(bitmap_rgb32 &bitmap, const rectangle &cliprect, const pixel_t *palette);
+ void update_geometry(void);
+ void update_border(UINT16 physical_scanline);
+ pixel_t get_composite_color(int color);
+ pixel_t get_rgb_color(int color);
+ offs_t get_video_base(void);
+ UINT16 get_lines_per_row(void);
+ UINT32 get_data_mc6847(UINT32 video_position, UINT8 *data, UINT8 *mode);
+ UINT32 get_data_without_attributes(UINT32 video_position, UINT8 *data, UINT8 *mode);
+ UINT32 get_data_with_attributes(UINT32 video_position, UINT8 *data, UINT8 *mode);
+ bool is_blinking(void);
+
+ // template function for doing video update collection
+ template<UINT8 xres, get_data_func get_data, bool record_mode>
+ UINT32 record_scanline_res(int scanline);
+
+ // rendering sampled graphics
+ typedef UINT32 (gime_base_device::*emit_samples_proc)(const scanline_record *scanline, int sample_start, int sample_count, pixel_t *pixels, const pixel_t *palette);
+ UINT32 emit_dummy_samples(const scanline_record *scanline, int sample_start, int sample_count, pixel_t *pixels, const pixel_t *palette);
+ UINT32 emit_mc6847_samples(const scanline_record *scanline, int sample_start, int sample_count, pixel_t *pixels, const pixel_t *palette);
+ template<int xscale>
+ UINT32 emit_gime_text_samples(const scanline_record *scanline, int sample_start, int sample_count, pixel_t *pixels, const pixel_t *palette);
+ template<int xscale, int bits_per_pixel>
+ UINT32 emit_gime_graphics_samples(const scanline_record *scanline, int sample_start, int sample_count, pixel_t *pixels, const pixel_t *palette);
+ template<int sample_count, emit_samples_proc emit_samples>
+ void render_scanline(const scanline_record *scanline, pixel_t *pixels, int min_x, int max_x, palette_resolver *resolver);
+};
+
+
+//**************************************************************************
+// VARIATIONS
+//**************************************************************************
+
+class gime_ntsc_device : public gime_base_device
+{
+public:
+ gime_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class gime_pal_device : public gime_base_device
+{
+public:
+ gime_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+extern const device_type GIME_NTSC;
+extern const device_type GIME_PAL;
+
+#endif /* __GIME__ */
diff --git a/src/mess/video/hd44352.c b/src/mess/video/hd44352.c
new file mode 100644
index 00000000000..72fee0350c4
--- /dev/null
+++ b/src/mess/video/hd44352.c
@@ -0,0 +1,456 @@
+/***************************************************************************
+
+ Hitachi HD44352 LCD controller
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/hd44352.h"
+
+#define LCD_BYTE_INPUT 0x01
+#define LCD_BYTE_OUTPUT 0x02
+#define LCD_CHAR_OUTPUT 0x03
+#define LCD_ON_OFF 0x04
+#define LCD_CURSOR_GRAPHIC 0x06
+#define LCD_CURSOR_CHAR 0x07
+#define LCD_SCROLL_CHAR_WIDTH 0x08
+#define LCD_CURSOR_STATUS 0x09
+#define LCD_USER_CHARACTER 0x0b
+#define LCD_CONTRAST 0x0c
+#define LCD_IRQ_FREQUENCY 0x0d
+#define LCD_CURSOR_POSITION 0x0e
+
+
+// devices
+const device_type HD44352 = &device_creator<hd44352_device>;
+
+//**************************************************************************
+// live device
+//**************************************************************************
+
+//-------------------------------------------------
+// hd44352_device - constructor
+//-------------------------------------------------
+
+hd44352_device::hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock):
+ device_t(mconfig, HD44352, "hd44352", tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void hd44352_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const hd44352_interface *intf = reinterpret_cast<const hd44352_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<hd44352_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_on, 0, sizeof(m_on));
+ }
+}
+
+//-------------------------------------------------
+// device_validity_check - perform validity checks
+// on this device
+//-------------------------------------------------
+
+void hd44352_device::device_validity_check(validity_checker &valid) const
+{
+}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void hd44352_device::device_start()
+{
+ m_on.resolve(m_on_cb, *this);
+
+ m_on_timer = timer_alloc(ON_TIMER);
+ m_on_timer->adjust(attotime::from_hz(m_clock/16384), 0, attotime::from_hz(m_clock/16384));
+
+ save_item( NAME(m_control_lines));
+ save_item( NAME(m_data_bus));
+ save_item( NAME(m_state));
+ save_item( NAME(m_offset));
+ save_item( NAME(m_char_width));
+ save_item( NAME(m_bank));
+ save_item( NAME(m_lcd_on));
+ save_item( NAME(m_scroll));
+ save_item( NAME(m_contrast));
+ save_item( NAME(m_byte_count));
+ save_item( NAME(m_cursor_status));
+ save_item( NAME(m_cursor_x));
+ save_item( NAME(m_cursor_y));
+ save_item( NAME(m_cursor_lcd));
+ save_item( NAME(m_video_ram[0]));
+ save_item( NAME(m_video_ram[1]));
+ save_item( NAME(m_par));
+ save_item( NAME(m_cursor));
+ save_item( NAME(m_custom_char[0]));
+ save_item( NAME(m_custom_char[1]));
+ save_item( NAME(m_custom_char[2]));
+ save_item( NAME(m_custom_char[3]));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void hd44352_device::device_reset()
+{
+ memset(m_video_ram, 0x00, sizeof(m_video_ram));
+ memset(m_par, 0x00, sizeof(m_par));
+ memset(m_custom_char, 0x00, sizeof(m_custom_char));
+ memset(m_cursor, 0x00, sizeof(m_cursor));
+ m_control_lines = 0;
+ m_data_bus = 0xff;
+ m_state = 0;
+ m_bank = 0;
+ m_offset = 0;
+ m_char_width = 6;
+ m_lcd_on = 0;
+ m_scroll = 0;
+ m_byte_count = 0;
+ m_cursor_status = 0;
+ m_cursor_x = 0;
+ m_cursor_y = 0;
+ m_cursor_lcd = 0;
+ m_contrast = 0;
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+void hd44352_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case ON_TIMER:
+ if (m_control_lines & 0x40)
+ {
+ m_on(ASSERT_LINE);
+ m_on(CLEAR_LINE);
+ }
+ break;
+ }
+}
+
+//**************************************************************************
+// device interface
+//**************************************************************************
+
+UINT32 hd44352_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT8 cw = m_char_width;
+
+ bitmap.fill(0, cliprect);
+
+ if (m_control_lines&0x80 && m_lcd_on)
+ {
+ for (int a=0; a<2; a++)
+ for (int py=0; py<4; py++)
+ for (int px=0; px<16; px++)
+ if (BIT(m_cursor_status, 4) && px == m_cursor_x && py == m_cursor_y && a == m_cursor_lcd)
+ {
+ //draw the cursor
+ for (int c=0; c<cw; c++)
+ {
+ UINT8 d = compute_newval((m_cursor_status>>5) & 0x07, m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48], m_cursor[c]);
+ for (int b=0; b<8; b++)
+ {
+ bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b);
+ }
+ }
+ }
+ else
+ {
+ for (int c=0; c<cw; c++)
+ {
+ UINT8 d = m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48];
+ for (int b=0; b<8; b++)
+ {
+ bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+void hd44352_device::control_write(UINT8 data)
+{
+ if(m_control_lines == data)
+ m_state = 0;
+
+ m_control_lines = data;
+}
+
+UINT8 hd44352_device::compute_newval(UINT8 type, UINT8 oldval, UINT8 newval)
+{
+ switch(type & 0x07)
+ {
+ case 0x00:
+ return (~oldval) & newval;
+ case 0x01:
+ return oldval ^ newval;
+ case 0x03:
+ return oldval & (~newval);
+ case 0x04:
+ return newval;
+ case 0x05:
+ return oldval | newval;
+ case 0x07:
+ return oldval;
+ case 0x02:
+ case 0x06:
+ default:
+ return 0;
+ }
+}
+
+UINT8 hd44352_device::get_char(UINT16 pos)
+{
+ switch ((UINT8)pos/8)
+ {
+ case 0xcf:
+ return m_custom_char[0][pos%8];
+ case 0xdf:
+ return m_custom_char[1][pos%8];
+ case 0xef:
+ return m_custom_char[2][pos%8];
+ case 0xff:
+ return m_custom_char[3][pos%8];
+ default:
+ return region()->u8(pos);
+ }
+}
+
+void hd44352_device::data_write(UINT8 data)
+{
+ // verify that controller is active
+ if (!(m_control_lines&0x80))
+ return;
+
+ if (m_control_lines & 0x01)
+ {
+ if (!(m_control_lines&0x02) && !(m_control_lines&0x04))
+ return;
+
+ switch (m_state)
+ {
+ case 0: //parameter 0
+ m_par[m_state++] = data;
+ break;
+ case 1: //parameter 1
+ m_par[m_state++] = data;
+ break;
+ case 2: //parameter 2
+ m_par[m_state++] = data;
+ break;
+ }
+
+ switch (m_par[0] & 0x0f)
+ {
+ case LCD_BYTE_INPUT:
+ case LCD_CHAR_OUTPUT:
+ {
+ if (m_state == 1)
+ m_bank = BIT(data, 4);
+ else if (m_state == 2)
+ m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48);
+ else if (m_state == 3)
+ m_offset += ((data & 0x03) * 96);
+ }
+ break;
+ case LCD_BYTE_OUTPUT:
+ {
+ if (m_state == 1)
+ m_bank = BIT(data, 4);
+ else if (m_state == 2)
+ m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48);
+ else if (m_state == 3)
+ m_offset += ((data & 0x03) * 96);
+ }
+ break;
+ case LCD_ON_OFF:
+ {
+ if (m_state == 1)
+ m_lcd_on = BIT(data, 4);
+ m_data_bus = 0xff;
+ m_state = 0;
+ }
+ break;
+ case LCD_SCROLL_CHAR_WIDTH:
+ {
+ if (m_state == 1)
+ {
+ m_char_width = 8-((data>>4)&3);
+ m_scroll = ((data>>6)&3);
+ }
+
+ m_data_bus = 0xff;
+ m_state = 0;
+ }
+ break;
+ case LCD_CURSOR_STATUS:
+ {
+ if (m_state == 1)
+ m_cursor_status = data;
+ m_data_bus = 0xff;
+ m_state = 0;
+ }
+ break;
+ case LCD_CONTRAST:
+ {
+ if (m_state == 1)
+ m_contrast = (m_contrast & 0x00ffff) | (data<<16);
+ else if (m_state == 2)
+ m_contrast = (m_contrast & 0xff00ff) | (data<<8);
+ else if (m_state == 3)
+ {
+ m_contrast = (m_contrast & 0xffff00) | (data<<0);
+ m_state = 0;
+ }
+
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_IRQ_FREQUENCY:
+ {
+ if (m_state == 1)
+ {
+ UINT32 on_timer_rate;
+
+ switch((data>>4) & 0x0f)
+ {
+ case 0x00: on_timer_rate = 16384; break;
+ case 0x01: on_timer_rate = 8; break;
+ case 0x02: on_timer_rate = 16; break;
+ case 0x03: on_timer_rate = 32; break;
+ case 0x04: on_timer_rate = 64; break;
+ case 0x05: on_timer_rate = 128; break;
+ case 0x06: on_timer_rate = 256; break;
+ case 0x07: on_timer_rate = 512; break;
+ case 0x08: on_timer_rate = 1024; break;
+ case 0x09: on_timer_rate = 2048; break;
+ case 0x0a: on_timer_rate = 4096; break;
+ case 0x0b: on_timer_rate = 4096; break;
+ default: on_timer_rate = 8192; break;
+ }
+
+ m_on_timer->adjust(attotime::from_hz(m_clock/on_timer_rate), 0, attotime::from_hz(m_clock/on_timer_rate));
+ }
+ m_data_bus = 0xff;
+ m_state = 0;
+ }
+ break;
+ case LCD_CURSOR_POSITION:
+ {
+ if (m_state == 1)
+ m_cursor_lcd = BIT(data, 4); //0:left lcd 1:right lcd;
+ else if (m_state == 2)
+ m_cursor_x = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48);
+ else if (m_state == 3)
+ {
+ m_cursor_y = data & 0x03;
+ m_state = 0;
+ }
+
+ m_data_bus = 0xff;
+ }
+ break;
+ }
+
+ m_byte_count = 0;
+ m_data_bus = 0xff;
+ }
+ else
+ {
+ switch (m_par[0] & 0x0f)
+ {
+ case LCD_BYTE_INPUT:
+ {
+ if (((m_par[0]>>5) & 0x07) != 0x03)
+ break;
+
+ m_offset %= 0x180;
+ m_data_bus = ((m_video_ram[m_bank][m_offset]<<4)&0xf0) | ((m_video_ram[m_bank][m_offset]>>4)&0x0f);
+ m_offset++; m_byte_count++;
+ }
+ break;
+ case LCD_BYTE_OUTPUT:
+ {
+ m_offset %= 0x180;
+ m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], data);
+ m_offset++; m_byte_count++;
+
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_CHAR_OUTPUT:
+ {
+ int char_pos = data*8;
+
+ for (int i=0; i<m_char_width; i++)
+ {
+ m_offset %= 0x180;
+ m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], get_char(char_pos));
+ m_offset++; char_pos++;
+ }
+
+ m_byte_count++;
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_CURSOR_GRAPHIC:
+ if (m_byte_count<8)
+ {
+ m_cursor[m_byte_count] = data;
+ m_byte_count++;
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_CURSOR_CHAR:
+ if (m_byte_count<1)
+ {
+ UINT8 char_code = ((data<<4)&0xf0) | ((data>>4)&0x0f);
+
+ for (int i=0; i<8; i++)
+ m_cursor[i] = get_char(char_code*8 + i);
+
+ m_byte_count++;
+ m_data_bus = 0xff;
+ }
+ break;
+ case LCD_USER_CHARACTER:
+ if (m_byte_count<8)
+ {
+ m_custom_char[(m_par[1]&0x03)][m_byte_count] = data;
+ m_byte_count++;
+ m_data_bus = 0xff;
+ }
+ break;
+ default:
+ m_data_bus = 0xff;
+ }
+
+ m_state=0;
+ }
+}
+
+UINT8 hd44352_device::data_read()
+{
+ return m_data_bus;
+}
diff --git a/src/mess/video/hd44352.h b/src/mess/video/hd44352.h
new file mode 100644
index 00000000000..8d277f67bc6
--- /dev/null
+++ b/src/mess/video/hd44352.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+
+ Hitachi HD44352 LCD controller
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __hd44352_H__
+#define __hd44352_H__
+
+
+#define MCFG_HD44352_ADD( _tag, _clock, _config) \
+ MCFG_DEVICE_ADD( _tag, HD44352, _clock ) \
+ MCFG_DEVICE_CONFIG( _config )
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> hd44352_interface
+
+struct hd44352_interface
+{
+ devcb_write_line m_on_cb; // ON line
+};
+
+// ======================> hd44352_device
+
+class hd44352_device :
+ public device_t,
+ public hd44352_interface
+{
+public:
+ // construction/destruction
+ hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device interface
+ UINT8 data_read();
+ void data_write(UINT8 data);
+ void control_write(UINT8 data);
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_config_complete();
+ virtual void device_validity_check(validity_checker &valid) const;
+
+private:
+ UINT8 compute_newval(UINT8 type, UINT8 oldval, UINT8 newval);
+ UINT8 get_char(UINT16 pos);
+
+ static const device_timer_id ON_TIMER = 1;
+ emu_timer *m_on_timer;
+
+ UINT8 m_video_ram[2][0x180];
+ UINT8 m_control_lines;
+ UINT8 m_data_bus;
+ UINT8 m_par[3];
+ UINT8 m_state;
+ UINT16 m_bank;
+ UINT16 m_offset;
+ UINT8 m_char_width;
+ UINT8 m_lcd_on;
+ UINT8 m_scroll;
+ UINT32 m_contrast;
+
+ UINT8 m_custom_char[4][8]; // 4 chars * 8 bytes
+ UINT8 m_byte_count;
+ UINT8 m_cursor_status;
+ UINT8 m_cursor[8];
+ UINT8 m_cursor_x;
+ UINT8 m_cursor_y;
+ UINT8 m_cursor_lcd;
+
+ devcb_resolved_write_line m_on; // ON line callback
+};
+
+// device type definition
+extern const device_type HD44352;
+
+#endif
diff --git a/src/mess/video/hd44780.c b/src/mess/video/hd44780.c
new file mode 100644
index 00000000000..8050c68a007
--- /dev/null
+++ b/src/mess/video/hd44780.c
@@ -0,0 +1,344 @@
+/***************************************************************************
+
+ Hitachi HD44780 LCD controller
+
+ TODO:
+ - 4-bit mode
+ - 5x10 chars
+ - dump internal CGROM
+
+ HACKS:
+ - A00 10 bit chars are tacked onto recreated chrrom at $700 (until internal rom is dumped)
+ - A00/A02 drawing selected by sizeof romfile, A02 is $800, A00 is $860
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/hd44780.h"
+
+// devices
+const device_type HD44780 = &device_creator<hd44780_device>;
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void hd44780_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const hd44780_interface *intf = reinterpret_cast<const hd44780_interface *>(static_config());
+
+ if (intf != NULL)
+ *static_cast<hd44780_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ height = width = 0;
+ }
+}
+
+
+//**************************************************************************
+// live device
+//**************************************************************************
+
+//-------------------------------------------------
+// hd44780_device - constructor
+//-------------------------------------------------
+
+hd44780_device::hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, HD44780, "HD44780", tag, owner, clock)
+{
+}
+
+hd44780_device::hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void hd44780_device::device_start()
+{
+ m_busy_timer = timer_alloc(BUSY_TIMER);
+ m_blink_timer = timer_alloc(BLINKING_TIMER);
+
+ m_blink_timer->adjust(attotime::from_msec(409), 0, attotime::from_msec(409));
+
+ save_item( NAME(m_ac));
+ save_item( NAME(m_ac_mode));
+ save_item( NAME(m_data_bus_flag));
+ save_item( NAME(m_cursor_pos));
+ save_item( NAME(m_display_on));
+ save_item( NAME(m_cursor_on));
+ save_item( NAME(m_shift_on));
+ save_item( NAME(m_blink_on));
+ save_item( NAME(m_direction));
+ save_item( NAME(m_data_len));
+ save_item( NAME(m_num_line));
+ save_item( NAME(m_char_size));
+ save_item( NAME(m_disp_shift));
+ save_item( NAME(m_blink));
+ save_item( NAME(m_ddram));
+ save_item( NAME(m_cgram));
+
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void hd44780_device::device_reset()
+{
+ m_busy_flag = 0;
+
+ memset(m_ddram, 0x20, sizeof(m_ddram)); // can't use 0 here as it would show CGRAM instead of blank space on a soft reset
+ memset(m_cgram, 0, sizeof(m_cgram));
+ m_ac = 0;
+ m_ac_mode = 0;
+ m_data_bus_flag = 0;
+ m_cursor_pos = 0;
+ m_display_on = 0;
+ m_cursor_on = 0;
+ m_shift_on = 0;
+ m_blink_on = 0;
+ m_direction = 1;
+ m_data_len = -1; // must not be 0 or 1 on intial start to pick up first 4/8 bit mode change
+ m_num_line = 0;
+ m_char_size = 0;
+ m_disp_shift = 0;
+ m_blink = 0;
+
+ set_busy_flag(1520);
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+void hd44780_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case BUSY_TIMER:
+ m_busy_flag = 0;
+ break;
+
+ case BLINKING_TIMER:
+ m_blink = !m_blink;
+ break;
+ }
+}
+
+void hd44780_device::set_busy_flag(UINT16 usec)
+{
+ m_busy_flag = 1;
+
+ m_busy_timer->adjust( attotime::from_usec( usec ) );
+
+}
+
+//**************************************************************************
+// device interface
+//**************************************************************************
+
+UINT32 hd44780_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ assert(height*9 <= bitmap.height() && width*6 <= bitmap.width());
+
+ bitmap.fill(0, cliprect);
+
+ if (m_display_on)
+ for (int l=0; l<height; l++)
+ for (int i=0; i<width; i++)
+ {
+ UINT8 line_base = l * 0x40;
+ UINT8 line_size = (m_num_line) ? 40 : 80;
+ INT8 char_pos = line_base + i;
+
+ char_pos += m_disp_shift;
+
+ while (char_pos < 0 || (char_pos - line_base) >= line_size)
+ {
+ if (char_pos < 0)
+ char_pos += line_size;
+ else if (char_pos - line_base >= line_size)
+ char_pos -= line_size;
+ }
+
+ for (int y=0; y<8; y++)
+ for (int x=0; x<5; x++)
+ if (m_ddram[char_pos] <= 0x10)
+ {
+ //draw CGRAM characters
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(m_cgram[(m_ddram[char_pos]&0x07)*8+y], 4-x);
+ }
+ else
+ {
+ //draw CGROM characters
+ if (region()->bytes() <= 0x800)
+ {
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(region()->u8(m_ddram[char_pos]*8+y), 4-x);
+ }
+ else
+ {
+ if(m_ddram[char_pos] < 0xe0)
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(region()->u8(m_ddram[char_pos]*8+y), 4-x);
+ else
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(region()->u8(0x700+((m_ddram[char_pos]-0xe0)*11)+y), 4-x);
+ }
+ }
+
+ // if is the correct position draw cursor and blink
+ if (char_pos == m_cursor_pos)
+ {
+ //draw the cursor
+ if (m_cursor_on)
+ for (int x=0; x<5; x++)
+ bitmap.pix16(l*9 + 7, i * 6 + x) = 1;
+
+ if (!m_blink && m_blink_on)
+ for (int y=0; y<7; y++)
+ for (int x=0; x<5; x++)
+ bitmap.pix16(l*9 + y, i * 6 + x) = 1;
+ }
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(hd44780_device::control_write)
+{
+ if (BIT(data, 7)) // Set DDRAM Address
+ {
+ m_ac_mode = 0;
+ m_ac = data & 0x7f;
+ m_cursor_pos = m_ac;
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 6)) // Set CGRAM Address
+ {
+ m_ac_mode = 1;
+ m_ac = data & 0x3f;
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 5)) // Function Set
+ {
+ // datasheet says you can't change char size after first function set without altering 4/8 bit mode
+ if (BIT(data, 4) != m_data_len)
+ m_char_size = BIT(data, 2);
+
+ m_data_len = BIT(data, 4);
+ m_num_line = BIT(data, 3);
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 4)) // Cursor or display shift
+ {
+ UINT8 direct = (BIT(data, 2)) ? +1 : -1;
+
+ if (BIT(data, 3))
+ m_disp_shift += direct;
+ else
+ {
+ m_ac += direct;
+ m_cursor_pos += direct;
+ }
+
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 3)) // Display on/off Control
+ {
+ m_display_on = BIT(data, 2);
+ m_cursor_on = BIT(data, 1);
+ m_blink_on = BIT(data, 0);
+
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 2)) // Entry Mode set
+ {
+ m_direction = (BIT(data, 1)) ? +1 : -1;
+
+ m_shift_on = BIT(data, 0);
+
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 1)) // return home
+ {
+ m_ac = 0;
+ m_cursor_pos = 0;
+ m_ac_mode = 0; // datasheet does not specifically say this but mephisto won't run without it
+ m_direction = 1;
+ m_disp_shift = 0;
+ set_busy_flag(1520);
+ }
+ else if (BIT(data, 0)) // clear display
+ {
+ m_ac = 0;
+ m_cursor_pos = 0;
+ m_ac_mode = 0;
+ m_direction = 1;
+ m_disp_shift = 0;
+ memset(m_ddram, 0x20, sizeof(m_ddram));
+ set_busy_flag(1520);
+ }
+}
+
+READ8_MEMBER(hd44780_device::control_read)
+{
+ return m_busy_flag<<7 || m_ac&0x7f;
+}
+
+void hd44780_device::update_ac(void) // m_data_bus_flag was left as global so old savestates will work
+{
+ int new_ac = m_ac + m_direction;
+ m_ac = (new_ac < 0) ? 0 : ((new_ac > 0x7f) ? 0x7f : new_ac);
+ if (m_ac_mode == 0)
+ {
+ m_cursor_pos = m_ac;
+ // display is shifted only after a write
+ if (m_shift_on && m_data_bus_flag == 1) m_disp_shift += m_direction;
+ }
+ m_data_bus_flag = 0;
+}
+
+
+WRITE8_MEMBER(hd44780_device::data_write)
+{
+ if (m_busy_flag)
+ {
+ logerror("HD44780 '%s' Ignoring data write %02x due of busy flag\n", tag(), data);
+ return;
+ }
+
+ if (m_ac_mode == 0)
+ m_ddram[m_ac] = data;
+ else
+ m_cgram[m_ac] = data;
+
+ m_data_bus_flag = 1;
+ update_ac();
+ set_busy_flag(41);
+}
+
+READ8_MEMBER(hd44780_device::data_read)
+{
+ UINT8 data;
+
+ if (m_ac_mode == 0)
+ data = m_ddram[m_ac];
+ else
+ data = m_cgram[m_ac];
+
+ m_data_bus_flag = 2;
+ update_ac();
+
+ set_busy_flag(41);
+
+ return data;
+}
diff --git a/src/mess/video/hd44780.h b/src/mess/video/hd44780.h
new file mode 100644
index 00000000000..483f30c2ea0
--- /dev/null
+++ b/src/mess/video/hd44780.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+
+ Hitachi HD44780 LCD controller
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __HD44780_H__
+#define __HD44780_H__
+
+
+#define MCFG_HD44780_ADD( _tag , _config) \
+ MCFG_DEVICE_ADD( _tag, HD44780, 0 ) \
+ MCFG_DEVICE_CONFIG(_config)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+#define HD44780_INTERFACE(name) \
+ const hd44780_interface (name) =
+
+// ======================> hd44780_interface
+
+struct hd44780_interface
+{
+ UINT8 height; // number of lines
+ UINT8 width; // chars for line
+};
+
+// ======================> hd44780_device
+
+class hd44780_device : public device_t,
+ public hd44780_interface
+{
+
+public:
+ // construction/destruction
+ hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // device interface
+ virtual DECLARE_WRITE8_MEMBER(control_write);
+ virtual DECLARE_READ8_MEMBER(control_read);
+ virtual DECLARE_WRITE8_MEMBER(data_write);
+ virtual DECLARE_READ8_MEMBER(data_read);
+
+ virtual UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_config_complete();
+
+protected:
+ // internal helper
+ void set_busy_flag(UINT16 usec);
+ void update_ac(void);
+ // internal state
+ static const device_timer_id BUSY_TIMER = 0;
+ static const device_timer_id BLINKING_TIMER = 1;
+
+ emu_timer *m_blink_timer;
+ emu_timer *m_busy_timer;
+
+ UINT8 m_busy_flag;
+
+ UINT8 m_ddram[0x80]; //internal display data RAM
+ UINT8 m_cgram[0x40]; //internal chargen RAM
+
+ INT8 m_ac; //address counter
+ UINT8 m_ac_mode; //0=DDRAM 1=CGRAM
+ UINT8 m_data_bus_flag; //0=none 1=write 2=read
+
+ INT8 m_cursor_pos; //cursor position
+ UINT8 m_display_on; //display on/off
+ UINT8 m_cursor_on; //cursor on/off
+ UINT8 m_blink_on; //blink on/off
+ UINT8 m_shift_on; //shift on/off
+ INT8 m_disp_shift; //display shift
+
+ INT8 m_direction; //auto increment/decrement
+ UINT8 m_data_len; //interface data length 4 or 8 bit
+ UINT8 m_num_line; //number of lines
+ UINT8 m_char_size; //char size 5x8 or 5x10
+
+ UINT8 m_blink;
+};
+
+// device type definition
+extern const device_type HD44780;
+
+#endif
diff --git a/src/mess/video/hd66421.c b/src/mess/video/hd66421.c
new file mode 100644
index 00000000000..843b9ed66f1
--- /dev/null
+++ b/src/mess/video/hd66421.c
@@ -0,0 +1,254 @@
+/*
+
+ Hitachi HD66421 LCD Controller/Driver
+
+ (c) 2001-2007 Tim Schuerewegen
+
+*/
+
+#include "emu.h"
+#include "hd66421.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG_LEVEL 1
+#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
+
+#define HD66421_RAM_SIZE (HD66421_WIDTH * HD66421_HEIGHT / 4) // 2-bits per pixel
+
+// R0 - control register 1
+#define LCD_R0_RMW 0x80 // read-modify-write mode
+#define LCD_R0_DISP 0x40 // display on/off
+#define LCD_R0_STBY 0x20 // standby (internal operation and power circuit halt)
+#define LCD_R0_PWR 0x10
+#define LCD_R0_AMP 0x08
+#define LCD_R0_REV 0x04 // reverse
+#define LCD_R0_HOLT 0x02
+#define LCD_R0_ADC 0x01
+
+// R1 - control register 2
+#define LCD_R1_BIS1 0x80 // bias ratio (bit 1)
+#define LCD_R1_BIS0 0x40 // bias ratio (bit 0)
+#define LCD_R1_WLS 0x20
+#define LCD_R1_GRAY 0x10 // grayscale palette 4/32
+#define LCD_R1_DTY1 0x08 // display duty cycle (bit 1)
+#define LCD_R1_DTY0 0x04 // display duty cycle (bit 0)
+#define LCD_R1_INC 0x02
+#define LCD_R1_BLK 0x01 // blink function
+
+// register 0 to 16
+#define LCD_REG_CONTROL_1 0x00 // control register 1
+#define LCD_REG_CONTROL_2 0x01 // control register 2
+#define LCD_REG_ADDR_X 0x02 // x address register
+#define LCD_REG_ADDR_Y 0x03 // y address register
+#define LCD_REG_RAM 0x04 // display ram access register
+#define LCD_REG_START_Y 0x05 // display start line register
+#define LCD_REG_BLINK_START 0x06 // blink start line register
+#define LCD_REG_BLINK_END 0x07 // blink end line register
+#define LCD_REG_BLINK_1 0x08 // blink register 1
+#define LCD_REG_BLINK_2 0x09 // blink register 2
+#define LCD_REG_BLINK_3 0x0A // blink register 3
+#define LCD_REG_PARTIAL 0x0B // partial display block register
+#define LCD_REG_COLOR_1 0x0C // gray scale palette 1 (0,0)
+#define LCD_REG_COLOR_2 0x0D // gray scale palette 2 (0,1)
+#define LCD_REG_COLOR_3 0x0E // gray scale palette 3 (1,0)
+#define LCD_REG_COLOR_4 0x0F // gray scale palette 4 (1,1)
+#define LCD_REG_CONTRAST 0x10 // contrast control register
+#define LCD_REG_PLANE 0x11 // plane selection register
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type HD66421 = &device_creator<hd66421_device>;
+
+
+// default address map
+static ADDRESS_MAP_START( hd66421, AS_0, 8, hd66421_device )
+ AM_RANGE(0x0000, HD66421_RAM_SIZE) AM_RAM
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *hd66421_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 hd66421_device::readbyte(offs_t address)
+{
+ return space()->read_byte(address);
+}
+
+
+//-------------------------------------------------
+// writebyte - write a byte at the given address
+//-------------------------------------------------
+
+inline void hd66421_device::writebyte(offs_t address, UINT8 data)
+{
+ space()->write_byte(address, data);
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// hd66421_device - constructor
+//-------------------------------------------------
+
+hd66421_device::hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, HD66421, "Hitachi HD66421 LCD Controller", tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(hd66421)),
+ m_cmd(0),
+ m_x(0),
+ m_y(0)
+{
+ for (int i = 0; i < 32; i++)
+ {
+ m_reg[i] = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void hd66421_device::device_start()
+{
+ // register for state saving
+ save_item(NAME(m_cmd));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_x));
+ save_item(NAME(m_y));
+}
+
+READ8_MEMBER( hd66421_device::reg_idx_r )
+{
+ _logerror( 2, ("reg_idx_r\n"));
+ return m_cmd;
+}
+
+WRITE8_MEMBER( hd66421_device::reg_idx_w )
+{
+ _logerror( 2, ("reg_idx_w (%02X)\n", data));
+ m_cmd = data;
+}
+
+READ8_MEMBER( hd66421_device::reg_dat_r )
+{
+ _logerror( 2, ("reg_dat_r\n"));
+ return m_reg[m_cmd];
+}
+
+WRITE8_MEMBER( hd66421_device::reg_dat_w )
+{
+ _logerror( 2, ("reg_dat_w (%02X)\n", data));
+ m_reg[m_cmd] = data;
+
+ switch (m_cmd)
+ {
+ case LCD_REG_ADDR_X :
+ m_x = data;
+ break;
+
+ case LCD_REG_ADDR_Y :
+ m_y = data;
+ break;
+
+ case LCD_REG_RAM :
+ {
+ UINT8 r1;
+ writebyte(m_y * (HD66421_WIDTH / 4) + m_x, data);
+ r1 = m_reg[LCD_REG_CONTROL_2];
+ if (r1 & 0x02)
+ m_x++;
+ else
+ m_y++;
+
+ if (m_x >= (HD66421_WIDTH / 4))
+ {
+ m_x = 0;
+ m_y++;
+ }
+
+ if (m_y >= HD66421_HEIGHT)
+ m_y = 0;
+ }
+ break;
+ }
+}
+
+void hd66421_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = (UINT16)color;
+}
+
+void hd66421_device::update_screen(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ pen_t pen[4];
+
+ _logerror( 1, ("video_update_hd66421\n"));
+
+ // update palette
+ for (int i = 0; i < 4; i++)
+ {
+ double bright;
+ int temp;
+ temp = 31 - (m_reg[LCD_REG_COLOR_1 + i] - m_reg[LCD_REG_CONTRAST] + 0x03);
+ if (temp < 0) temp = 0;
+ if (temp > 31) temp = 31;
+ bright = 1.0 * temp / 31;
+ pen[i] = i;
+ #ifdef HD66421_BRIGHTNESS_DOES_NOT_WORK
+ palette_set_color(machine(), pen[i], 255 * bright, 255 * bright, 255 * bright);
+ #else
+ palette_set_pen_contrast(machine(), pen[i], bright);
+ #endif
+ }
+
+ // draw bitmap (bottom to top)
+ if (m_reg[0] & LCD_R0_DISP)
+ {
+ int x, y;
+ x = 0;
+ y = HD66421_HEIGHT - 1;
+
+ for (int i = 0; i < HD66421_RAM_SIZE; i++)
+ {
+ plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 6) & 3]);
+ plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 4) & 3]);
+ plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 2) & 3]);
+ plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 0) & 3]);
+ if (x >= HD66421_WIDTH)
+ {
+ x = 0;
+ y = y - 1;
+ }
+ }
+ }
+ else
+ {
+ rectangle rect(0, HD66421_WIDTH - 1, 0, HD66421_HEIGHT - 1);
+ bitmap.fill(get_white_pen(machine()), rect);
+ }
+}
diff --git a/src/mess/video/hd66421.h b/src/mess/video/hd66421.h
new file mode 100644
index 00000000000..ce23f75e75d
--- /dev/null
+++ b/src/mess/video/hd66421.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+
+ Hitachi HD66421 LCD Controller
+
+ (c) 2001-2007 Tim Schuerewegen
+
+ ***************************************************************************/
+
+#pragma once
+
+#ifndef __HD66421_H__
+#define __HD66421_H__
+
+
+///*************************************************************************
+// MACROS / CONSTANTS
+///*************************************************************************
+
+//#define HD66421_BRIGHTNESS_DOES_NOT_WORK
+
+#define HD66421_WIDTH 160
+#define HD66421_HEIGHT 100
+
+
+/*----------- defined in video/hd66421.c -----------*/
+
+///*************************************************************************
+// INTERFACE CONFIGURATION MACROS
+///*************************************************************************
+
+#define MCFG_HD66421_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, HD66421, 0) \
+
+
+///*************************************************************************
+// TYPE DEFINITIONS
+///*************************************************************************
+
+// ======================> hd66421_device
+
+class hd66421_device : public device_t,
+ public device_memory_interface
+{
+public:
+ // construction/destruction
+ hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( reg_idx_r );
+ DECLARE_WRITE8_MEMBER( reg_idx_w );
+ DECLARE_READ8_MEMBER( reg_dat_r );
+ DECLARE_WRITE8_MEMBER( reg_dat_w );
+
+ void update_screen(bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+
+ inline UINT8 readbyte(offs_t address);
+ inline void writebyte(offs_t address, UINT8 data);
+
+ void plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color);
+
+private:
+ UINT8 m_cmd, m_reg[32];
+ int m_x, m_y;
+};
+
+
+// device type definition
+extern const device_type HD66421;
+
+
+#endif
diff --git a/src/mess/video/hec2video.c b/src/mess/video/hec2video.c
new file mode 100644
index 00000000000..504e6de1f07
--- /dev/null
+++ b/src/mess/video/hec2video.c
@@ -0,0 +1,144 @@
+/////////////////////////////////////////////////////////////////////////////////
+///// Hector video
+/////////////////////////////////////////////////////////////////////////////////
+/* Hector 2HR+
+ Victor
+ Hector 2HR
+ Hector HRX
+ Hector MX40c
+ Hector MX80c
+ Hector 1
+ Interact
+
+ 12/05/2009 Skeleton driver - Micko : mmicko@gmail.com
+ 31/06/2009 Video - Robbbert
+
+ 29/10/2009 Update skeleton to functional machine
+ by yo_fr (jj.stac @ aliceadsl.fr)
+
+ => add Keyboard,
+ => add color,
+ => add cassette,
+ => add sn76477 sound and 1bit sound,
+ => add joysticks (stick, pot, fire)
+ => add BR/HR switching
+ => add bank switch for HRX
+ => add device MX80c and bank switching for the ROM
+ Importante note : the keyboard function add been piked from
+ DChector project : http://dchector.free.fr/ made by DanielCoulom
+ (thank's Daniel)
+ TODO : Add the cartridge function,
+ Adjust the one shot and A/D timing (sn76477)
+*/
+
+#include "emu.h"
+#include "sound/sn76477.h" // for sn sound
+
+#include "includes/hec2hrp.h"
+
+
+static void Init_Hector_Palette( running_machine &machine)
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+ UINT8 *hector_color = state->m_hector_color;
+ // basic colors !
+ hector_color[0] = 0; // fond (noir)
+ hector_color[1] = 1; // HECTOR HRX (rouge)
+ hector_color[2] = 7; // Point interrogation (Blanc)
+ hector_color[3] = 3; // Ecriture de choix (jaune)
+
+ // Color initialisation : full lightning
+ palette_set_color( machine, 0,MAKE_RGB(000,000,000));//Noir
+ palette_set_color( machine, 1,MAKE_RGB(255,000,000));//Rouge
+ palette_set_color( machine, 2,MAKE_RGB(000,255,000));//Vert
+ palette_set_color( machine, 3,MAKE_RGB(255,255,000));//Jaune
+ palette_set_color( machine, 4,MAKE_RGB(000,000,255));//Bleu
+ palette_set_color( machine, 5,MAKE_RGB(255,000,255));//Magneta
+ palette_set_color( machine, 6,MAKE_RGB(000,255,255));//Cyan
+ palette_set_color( machine, 7,MAKE_RGB(255,255,255));//Blanc
+ // 1/2 lightning
+
+ palette_set_color( machine, 8,MAKE_RGB(000,000,000));//Noir
+ palette_set_color( machine, 9,MAKE_RGB(128,000,000));//Rouge
+ palette_set_color( machine,10,MAKE_RGB(000,128,000));//Vert
+ palette_set_color( machine,11,MAKE_RGB(128,128,000));//Jaune
+ palette_set_color( machine,12,MAKE_RGB(000,000,128));//Bleu
+ palette_set_color( machine,13,MAKE_RGB(128,000,128));//Magneta
+ palette_set_color( machine,14,MAKE_RGB(000,128,128));//Cyan
+ palette_set_color( machine,15,MAKE_RGB(128,128,128));//Blanc
+}
+
+void hector_hr(running_machine &machine, bitmap_ind16 &bitmap, UINT8 *page, int ymax, int yram)
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+ UINT8 *hector_color = state->m_hector_color;
+ UINT8 gfx,y;
+ UINT16 sy=0,ma=0,x;
+ for (y = 0; y <= ymax; y++) { //224
+ UINT16 *p = &bitmap.pix16(sy++);
+ for (x = ma; x < ma + yram; x++) { // 64
+ gfx = *(page+x);
+ /* Display a scanline of a character (4 pixels !) */
+ *p++ = hector_color[(gfx >> 0) & 0x03];
+ *p++ = hector_color[(gfx >> 2) & 0x03];
+ *p++ = hector_color[(gfx >> 4) & 0x03];
+ *p++ = hector_color[(gfx >> 6) & 0x03];
+ }
+ ma+=yram;
+ }
+}
+
+void hector_80c(running_machine &machine, bitmap_ind16 &bitmap, UINT8 *page, int ymax, int yram)
+{
+ UINT8 gfx,y;
+ UINT16 sy=0,ma=0,x;
+ for (y = 0; y <= ymax; y++) { //224
+ UINT16 *p = &bitmap.pix16(sy++);
+ for (x = ma; x < ma + yram; x++) { // 64
+ gfx = *(page+x);
+ /* Display a scanline of a character (8 pixels !) */
+ *p++ = (gfx & 0x01) ? 7 : 0;
+ *p++ = (gfx & 0x02) ? 7 : 0;
+ *p++ = (gfx & 0x04) ? 7 : 0;
+ *p++ = (gfx & 0x08) ? 7 : 0;
+ *p++ = (gfx & 0x10) ? 7 : 0;
+ *p++ = (gfx & 0x20) ? 7 : 0;
+ *p++ = (gfx & 0x40) ? 7 : 0;
+ *p++ = (gfx & 0x80) ? 7 : 0;
+ }
+ ma+=yram;
+ }
+}
+
+
+VIDEO_START( hec2hrp )
+{
+ Init_Hector_Palette(machine);
+}
+
+SCREEN_UPDATE_IND16( hec2hrp )
+{
+ hec2hrp_state *state = screen.machine().driver_data<hec2hrp_state>();
+ UINT8 *videoram = state->m_videoram;
+ UINT8 *videoram_HR = state->m_hector_videoram;
+ if (state->m_hector_flag_hr==1)
+ {
+ if (state->m_hector_flag_80c==0)
+ {
+ screen.set_visible_area(0, 243, 0, 227);
+ hector_hr( screen.machine(), bitmap , &videoram_HR[0], 227, 64);
+ }
+ else
+ {
+ screen.set_visible_area(0, 243*2, 0, 227);
+ hector_80c( screen.machine(), bitmap , &videoram_HR[0], 227, 64);
+ }
+ }
+ else
+ {
+ screen.set_visible_area(0, 113, 0, 75);
+ hector_hr( screen.machine(), bitmap, videoram, 77, 32);
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/hp48.c b/src/mess/video/hp48.c
new file mode 100644
index 00000000000..913e4576062
--- /dev/null
+++ b/src/mess/video/hp48.c
@@ -0,0 +1,202 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2008
+
+ Hewlett Packard HP48 S/SX & G/GX/G+
+
+**********************************************************************/
+
+#include "emu.h"
+#include "includes/hp48.h"
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+
+#define VERBOSE 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES & CONSTANTS
+***************************************************************************/
+
+/* base colors */
+static const int hp48_bg_color[3] = { 136, 147, 109 }; /* yellow */
+static const int hp48_fg_color[3] = { 0, 0, 64 }; /* dark blue */
+
+/* color mixing */
+#define mix(c1,c2,x) (c1)*(1-(x))+(c2)*(x)
+#define mix2(i,x) mix(hp48_bg_color[i],hp48_fg_color[i],x)
+
+
+
+
+/***************************************************************************
+ FUNCTIONS
+***************************************************************************/
+
+PALETTE_INIT ( hp48 )
+{
+ int i;
+ for ( i = 0; i < 255; i++ )
+ {
+ float c = i/255.;
+ palette_set_color( machine, i, MAKE_ARGB( 0, mix2(0,c), mix2(1,c), mix2(2,c) ) );
+ }
+}
+
+
+
+/* The screen is organised as follows:
+
+
+
+ announciators
+
+ ---------------------- ^ ^
+ | | | |
+ | | | |
+ | | | |
+ | | M lines |
+ | main screen | | |
+ | | | |
+ | | | 64 lines
+ | | | |
+ | | | |
+ |----------------------| - |
+ | | | |
+ | menu | m lines |
+ | | | |
+ ---------------------- v v
+
+ <----- 131 columns ---->
+
+
+
+ The LCD is 131x64 pixels and has two components:
+ - a main screen
+ - a menu screen
+
+ The main height (M) and the menu height (m) can be changed with the constraints:
+ - m+M=64
+ - M>=2
+
+ Pixels are 1-bit, packed in memory.
+
+ The start address of both screens can be changed independently
+ (this allows smooth, pixel-precise vertical scrooling of both parts).
+ They must be even addresses (in nibbles).
+
+ The stride (offset in nibbles between two scanlines) can be changed for the main screen.
+ It must be even.
+ It is fixed to 34 for the menu screen.
+
+ The bit offset for the first column of the main screen can be changed
+ (this allows smooth, pixel-precise horizontal scrooling).
+ It is always 0 for the menu screen.
+
+ Above the LCD, there are 6 annonciators that can be independently turned
+ on and off (and independetly from the LCD).
+ They are not handled here, but through output_set_value.
+ */
+
+
+/*
+ In theory, the LCD is monorchrome, with a global adjustable contrast (32 levels).
+ However, by switching between screens at each refresh (64 Hz), one can achieve the
+ illusion of grayscale, with moderate flickering.
+ This technique was very widespread.
+ We emulate it by simply averaging between the last few (HP48_NB_SCREENS) frames.
+
+ HP48_NB_SCREENS should be a multiple of the period of screen flips to avoid
+ flickering in the emulation.
+ */
+
+
+#define draw_pixel \
+ state->m_screens[ state->m_cur_screen ][ y ][ xp + 8 ] = (data & 1) ? fg : 0; \
+ xp++; \
+ data >>= 1
+
+#define draw_quart \
+ UINT8 data = space->read_byte( addr ); \
+ draw_pixel; draw_pixel; draw_pixel; draw_pixel;
+
+
+SCREEN_UPDATE_IND16 ( hp48 )
+{
+ hp48_state *state = screen.machine().driver_data<hp48_state>();
+ address_space *space = screen.machine().device("maincpu")->memory().space(AS_PROGRAM);
+ int x, y, xp, i, addr;
+ int display = HP48_IO_4(0) >> 3; /* 1=on, 0=off */
+ int left_margin = HP48_IO_4(0) & 7; /* 0..7 pixels for main bitmap */
+ int contrast = HP48_IO_8(1) & 0x1f; /* 0..31 */
+ int refresh = HP48_IO_4(3) >> 3; /* vertical refresh */
+ int bitmap_start = HP48_IO_20(0x20) & ~1; /* main bitmap address */
+ int right_margin = HP48_IO_12(0x25) & ~1; /* -2048..2046 nibbles for main bitmap */
+ int last_line = HP48_IO_8(0x28) & 0x3f; /* 2..63 lines of main bitmap before menu */
+ int menu_start = HP48_IO_20(0x30) & ~1; /* menu bitmap address */
+ int fg = contrast + 2;
+
+ LOG(( "%f hp48 video_update called: ", screen.machine().time().as_double()));
+
+ if ( !display || refresh )
+ {
+ LOG(( "display off\n" ));
+ bitmap.fill(0 );
+ return 0;
+ }
+
+ /* correcting factors */
+ if ( right_margin & 0x800 ) right_margin -= 0x1000;
+ if ( last_line <= 1 ) last_line = 0x3f;
+
+ LOG(( "on=%i lmargin=%i rmargin=%i contrast=%i start=%05x lline=%i menu=%05x\n",
+ display, left_margin, right_margin, contrast, bitmap_start, last_line, menu_start ));
+
+ /* draw main bitmap */
+ addr = bitmap_start;
+ for ( y = 0; y <= last_line; y++ )
+ {
+ xp = -left_margin;
+ for ( x = 0; x < 34; x++, addr++ )
+ {
+ draw_quart;
+ }
+ addr += (right_margin + (left_margin / 4) + 1) & ~1;
+ }
+
+ /* draw menu bitmap */
+ addr = menu_start;
+ for ( ; y <= 0x3f; y++ )
+ {
+ xp = 0;
+ for ( x = 0; x < 34; x++, addr++ )
+ {
+ draw_quart;
+ }
+ }
+
+ /* draw averaged frames */
+ for ( y = 0; y < 64; y++ )
+ {
+ for ( x = 0; x < 131; x++ )
+ {
+ int acc = 0;
+ for ( i = 0; i < HP48_NB_SCREENS; i++ )
+ {
+ acc += state->m_screens[ i ][ y ][ x+8 ];
+ }
+ acc = (acc * 255) / (33 * HP48_NB_SCREENS);
+ bitmap.pix16(y, x ) = acc;
+ }
+ }
+
+ state->m_cur_screen = (state->m_cur_screen + 1) % HP48_NB_SCREENS;
+
+ return 0;
+}
diff --git a/src/mess/video/intv.c b/src/mess/video/intv.c
new file mode 100644
index 00000000000..a91f9584f87
--- /dev/null
+++ b/src/mess/video/intv.c
@@ -0,0 +1,855 @@
+#include "emu.h"
+#include "video/stic.h"
+#include "includes/intv.h"
+
+#define FOREGROUND_BIT 0x0010
+
+// conversion from Intellivision color to internal representation
+#define SET_COLOR(c) ((c * 2) + 1)
+#define GET_COLOR(c) ((c - 1) / 2)
+
+/* initialized to non-zero, because we divide by it */
+
+INLINE void intv_set_pixel(intv_state *state, bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ int w, h;
+
+ // output scaling
+ x *= state->m_x_scale;
+ y *= state->m_y_scale;
+ color = SET_COLOR(color);
+
+ for (h = 0; h < state->m_y_scale; h++)
+ for (w = 0; w < state->m_x_scale; w++)
+ bitmap.pix16(y + h, x + w) = color;
+}
+
+INLINE UINT32 intv_get_pixel(intv_state *state, bitmap_ind16 &bitmap, int x, int y)
+{
+ return GET_COLOR(bitmap.pix16(y * state->m_y_scale, x * state->m_x_scale));
+}
+
+INLINE void intv_plot_box(intv_state *state, bitmap_ind16 &bm, int x, int y, int w, int h, int color)
+{
+ bm.plot_box(x * state->m_x_scale, y * state->m_y_scale, w * state->m_x_scale, h * state->m_y_scale, SET_COLOR(color));
+}
+
+VIDEO_START( intv )
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ //int i,j,k;
+
+ state->m_tms9927_num_rows = 25;
+
+ machine.primary_screen->register_screen_bitmap(state->m_bitmap);
+
+#if 0
+ for (i = 0; i < STIC_MOBS; i++)
+ {
+ intv_sprite_type* s = &state->m_sprite[i];
+ s->visible = 0;
+ s->xpos = 0;
+ s->ypos = 0;
+ s->coll = 0;
+ s->collision = 0;
+ s->doublex = 0;
+ s->doubley = 0;
+ s->quady = 0;
+ s->xflip = 0;
+ s->yflip = 0;
+ s->behind_foreground = 0;
+ s->grom = 0;
+ s->card = 0;
+ s->color = 0;
+ s->doubleyres = 0;
+ s->dirty = 1;
+ for (j = 0; j < 16; j++)
+ {
+ for (k = 0; k < 128; k++)
+ {
+ state->m_sprite_buffers[i][j][k] = 0;
+ }
+ }
+ }
+ for(i = 0; i < STIC_REGISTERS; i++)
+ {
+ state->m_stic_registers[i] = 0;
+ }
+ state->m_color_stack_mode = 0;
+ state->m_color_stack_offset = 0;
+ state->m_stic_handshake = 0;
+ state->m_border_color = 0;
+ state->m_col_delay = 0;
+ state->m_row_delay = 0;
+ state->m_left_edge_inhibit = 0;
+ state->m_top_edge_inhibit = 0;
+
+ state->m_gramdirty = 1;
+ for(i=0;i<64;i++)
+ {
+ state->m_gram[i] = 0;
+ state->m_gramdirtybytes[i] = 1;
+ }
+#endif
+}
+
+
+static int sprites_collide(intv_state *state, int spriteNum1, int spriteNum2)
+{
+ INT16 x0, y0, w0, h0, x1, y1, w1, h1, x2, y2, w2, h2;
+
+ intv_sprite_type* s1 = &state->m_sprite[spriteNum1];
+ intv_sprite_type* s2 = &state->m_sprite[spriteNum2];
+
+ x0 = STIC_OVERSCAN_LEFT_WIDTH + state->m_col_delay - STIC_CARD_WIDTH;
+ y0 = STIC_OVERSCAN_TOP_HEIGHT + state->m_row_delay - STIC_CARD_HEIGHT;
+ x1 = (s1->xpos + x0) * STIC_X_SCALE; y1 = (s1->ypos + y0) * STIC_Y_SCALE;
+ x2 = (s2->xpos + x0) * STIC_X_SCALE; y2 = (s2->ypos + y0) * STIC_Y_SCALE;
+ w1 = (s1->doublex ? 2 : 1) * STIC_CARD_WIDTH;
+ w2 = (s2->doublex ? 2 : 1) * STIC_CARD_WIDTH;
+ h1 = (s1->quady ? 4 : 1) * (s1->doubley ? 2 : 1) * (s1->doubleyres ? 2 : 1) * STIC_CARD_HEIGHT;
+ h2 = (s2->quady ? 4 : 1) * (s2->doubley ? 2 : 1) * (s2->doubleyres ? 2 : 1) * STIC_CARD_HEIGHT;
+
+ if ((x1 >= x2 + w2) || (y1 >= y2 + h2) ||
+ (x2 >= x1 + w1) || (y2 >= y1 + h1))
+ return FALSE;
+
+ // iterate over the intersecting bits to see if any touch
+ x0 = MAX(x1, x2);
+ y0 = MAX(y1, y2);
+ w0 = MIN(x1 + w1, x2 + w2) - x0;
+ h0 = MIN(y1 + h1, y2 + h2) - y0;
+ x1 = x0 - x1;
+ y1 = y0 - y1;
+ x2 = x0 - x2;
+ y2 = y0 - y2;
+ for (x0 = 0; x0 < w0; x0++)
+ {
+ for (y0 = 0; y0 < h0; y0++)
+ {
+ if (state->m_sprite_buffers[spriteNum1][x0 + x1][y0 + y1] &&
+ state->m_sprite_buffers[spriteNum2][x0 + x2][y0 + y2])
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void determine_sprite_collisions(intv_state *state)
+{
+ // check sprite to sprite collisions
+ int i, j;
+ for (i = 0; i < STIC_MOBS - 1; i++)
+ {
+ intv_sprite_type* s1 = &state->m_sprite[i];
+ if (s1->xpos == 0 || !s1->coll)
+ continue;
+
+ for (j = i + 1; j < STIC_MOBS; j++)
+ {
+ intv_sprite_type* s2 = &state->m_sprite[j];
+ if (s2->xpos == 0 || !s2->coll)
+ continue;
+
+ if (sprites_collide(state, i, j))
+ {
+ s1->collision |= (1 << j);
+ s2->collision |= (1 << i);
+ }
+ }
+ }
+}
+
+static void render_sprites(running_machine &machine)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ INT32 cardMemoryLocation, pixelSize;
+ INT32 spritePixelHeight;
+ INT32 nextMemoryLocation;
+ INT32 nextData;
+ INT32 nextX;
+ INT32 nextY;
+ INT32 xInc;
+ INT32 i, j, k;
+
+ UINT8* memory = state->memregion("maincpu")->base();
+
+ for (i = 0; i < STIC_MOBS; i++)
+ {
+ intv_sprite_type* s = &state->m_sprite[i];
+
+ if (s->grom)
+ cardMemoryLocation = (s->card * STIC_CARD_HEIGHT);
+ else
+ cardMemoryLocation = ((s->card & 0x003F) * STIC_CARD_HEIGHT);
+
+ pixelSize = (s->quady ? 4 : 1) * (s->doubley ? 2 : 1);
+ spritePixelHeight = pixelSize * (s->doubleyres ? 2 : 1) * STIC_CARD_HEIGHT;
+
+ for (j = 0; j < spritePixelHeight; j++)
+ {
+ nextMemoryLocation = (cardMemoryLocation + (j/pixelSize));
+ if (s->grom)
+ nextData = memory[(0x3000+nextMemoryLocation)<<1];
+ else if (nextMemoryLocation < 0x200)
+ nextData = state->m_gram[nextMemoryLocation];
+ else
+ nextData = 0xFFFF;
+ nextX = (s->xflip ? ((s->doublex ? 2 : 1) * STIC_CARD_WIDTH - 1) : 0);
+ nextY = (s->yflip ? (spritePixelHeight - j - 1) : j);
+ xInc = (s->xflip ? -1: 1);
+
+ for (k = 0; k < STIC_CARD_WIDTH * (1 + s->doublex); k++)
+ {
+ state->m_sprite_buffers[i][nextX + k * xInc][nextY] = (nextData & (1 << ((STIC_CARD_WIDTH - 1) - k / (1 + s->doublex)))) != 0;
+ }
+ }
+ }
+}
+
+static void render_line(running_machine &machine, bitmap_ind16 &bitmap,
+ UINT8 nextByte, UINT16 x, UINT16 y, UINT8 fgcolor, UINT8 bgcolor)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ UINT32 color;
+ UINT8 i;
+
+ for (i = 0; i < STIC_CARD_WIDTH; i++)
+ {
+ color = (nextByte & (1 << ((STIC_CARD_WIDTH - 1) - i)) ? fgcolor : bgcolor);
+ intv_set_pixel(state, bitmap, x+i, y, color);
+ intv_set_pixel(state, bitmap, x+i, y+1, color);
+ }
+}
+
+static void render_colored_squares(running_machine &machine, bitmap_ind16 &bitmap,
+ UINT16 x, UINT16 y, UINT8 color0, UINT8 color1, UINT8 color2, UINT8 color3)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+
+ intv_plot_box(state, bitmap, x, y, STIC_CSQM_WIDTH * STIC_X_SCALE, STIC_CSQM_HEIGHT * STIC_Y_SCALE, color0);
+ intv_plot_box(state, bitmap, x + STIC_CSQM_WIDTH * STIC_X_SCALE, y, STIC_CSQM_WIDTH * STIC_X_SCALE, STIC_CSQM_HEIGHT * STIC_Y_SCALE, color1);
+ intv_plot_box(state, bitmap, x, y + STIC_CSQM_HEIGHT * STIC_Y_SCALE, STIC_CSQM_WIDTH * STIC_X_SCALE, STIC_CSQM_HEIGHT * STIC_Y_SCALE, color2);
+ intv_plot_box(state, bitmap, x + STIC_CSQM_WIDTH * STIC_X_SCALE, y + STIC_CSQM_HEIGHT * STIC_Y_SCALE, STIC_CSQM_WIDTH * STIC_X_SCALE, STIC_CSQM_HEIGHT * STIC_Y_SCALE, color3);
+}
+
+static void render_color_stack_mode(running_machine &machine, bitmap_ind16 &bitmap)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ INT16 w, h, nextx, nexty;
+ UINT8 csPtr = 0;
+ UINT16 nextCard;
+ UINT8 *ram = state->memregion("maincpu")->base();
+
+ for (h = 0, nexty = (STIC_OVERSCAN_TOP_HEIGHT + state->m_row_delay) * STIC_Y_SCALE;
+ h < STIC_BACKTAB_HEIGHT;
+ h++, nexty += STIC_CARD_HEIGHT * STIC_Y_SCALE)
+ {
+ for (w = 0, nextx = (STIC_OVERSCAN_LEFT_WIDTH + state->m_col_delay) * STIC_X_SCALE;
+ w < STIC_BACKTAB_WIDTH;
+ w++, nextx += STIC_CARD_WIDTH * STIC_X_SCALE)
+ {
+ nextCard = state->m_backtab_buffer[h][w];
+
+ // colored squares mode
+ if ((nextCard & (STIC_CSTM_FG3|STIC_CSTM_SEL)) == STIC_CSTM_FG3)
+ {
+ UINT8 csColor = state->m_stic_registers[STIC_CSR + csPtr];
+ UINT8 color0 = nextCard & STIC_CSQM_A;
+ UINT8 color1 = (nextCard & STIC_CSQM_B) >> 3;
+ UINT8 color2 = (nextCard & STIC_CSQM_C) >> 6;
+ UINT8 color3 = ((nextCard & STIC_CSQM_D2) >> 11) |
+ ((nextCard & (STIC_CSQM_D10)) >> 9);
+ render_colored_squares(machine, bitmap, nextx, nexty,
+ (color0 == 7 ? csColor : (color0 | FOREGROUND_BIT)),
+ (color1 == 7 ? csColor : (color1 | FOREGROUND_BIT)),
+ (color2 == 7 ? csColor : (color2 | FOREGROUND_BIT)),
+ (color3 == 7 ? csColor : (color3 | FOREGROUND_BIT)));
+ }
+ //color stack mode
+ else
+ {
+ UINT8 isGrom, j;
+ UINT16 memoryLocation, fgcolor, bgcolor;
+ UINT8* memory;
+
+ //advance the color pointer, if necessary
+ if (nextCard & STIC_CSTM_ADV)
+ csPtr = (csPtr+1) & (STIC_CSRS - 1);
+
+ fgcolor = ((nextCard & STIC_CSTM_FG3) >> 9) |
+ (nextCard & (STIC_CSTM_FG20)) | FOREGROUND_BIT;
+ bgcolor = state->m_stic_registers[STIC_CSR + csPtr] & STIC_CSR_BG;
+
+ isGrom = !(nextCard & STIC_CSTM_SEL);
+ if (isGrom)
+ {
+ memoryLocation = 0x3000 + (nextCard & STIC_CSTM_C);
+ memory = ram;
+ for (j = 0; j < STIC_CARD_HEIGHT; j++)
+ render_line(machine, bitmap, memory[(memoryLocation + j) * 2],
+ nextx, nexty + j * STIC_Y_SCALE, fgcolor, bgcolor);
+ }
+ else
+ {
+ memoryLocation = (nextCard & STIC_CSTM_C50);
+ memory = state->m_gram;
+ for (j = 0; j < STIC_CARD_HEIGHT; j++)
+ render_line(machine, bitmap, memory[memoryLocation + j],
+ nextx, nexty + j * STIC_Y_SCALE, fgcolor, bgcolor);
+ }
+ }
+ }
+ }
+}
+
+static void render_fg_bg_mode(running_machine &machine, bitmap_ind16 &bitmap)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ INT16 w, h, nextx, nexty;
+ UINT8 j, isGrom, fgcolor, bgcolor;
+ UINT16 nextCard, memoryLocation;
+ UINT8* memory;
+ UINT8* ram = state->memregion("maincpu")->base();
+
+ for (h = 0, nexty = (STIC_OVERSCAN_TOP_HEIGHT + state->m_row_delay) * STIC_Y_SCALE;
+ h < STIC_BACKTAB_HEIGHT;
+ h++, nexty += STIC_CARD_HEIGHT * STIC_Y_SCALE)
+ {
+ for (w = 0, nextx = (STIC_OVERSCAN_LEFT_WIDTH + state->m_col_delay) * STIC_X_SCALE;
+ w < STIC_BACKTAB_WIDTH;
+ w++, nextx += STIC_CARD_WIDTH * STIC_X_SCALE)
+ {
+ nextCard = state->m_backtab_buffer[h][w];
+ fgcolor = (nextCard & STIC_FBM_FG) | FOREGROUND_BIT;
+ bgcolor = ((nextCard & STIC_FBM_BG2) >> 11) |
+ ((nextCard & STIC_FBM_BG310) >> 9);
+
+ isGrom = !(nextCard & STIC_FBM_SEL);
+ if (isGrom)
+ {
+ memoryLocation = 0x3000 + (nextCard & STIC_FBM_C);
+ memory = ram;
+ for (j = 0; j < STIC_CARD_HEIGHT; j++)
+ render_line(machine, bitmap, memory[(memoryLocation + j) * 2],
+ nextx, nexty + j * STIC_Y_SCALE, fgcolor, bgcolor);
+ }
+ else
+ {
+ memoryLocation = (nextCard & STIC_FBM_C);
+ memory = state->m_gram;
+ for (j = 0; j < STIC_CARD_HEIGHT; j++)
+ render_line(machine, bitmap, memory[memoryLocation + j],
+ nextx, nexty + j * STIC_Y_SCALE, fgcolor, bgcolor);
+ }
+ }
+ }
+}
+
+static void copy_sprites_to_background(running_machine &machine, bitmap_ind16 &bitmap)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ UINT8 width, currentPixel;
+ UINT8 borderCollision, foregroundCollision;
+ UINT8 spritePixelHeight, x, y;
+ INT16 leftX, nextY, i;
+ INT16 leftBorder, rightBorder, topBorder, bottomBorder;
+ INT32 nextX;
+
+ for (i = STIC_MOBS - 1; i >= 0; i--)
+ {
+ intv_sprite_type *s = &state->m_sprite[i];
+ if (s->xpos == 0 || (!s->coll && !s->visible))
+ continue;
+
+ borderCollision = FALSE;
+ foregroundCollision = FALSE;
+
+ spritePixelHeight = (s->quady ? 4 : 1) * (s->doubley ? 2 : 1) * (s->doubleyres ? 2 : 1) * STIC_CARD_HEIGHT;
+ width = (s->doublex ? 2 : 1) * STIC_CARD_WIDTH;
+
+ leftX = (s->xpos - STIC_CARD_WIDTH + STIC_OVERSCAN_LEFT_WIDTH + state->m_col_delay) * STIC_X_SCALE;
+ nextY = (s->ypos - STIC_CARD_HEIGHT + STIC_OVERSCAN_TOP_HEIGHT + state->m_row_delay) * STIC_Y_SCALE;
+
+ leftBorder = (STIC_OVERSCAN_LEFT_WIDTH + (state->m_left_edge_inhibit ? STIC_CARD_WIDTH : 0)) * STIC_X_SCALE;
+ rightBorder = (STIC_OVERSCAN_LEFT_WIDTH + STIC_BACKTAB_WIDTH * STIC_CARD_WIDTH - 1 - 1) * STIC_X_SCALE;
+ topBorder = (STIC_OVERSCAN_TOP_HEIGHT + (state->m_top_edge_inhibit ? STIC_CARD_HEIGHT : 0)) * STIC_Y_SCALE;
+ bottomBorder = (STIC_OVERSCAN_TOP_HEIGHT + STIC_BACKTAB_HEIGHT * STIC_CARD_HEIGHT) * STIC_Y_SCALE - 1;
+
+ for (y = 0; y < spritePixelHeight; y++)
+ {
+ for (x = 0; x < width; x++)
+ {
+ //if this sprite pixel is not on, then don't paint it
+ if (!state->m_sprite_buffers[i][x][y])
+ continue;
+
+ nextX = leftX + x;
+ //if the next pixel location is on the border, then we
+ //have a border collision and we can ignore painting it
+ if ((nextX < leftBorder) || (nextX > rightBorder) ||
+ (nextY < topBorder) || (nextY > bottomBorder))
+ {
+ borderCollision = TRUE;
+ continue;
+ }
+
+ currentPixel = intv_get_pixel(state, bitmap, nextX, nextY);
+
+ //check for foreground collision
+ if (currentPixel & FOREGROUND_BIT)
+ {
+ foregroundCollision = TRUE;
+ if (s->behind_foreground)
+ continue;
+ }
+
+ if (s->visible)
+ {
+ intv_set_pixel(state, bitmap, nextX, nextY, s->color | (currentPixel & FOREGROUND_BIT));
+ }
+ }
+ nextY++;
+ }
+
+ //update the collision bits
+ if (s->coll)
+ {
+ if (foregroundCollision)
+ s->collision |= STIC_MCR_BKGD;
+ if (borderCollision)
+ s->collision |= STIC_MCR_BRDR;
+ }
+ }
+}
+
+static void render_background(running_machine &machine, bitmap_ind16 &bitmap)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ if (state->m_color_stack_mode)
+ render_color_stack_mode(machine, bitmap);
+ else
+ render_fg_bg_mode(machine, bitmap);
+}
+
+#ifdef UNUSED_CODE
+static void draw_background(running_machine &machine, bitmap_ind16 &bitmap, int transparency)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ // First, draw the background
+ int offs = 0;
+ int value = 0;
+ int row,col;
+ int fgcolor,bgcolor = 0;
+ int code;
+
+ int colora, colorb, colorc, colord;
+
+ int n_bit;
+ int p_bit;
+ int g_bit;
+
+ int j;
+
+ int x0 = STIC_OVERSCAN_LEFT_WIDTH + state->m_col_delay;
+ int y0 = STIC_OVERSCAN_TOP_HEIGHT + state->m_row_delay;
+
+ if (state->m_color_stack_mode == 1)
+ {
+ state->m_color_stack_offset = 0;
+ for(row = 0; row < STIC_BACKTAB_HEIGHT; row++)
+ {
+ for(col = 0; col < STIC_BACKTAB_WIDTH; col++)
+ {
+ value = state->m_ram16[offs];
+
+ n_bit = value & STIC_CSTM_ADV;
+ p_bit = value & STIC_CSTM_FG3;
+ g_bit = value & STIC_CSTM_SEL;
+
+ if (p_bit && (!g_bit)) // colored squares mode
+ {
+ colora = value & STIC_CSQM_A;
+ colorb = (value & STIC_CSQM_B) >> 3;
+ colorc = (value & STIC_CSQM_C) >> 6;
+ colord = ((n_bit & STIC_CSQM_D2) >> 11) + ((value & STIC_CSQM_D10) >> 9);
+ // color 7 if the top of the color stack in this mode
+ if (colora == 7) colora = state->m_stic_registers[STIC_CSR + STIC_CSR3];
+ if (colorb == 7) colorb = state->m_stic_registers[STIC_CSR + STIC_CSR3];
+ if (colorc == 7) colorc = state->m_stic_registers[STIC_CSR + STIC_CSR3];
+ if (colord == 7) colord = state->m_stic_registers[STIC_CSR + STIC_CSR3];
+ intv_plot_box(state, bitmap, (x0 + col * STIC_CARD_WIDTH) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT) * STIC_Y_SCALE, STIC_CSQM_WIDTH * STIC_X_SCALE, STIC_CSQM_HEIGHT * STIC_Y_SCALE, colora);
+ intv_plot_box(state, bitmap, (x0 + col * STIC_CARD_WIDTH + STIC_CSQM_WIDTH)) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT) * STIC_Y_SCALE, STIC_CSQM_WIDTH * STIC_X_SCALE, STIC_CSQM_HEIGHT * STIC_Y_SCALE, colorb);
+ intv_plot_box(state, bitmap, (x0 + col * STIC_CARD_WIDTH) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT + STIC_CSQM_HEIGHT) * STIC_Y_SCALE, STIC_CSQM_WIDTH * STIC_X_SCALE, STIC_CSQM_HEIGHT * STIC_Y_SCALE, colorc);
+ intv_plot_box(state, bitmap, (x0 + col * STIC_CARD_WIDTH + STIC_CSQM_WIDTH) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT + STIC_CSQM_HEIGHT) * STIC_Y_SCALE, STIC_CSQM_WIDTH * STIC_X_SCALE, STIC_CSQM_HEIGHT * STIC_Y_SCALE, colord);
+ }
+ else // normal color stack mode
+ {
+ if (n_bit) // next color
+ {
+ state->m_color_stack_offset += 1;
+ state->m_color_stack_offset &= (STIC_CSRS - 1);
+ }
+
+ if (p_bit) // pastel color set
+ fgcolor = (value & STIC_CSTM_FG20) + 8;
+ else
+ fgcolor = value & STIC_CSTM_FG20;
+
+ bgcolor = state->m_stic_registers[STIC_CSR + state->m_color_stack_offset];
+ code = (value & STIC_CSTM_C)>>3;
+
+ if (g_bit) // read from gram
+ {
+ code &= (STIC_CSTM_C50 >> 3); // keep from going outside the array
+ //if (state->m_gramdirtybytes[code] == 1)
+ {
+ decodechar(machine.gfx[1],
+ code,
+ state->m_gram,
+ machine.config()->gfxdecodeinfo[1].gfxlayout);
+ state->m_gramdirtybytes[code] = 0;
+ }
+ // Draw GRAM char
+ drawgfx(bitmap,machine.gfx[1],
+ code,
+ bgcolor*16+fgcolor,
+ 0,0, (x0 + col * STIC_CARD_WIDTH) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT) * STIC_Y_SCALE,
+ 0,transparency,bgcolor);
+
+ for(j=0;j<8;j++)
+ {
+ //intv_set_pixel(state, bitmap, (x0 + col * STIC_CARD_WIDTH + j) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT + 7) * STIC_Y_SCALE + 1, 1);
+ }
+
+ }
+ else // read from grom
+ {
+ drawgfx(bitmap,machine.gfx[0],
+ code,
+ bgcolor*16+fgcolor,
+ 0,0, (x0 + col * STIC_CARD_WIDTH) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT) * STIC_Y_SCALE,
+ 0,transparency,bgcolor);
+
+ for(j=0;j<8;j++)
+ {
+ //intv_set_pixel(state, bitmap, (x0 + col * STIC_CARD_WIDTH + j) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT + 7) * STIC_Y_SCALE + 1, 2);
+ }
+ }
+ }
+ offs++;
+ } // next col
+ } // next row
+ }
+ else
+ {
+ // fg/bg mode goes here
+ for(row = 0; row < STIC_BACKTAB_HEIGHT; row++)
+ {
+ for(col = 0; col < STIC_BACKTAB_WIDTH; col++)
+ {
+ value = state->m_ram16[offs];
+ fgcolor = value & STIC_FBM_FG;
+ bgcolor = ((value & STIC_FBM_BG2) >> 11) + ((value & STIC_FBM_BG310) >> 9);
+ code = (value & STIC_FBM_C) >> 3;
+
+ if (value & STIC_FBM_SEL) // read for GRAM
+ {
+ //if (state->m_gramdirtybytes[code] == 1)
+ {
+ decodechar(machine.gfx[1],
+ code,
+ state->m_gram,
+ machine.config()->gfxdecodeinfo[1].gfxlayout);
+ state->m_gramdirtybytes[code] = 0;
+ }
+ // Draw GRAM char
+ drawgfx(bitmap,machine.gfx[1],
+ code,
+ bgcolor*16+fgcolor,
+ 0,0, (x0 + col * STIC_CARD_WIDTH) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT) * STIC_Y_SCALE,
+ 0,transparency,bgcolor);
+ }
+ else // read from GROM
+ {
+ drawgfx(bitmap,machine.gfx[0],
+ code,
+ bgcolor*16+fgcolor,
+ 0,0, (x0 + col * STIC_CARD_WIDTH) * STIC_X_SCALE, (y0 + row * STIC_CARD_HEIGHT) * STIC_Y_SCALE,
+ 0,transparency,bgcolor);
+ }
+ offs++;
+ } // next col
+ } // next row
+ }
+}
+#endif
+
+/* TBD: need to handle sprites behind foreground? */
+#ifdef UNUSED_FUNCTION
+static void draw_sprites(running_machine &machine, bitmap_ind16 &bitmap, int behind_foreground)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ int i;
+ int code;
+ int x0 = STIC_OVERSCAN_LEFT_WIDTH + state->m_col_delay - STIC_CARD_WIDTH;
+ int y0 = STIC_OVERSCAN_TOP_HEIGHT + state->m_row_delay - STIC_CARD_HEIGHT;
+
+ for(i = STIC_MOBS - 1; i >= 0; --i)
+ {
+ intv_sprite_type *s = &state->m_sprite[i];
+ if (s->visible && (s->behind_foreground == behind_foreground))
+ {
+ code = s->card;
+ if (!s->grom)
+ {
+ code %= 64; // keep from going outside the array
+ if (s->yres == 1)
+ {
+ //if (state->m_gramdirtybytes[code] == 1)
+ {
+ decodechar(machine.gfx[1],
+ code,
+ state->m_gram,
+ machine.config()->gfxdecodeinfo[1].gfxlayout);
+ state->m_gramdirtybytes[code] = 0;
+ }
+ // Draw GRAM char
+ drawgfxzoom_transpen(bitmap,&machine.screen[0].visarea,machine.gfx[1],
+ code,
+ s->color,
+ s->xflip,s->yflip,
+ (s->xpos + x0) * STIC_X_SCALE, (s->ypos + y0) * STIC_Y_SCALE,
+ 0x8000 * s->xsize, 0x8000 * s->ysize,0);
+ }
+ else
+ {
+ //if ((state->m_gramdirtybytes[code] == 1) || (state->m_gramdirtybytes[code+1] == 1))
+ {
+ decodechar(machine.gfx[1],
+ code,
+ state->m_gram,
+ machine.config()->gfxdecodeinfo[1].gfxlayout);
+ decodechar(machine.gfx[1],
+ code+1,
+ state->m_gram,
+ machine.config()->gfxdecodeinfo[1].gfxlayout);
+ state->m_gramdirtybytes[code] = 0;
+ state->m_gramdirtybytes[code+1] = 0;
+ }
+ // Draw GRAM char
+ drawgfxzoom_transpen(bitmap,&machine.screen[0].visarea,machine.gfx[1],
+ code,
+ s->color,
+ s->xflip,s->yflip,
+ (s->xpos + x0) * STIC_X_SCALE, (s->ypos + y0) * STIC_Y_SCALE + s->yflip * s->ysize * STIC_CARD_HEIGHT,
+ 0x8000*s->xsize, 0x8000*s->ysize,0);
+ drawgfxzoom_transpen(bitmap,&machine.screen[0].visarea,machine.gfx[1],
+ code+1,
+ s->color,
+ s->xflip,s->yflip,
+ (s->xpos + x0) * STIC_X_SCALE, (s->ypos + y0) * STIC_Y_SCALE + (1 - s->yflip) * s->ysize * STIC_CARD_HEIGHT,
+ 0x8000*s->xsize, 0x8000*s->ysize,0);
+ }
+ }
+ else
+ {
+ if (s->yres == 1)
+ {
+ // Draw GROM char
+ drawgfxzoom_transpen(bitmap,&machine.screen[0].visarea,machine.gfx[0],
+ code,
+ s->color,
+ s->xflip,s->yflip,
+ (s->xpos + x0) * STIC_X_SCALE, (s->ypos + y0) * STIC_Y_SCALE,
+ 0x8000*s->xsize, 0x8000*s->ysize,0);
+ }
+ else
+ {
+ drawgfxzoom_transpen(bitmap,&machine.screen[0].visarea,machine.gfx[0],
+ code,
+ s->color,
+ s->xflip,s->yflip,
+ (s->xpos + x0) * STIC_X_SCALE, (s->ypos + y0) * STIC_Y_SCALE + s->yflip * s->ysize * STIC_CARD_HEIGHT,
+ 0x8000*s->xsize, 0x8000*s->ysize,0);
+ drawgfxzoom_transpen(bitmap,&machine.screen[0].visarea,machine.gfx[0],
+ code+1,
+ s->color,
+ s->xflip,s->yflip,
+ (s->xpos + x0) * STIC_X_SCALE, (s->ypos + y0) * STIC_Y_SCALE + (1 - s->yflip) * s->ysize * STIC_CARD_HEIGHT,
+ 0x8000*s->xsize, 0x8000*s->ysize,0);
+ }
+ }
+ }
+ }
+}
+#endif
+
+static void draw_borders(running_machine &machine, bitmap_ind16 &bm)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+
+ intv_plot_box(state, bm, 0, 0, (STIC_OVERSCAN_LEFT_WIDTH + (state->m_left_edge_inhibit ? STIC_CARD_WIDTH : state->m_col_delay)) * STIC_X_SCALE, (STIC_OVERSCAN_TOP_HEIGHT + STIC_BACKTAB_HEIGHT * STIC_CARD_HEIGHT + STIC_OVERSCAN_BOTTOM_HEIGHT) * STIC_Y_SCALE, state->m_border_color);
+ intv_plot_box(state, bm, (STIC_OVERSCAN_LEFT_WIDTH + STIC_BACKTAB_WIDTH * STIC_CARD_WIDTH - 1) * STIC_X_SCALE, 0, STIC_OVERSCAN_RIGHT_WIDTH, (STIC_OVERSCAN_TOP_HEIGHT + STIC_BACKTAB_HEIGHT * STIC_CARD_HEIGHT + STIC_OVERSCAN_BOTTOM_HEIGHT) * STIC_Y_SCALE, state->m_border_color);
+
+ intv_plot_box(state, bm, 0, 0, (STIC_OVERSCAN_LEFT_WIDTH + STIC_BACKTAB_WIDTH * STIC_CARD_WIDTH - 1 + STIC_OVERSCAN_RIGHT_WIDTH) * STIC_X_SCALE, (STIC_OVERSCAN_TOP_HEIGHT + (state->m_top_edge_inhibit ? STIC_CARD_HEIGHT : state->m_row_delay)) * STIC_Y_SCALE, state->m_border_color);
+ intv_plot_box(state, bm, 0, (STIC_OVERSCAN_TOP_HEIGHT + STIC_BACKTAB_HEIGHT * STIC_CARD_HEIGHT) * STIC_Y_SCALE, (STIC_OVERSCAN_LEFT_WIDTH + STIC_BACKTAB_WIDTH * STIC_CARD_WIDTH - 1 + STIC_OVERSCAN_RIGHT_WIDTH) * STIC_X_SCALE, STIC_OVERSCAN_BOTTOM_HEIGHT * STIC_Y_SCALE, state->m_border_color);
+}
+
+void intv_stic_screenrefresh(running_machine &machine)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ int i;
+
+ if (state->m_stic_handshake != 0)
+ {
+ state->m_stic_handshake = 0;
+ // Render the background
+ render_background(machine, state->m_bitmap);
+ // Render the sprites into their buffers
+ render_sprites(machine);
+ for (i = 0; i < STIC_MOBS; i++) state->m_sprite[i].collision = 0;
+ // Copy the sprites to the background
+ copy_sprites_to_background(machine, state->m_bitmap);
+ determine_sprite_collisions(state);
+ for (i = 0; i < STIC_MOBS; i++) state->m_stic_registers[STIC_MCR + i] |= state->m_sprite[i].collision;
+ /* draw the screen borders if enabled */
+ draw_borders(machine, state->m_bitmap);
+ }
+ else
+ {
+ /* STIC disabled, just fill with border color */
+ state->m_bitmap.fill(SET_COLOR(state->m_border_color));
+ }
+}
+
+
+/* very rudimentary support for the tms9927 character generator IC */
+
+
+ READ8_MEMBER( intv_state::intvkbd_tms9927_r )
+{
+ //intv_state *state = space->machine().driver_data<intv_state>();
+ UINT8 rv;
+ switch (offset)
+ {
+ case 8:
+ rv = m_tms9927_cursor_row;
+ break;
+ case 9:
+ /* note: this is 1-based */
+ rv = m_tms9927_cursor_col;
+ break;
+ case 11:
+ m_tms9927_last_row = (m_tms9927_last_row + 1) % m_tms9927_num_rows;
+ rv = m_tms9927_last_row;
+ break;
+ default:
+ rv = 0;
+ }
+ return rv;
+}
+
+WRITE8_MEMBER( intv_state::intvkbd_tms9927_w )
+{
+ //intv_state *state = space->machine().driver_data<intv_state>();
+ switch (offset)
+ {
+ case 3:
+ m_tms9927_num_rows = (data & 0x3f) + 1;
+ break;
+ case 6:
+ m_tms9927_last_row = data;
+ break;
+ case 11:
+ m_tms9927_last_row = (m_tms9927_last_row + 1) % m_tms9927_num_rows;
+ break;
+ case 12:
+ /* note: this is 1-based */
+ m_tms9927_cursor_col = data;
+ break;
+ case 13:
+ m_tms9927_cursor_row = data;
+ break;
+ }
+}
+
+SCREEN_UPDATE_IND16( intv )
+{
+ intv_state *state = screen.machine().driver_data<intv_state>();
+ copybitmap(bitmap, state->m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( intvkbd )
+{
+ intv_state *state = screen.machine().driver_data<intv_state>();
+ UINT8 *videoram = state->m_videoram;
+ int x,y,offs;
+ int current_row;
+// char c;
+
+ /* Draw the underlying INTV screen first */
+ copybitmap(bitmap, state->m_bitmap, 0, 0, 0, 0, cliprect);
+
+ /* if the intvkbd text is not blanked, overlay it */
+ if (!state->m_intvkbd_text_blanked)
+ {
+ current_row = (state->m_tms9927_last_row + 1) % state->m_tms9927_num_rows;
+ for(y=0;y<24;y++)
+ {
+ for(x=0;x<40;x++)
+ {
+ offs = current_row*64+x;
+ drawgfx_transpen(bitmap, cliprect,
+ screen.machine().gfx[1],
+ videoram[offs],
+ 7, /* white */
+ 0,0,
+ x<<3,y<<3, 0);
+ }
+ if (current_row == state->m_tms9927_cursor_row)
+ {
+ /* draw the cursor as a solid white block */
+ /* (should use a filled rect here!) */
+ drawgfx_transpen(bitmap, cliprect,
+ screen.machine().gfx[1],
+ 191, /* a block */
+ 7, /* white */
+ 0,0,
+ (state->m_tms9927_cursor_col-1)<<3,y<<3, 0);
+ }
+ current_row = (current_row + 1) % state->m_tms9927_num_rows;
+ }
+ }
+
+#if 0
+ // debugging
+ c = tape_motor_mode_desc[state->m_tape_motor_mode][0];
+ drawgfx_transpen(bitmap,&machine.screen[0].visarea, machine.gfx[1],
+ c,
+ 1,
+ 0,0,
+ 0*8,0*8, 0);
+ for(y=0;y<5;y++)
+ {
+ drawgfx_transpen(bitmap,&machine.screen[0].visarea, machine.gfx[1],
+ state->m_tape_unknown_write[y]+'0',
+ 1,
+ 0,0,
+ 0*8,(y+2)*8, 0);
+ }
+ drawgfx_transpen(bitmap,&machine.screen[0].visarea, machine.gfx[1],
+ state->m_tape_unknown_write[5]+'0',
+ 1,
+ 0,0,
+ 0*8,8*8, 0);
+ drawgfx_transpen(bitmap,&machine.screen[0].visarea, machine.gfx[1],
+ state->m_tape_interrupts_enabled+'0',
+ 1,
+ 0,0,
+ 0*8,10*8, 0);
+#endif
+ return 0;
+}
diff --git a/src/mess/video/iq151_grafik.c b/src/mess/video/iq151_grafik.c
new file mode 100644
index 00000000000..4d2853f2026
--- /dev/null
+++ b/src/mess/video/iq151_grafik.c
@@ -0,0 +1,198 @@
+/***************************************************************************
+
+ IQ151 grafik emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "iq151_grafik.h"
+
+#define LOG 0
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static I8255_INTERFACE( grafik_ppi8255_intf )
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, iq151_grafik_device, x_write),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, iq151_grafik_device, y_write),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, iq151_grafik_device, control_w),
+};
+
+static MACHINE_CONFIG_FRAGMENT( iq151_grafik )
+ MCFG_I8255_ADD("ppi8255", grafik_ppi8255_intf)
+MACHINE_CONFIG_END
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type IQ151_GRAFIK = &device_creator<iq151_grafik_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// iq151_grafik_device - constructor
+//-------------------------------------------------
+
+iq151_grafik_device::iq151_grafik_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, IQ151_GRAFIK, "IQ151 grafik", tag, owner, clock),
+ device_iq151cart_interface( mconfig, *this ),
+ m_ppi8255(*this, "ppi8255")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void iq151_grafik_device::device_start()
+{
+ // allocate the videoram
+ m_videoram = (UINT8*)auto_alloc_array_clear(machine(), UINT8, 0x4000);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void iq151_grafik_device::device_reset()
+{
+ screen_device *screen = machine().primary_screen;
+
+ // if required adjust screen size
+ if (screen->visible_area().max_x < 64*8-1)
+ screen->set_visible_area(0, 64*8-1, 0, 32*8-1);
+
+ memset(m_videoram, 0x00, 0x4000);
+}
+
+//-------------------------------------------------
+// device_mconfig_additions
+//-------------------------------------------------
+
+machine_config_constructor iq151_grafik_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( iq151_grafik );
+}
+
+//-------------------------------------------------
+// I8255 port a
+//-------------------------------------------------
+
+WRITE8_MEMBER(iq151_grafik_device::x_write)
+{
+ if (LOG) logerror("Grafik: set posx 0x%02x\n", data);
+
+ m_posx = data & 0x3f;
+}
+
+//-------------------------------------------------
+// I8255 port b
+//-------------------------------------------------
+
+WRITE8_MEMBER(iq151_grafik_device::y_write)
+{
+ if (LOG) logerror("Grafik: set posy 0x%02x\n", data);
+
+ m_posy = data;
+}
+
+//-------------------------------------------------
+// I8255 port c
+//-------------------------------------------------
+
+WRITE8_MEMBER(iq151_grafik_device::control_w)
+{
+ if (LOG) logerror("Grafik: control write 0x%02x\n", data);
+
+ m_all = BIT(data, 0);
+ m_pen = BIT(data, 1);
+ m_fast = BIT(data, 2);
+ m_ev = BIT(data, 3);
+ m_ex = (data>>4) & 0x03;
+ m_sel = BIT(data, 7);
+}
+
+
+//-------------------------------------------------
+// IO read
+//-------------------------------------------------
+
+void iq151_grafik_device::io_read(offs_t offset, UINT8 &data)
+{
+ if (offset >= 0xd0 && offset < 0xd4)
+ {
+ address_space* space = machine().device("maincpu")->memory().space(AS_IO);
+ data = m_ppi8255->read(*space, offset & 3);
+ }
+ else if (offset == 0xd4)
+ {
+ if (LOG) logerror("Grafik: vram read 0x%04x\n", m_posx + 0x40 * m_posy);
+
+ if (m_sel)
+ data = m_videoram[m_posx + 0x40 * m_posy];
+ }
+}
+
+//-------------------------------------------------
+// IO write
+//-------------------------------------------------
+
+void iq151_grafik_device::io_write(offs_t offset, UINT8 data)
+{
+ if (offset >= 0xd0 && offset < 0xd4)
+ {
+ address_space* space = machine().device("maincpu")->memory().space(AS_IO);
+ m_ppi8255->write(*space, offset & 3, data);
+ }
+ else if (offset == 0xd4)
+ {
+ if (m_sel)
+ {
+ if (LOG) logerror("Grafik: vram write 0x%04x 0x%02x\n", m_posx + 0x40 * m_posy, data);
+
+ if (m_all)
+ {
+ m_videoram[m_posx + 0x40 * m_posy] = data;
+ }
+ else
+ {
+ if (m_pen)
+ m_videoram[m_posx + 0x40 * m_posy] &= ~(1 << (data >> 5));
+ else
+ m_videoram[m_posx + 0x40 * m_posy] |= (1 << (data >> 5));
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// video update
+//-------------------------------------------------
+
+void iq151_grafik_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ if (m_ev)
+ {
+ for (int y = 0; y < 32*8; y++)
+ {
+ for (int x = 0; x < 64; x++)
+ {
+ for (int ra = 0; ra < 8; ra++)
+ {
+ bitmap.pix16(y, x*8 + ra) |= BIT(m_videoram[(32*8 -1 - y)*64 + x], ra);
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/mess/video/iq151_grafik.h b/src/mess/video/iq151_grafik.h
new file mode 100644
index 00000000000..728e4ae725e
--- /dev/null
+++ b/src/mess/video/iq151_grafik.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#ifndef __IQ151_GRAFIK_H__
+#define __IQ151_GRAFIK_H__
+
+#include "emu.h"
+#include "machine/iq151cart.h"
+#include "machine/i8255.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> iq151_grafik_device
+
+class iq151_grafik_device :
+ public device_t,
+ public device_iq151cart_interface
+{
+public:
+ // construction/destruction
+ iq151_grafik_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ // ppi8255 callback
+ DECLARE_WRITE8_MEMBER(x_write);
+ DECLARE_WRITE8_MEMBER(y_write);
+ DECLARE_WRITE8_MEMBER(control_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "iq151_grafik"; }
+
+ // iq151cart_interface overrides
+ virtual void io_read(offs_t offset, UINT8 &data);
+ virtual void io_write(offs_t offset, UINT8 data);
+ virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+private:
+
+ required_device<i8255_device> m_ppi8255;
+
+ UINT8 * m_videoram;
+ UINT8 m_posx; // horizontal position
+ UINT8 m_posy; // vertical position
+ UINT8 m_all; // 0: bit mode 1: byte mode
+ UINT8 m_pen;
+ UINT8 m_fast;
+ UINT8 m_ev; // enable video out
+ UINT8 m_ex;
+ UINT8 m_sel; // enable vram access
+};
+
+
+// device type definition
+extern const device_type IQ151_GRAFIK;
+
+#endif /* __IQ151_GRAFIK_H__ */
diff --git a/src/mess/video/iq151_video32.c b/src/mess/video/iq151_video32.c
new file mode 100644
index 00000000000..14ca59b746e
--- /dev/null
+++ b/src/mess/video/iq151_video32.c
@@ -0,0 +1,148 @@
+/***************************************************************************
+
+ IQ151 video32 cartridge emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "iq151_video32.h"
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+ROM_START( iq151_video32 )
+ ROM_REGION(0x0400, "chargen", ROMREGION_INVERT)
+ ROM_LOAD( "iq151_video32font.rom", 0x0000, 0x0400, CRC(395567a7) SHA1(18800543daf4daed3f048193c6ae923b4b0e87db))
+
+ ROM_REGION(0x0400, "videoram", ROMREGION_ERASE)
+ROM_END
+
+
+/* F4 Character Displayer */
+static const gfx_layout iq151_video32_charlayout =
+{
+ 8, 8, /* 8 x 8 characters */
+ 128, /* 128 characters */
+ 1, /* 1 bits per pixel */
+ { 0 }, /* no bitplanes */
+ /* x offsets */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8 /* every char takes 8 bytes */
+};
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type IQ151_VIDEO32 = &device_creator<iq151_video32_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// iq151_video32_device - constructor
+//-------------------------------------------------
+
+iq151_video32_device::iq151_video32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, IQ151_VIDEO32, "IQ151 video32", tag, owner, clock),
+ device_iq151cart_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void iq151_video32_device::device_start()
+{
+ m_videoram = (UINT8*)memregion("videoram")->base();
+ m_chargen = (UINT8*)memregion("chargen")->base();
+
+ machine().gfx[0] = gfx_element_alloc(machine(), &iq151_video32_charlayout, m_chargen, 1, 0);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void iq151_video32_device::device_reset()
+{
+ screen_device *screen = machine().primary_screen;
+
+ // if required adjust screen size
+ if (screen->visible_area().max_x < 32*8 - 1)
+ screen->set_visible_area(0, 32*8-1, 0, 32*8-1);
+}
+
+//-------------------------------------------------
+// device_rom_region
+//-------------------------------------------------
+
+const rom_entry *iq151_video32_device::device_rom_region() const
+{
+ return ROM_NAME( iq151_video32 );
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+void iq151_video32_device::read(offs_t offset, UINT8 &data)
+{
+ // videoram is mapped at 0xec00-0xefff
+ if (offset >= 0xec00 && offset < 0xf000)
+ data = m_videoram[offset & 0x3ff];
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void iq151_video32_device::write(offs_t offset, UINT8 data)
+{
+ if (offset >= 0xec00 && offset < 0xf000)
+ m_videoram[offset & 0x3ff] = data;
+}
+
+//-------------------------------------------------
+// video update
+//-------------------------------------------------
+
+void iq151_video32_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT16 ma = 0, sy = 0;
+
+ for (int y = 0; y < 32; y++)
+ {
+ for (int ra = 0; ra < 8; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (int x = ma; x < ma + 32; x++)
+ {
+ UINT8 chr = m_videoram[x] & 0x7f; // rom only has 128 characters
+ UINT8 gfx = m_chargen[(chr<<3) | ra ];
+
+ // chars above 0x7f have colors inverted
+ if (m_videoram[x] > 0x7f)
+ gfx = ~gfx;
+
+ /* Display a scanline of a character */
+ *p++ |= BIT(gfx, 7);
+ *p++ |= BIT(gfx, 6);
+ *p++ |= BIT(gfx, 5);
+ *p++ |= BIT(gfx, 4);
+ *p++ |= BIT(gfx, 3);
+ *p++ |= BIT(gfx, 2);
+ *p++ |= BIT(gfx, 1);
+ *p++ |= BIT(gfx, 0);
+ }
+ }
+ ma += 32;
+ }
+}
diff --git a/src/mess/video/iq151_video32.h b/src/mess/video/iq151_video32.h
new file mode 100644
index 00000000000..d8b77ecee54
--- /dev/null
+++ b/src/mess/video/iq151_video32.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#ifndef __IQ151_VIDEO32_H__
+#define __IQ151_VIDEO32_H__
+
+#include "emu.h"
+#include "machine/iq151cart.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> iq151_video32_device
+
+class iq151_video32_device :
+ public device_t,
+ public device_iq151cart_interface
+{
+public:
+ // construction/destruction
+ iq151_video32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "iq151_video32"; }
+
+ // iq151cart_interface overrides
+ virtual void read(offs_t offset, UINT8 &data);
+ virtual void write(offs_t offset, UINT8 data);
+ virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+private:
+ UINT8 * m_videoram;
+ UINT8 * m_chargen;
+};
+
+
+// device type definition
+extern const device_type IQ151_VIDEO32;
+
+#endif /* __IQ151_VIDEO32_H__ */
diff --git a/src/mess/video/iq151_video64.c b/src/mess/video/iq151_video64.c
new file mode 100644
index 00000000000..76f59110e50
--- /dev/null
+++ b/src/mess/video/iq151_video64.c
@@ -0,0 +1,156 @@
+/***************************************************************************
+
+ IQ151 video64 cartridge emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "iq151_video64.h"
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+ROM_START( iq151_video64 )
+ ROM_REGION(0x0800, "chargen", ROMREGION_INVERT)
+ ROM_LOAD( "iq151_video64font.rom", 0x0000, 0x0800, CRC(cb6f43c0) SHA1(4b2c1d41838d569228f61568c1a16a8d68b3dadf))
+
+ ROM_REGION(0x0800, "videoram", ROMREGION_ERASE)
+ROM_END
+
+
+/* F4 Character Displayer */
+static const gfx_layout iq151_video64_charlayout =
+{
+ 6, 8, /* 6 x 8 characters */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ { 0 }, /* no bitplanes */
+ /* x offsets */
+ { 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8 /* every char takes 8 bytes */
+};
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type IQ151_VIDEO64 = &device_creator<iq151_video64_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// iq151_video64_device - constructor
+//-------------------------------------------------
+
+iq151_video64_device::iq151_video64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, IQ151_VIDEO64, "IQ151 video64", tag, owner, clock),
+ device_iq151cart_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void iq151_video64_device::device_start()
+{
+ m_videoram = (UINT8*)memregion("videoram")->base();
+ m_chargen = (UINT8*)memregion("chargen")->base();
+
+ machine().gfx[0] = gfx_element_alloc(machine(), &iq151_video64_charlayout, m_chargen, 1, 0);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void iq151_video64_device::device_reset()
+{
+ screen_device *screen = machine().primary_screen;
+
+ // if required adjust screen size
+ if (screen->visible_area().max_x < 64*6 - 1)
+ screen->set_visible_area(0, 64*6-1, 0, 32*8-1);
+}
+
+//-------------------------------------------------
+// device_rom_region
+//-------------------------------------------------
+
+const rom_entry *iq151_video64_device::device_rom_region() const
+{
+ return ROM_NAME( iq151_video64 );
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+void iq151_video64_device::read(offs_t offset, UINT8 &data)
+{
+ // videoram is mapped at 0xe800-0xefff
+ if (offset >= 0xe800 && offset < 0xf000)
+ data = m_videoram[offset & 0x7ff];
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void iq151_video64_device::write(offs_t offset, UINT8 data)
+{
+ if (offset >= 0xe800 && offset < 0xf000)
+ m_videoram[offset & 0x7ff] = data;
+}
+
+//-------------------------------------------------
+// IO read
+//-------------------------------------------------
+
+void iq151_video64_device::io_read(offs_t offset, UINT8 &data)
+{
+ if (offset >= 0xfc && offset < 0x100)
+ {
+ // this value is used by the IQ151 for detect if the installed
+ // cart is video64 or video32
+ data = 0xfe;
+ }
+}
+
+//-------------------------------------------------
+// video update
+//-------------------------------------------------
+
+void iq151_video64_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT16 ma = 0, sy = 0;
+
+ for (int y = 0; y < 32; y++)
+ {
+ for (int ra = 0; ra < 8; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (int x = ma; x < ma + 64; x++)
+ {
+ UINT8 chr = m_videoram[x];
+ UINT8 gfx = m_chargen[(chr<<3) | ra ];
+
+ /* Display a scanline of a character */
+ *p++ |= BIT(gfx, 5);
+ *p++ |= BIT(gfx, 4);
+ *p++ |= BIT(gfx, 3);
+ *p++ |= BIT(gfx, 2);
+ *p++ |= BIT(gfx, 1);
+ *p++ |= BIT(gfx, 0);
+ }
+ }
+ ma += 64;
+ }
+}
diff --git a/src/mess/video/iq151_video64.h b/src/mess/video/iq151_video64.h
new file mode 100644
index 00000000000..c852722c738
--- /dev/null
+++ b/src/mess/video/iq151_video64.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#ifndef __IQ151_VIDEO64_H__
+#define __IQ151_VIDEO64_H__
+
+#include "emu.h"
+#include "machine/iq151cart.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> iq151_video64_device
+
+class iq151_video64_device :
+ public device_t,
+ public device_iq151cart_interface
+{
+public:
+ // construction/destruction
+ iq151_video64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "iq151_video64"; }
+
+ // iq151cart_interface overrides
+ virtual void read(offs_t offset, UINT8 &data);
+ virtual void write(offs_t offset, UINT8 data);
+ virtual void io_read(offs_t offset, UINT8 &data);
+ virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+private:
+ UINT8 * m_videoram;
+ UINT8 * m_chargen;
+};
+
+
+// device type definition
+extern const device_type IQ151_VIDEO64;
+
+#endif /* __IQ151_VIDEO64_H__ */
diff --git a/src/mess/video/irisha.c b/src/mess/video/irisha.c
new file mode 100644
index 00000000000..79abea3a054
--- /dev/null
+++ b/src/mess/video/irisha.c
@@ -0,0 +1,43 @@
+/***************************************************************************
+
+ Irisha video driver by Miodrag Milanovic
+
+ 27/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/irisha.h"
+
+
+VIDEO_START( irisha )
+{
+}
+
+SCREEN_UPDATE_IND16( irisha )
+{
+ UINT8 code1; //, code2;
+ UINT8 col;
+ int y, x, b;
+ address_space *space = screen.machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ // draw image
+ for (y = 0; y < 200; y++)
+ {
+ for (x = 0; x < 40; x++)
+ {
+ code1 = space->read_byte(0xe000 + x + y * 40);
+// code2 = space->read_byte(0xc000 + x + y * 40);
+ for (b = 0; b < 8; b++)
+ {
+ col = ((code1 >> b) & 0x01);
+ bitmap.pix16(y, x * 8 + (7 - b)) = col;
+ }
+ }
+ }
+
+
+ return 0;
+}
+
diff --git a/src/mess/video/isa_cga.c b/src/mess/video/isa_cga.c
new file mode 100644
index 00000000000..997d7c59366
--- /dev/null
+++ b/src/mess/video/isa_cga.c
@@ -0,0 +1,2035 @@
+/***************************************************************************
+
+ Color Graphics Adapter (CGA) section
+
+
+ Notes on Port 3D8
+ (http://www.clipx.net/ng/interrupts_and_ports/ng2d045.php)
+
+ Port 3D8 - Color/VGA Mode control register
+
+ xx1x xxxx Attribute bit 7. 0=blink, 1=Intesity
+ xxx1 xxxx 640x200 mode
+ xxxx 1xxx Enable video signal
+ xxxx x1xx Select B/W mode
+ xxxx xx1x Select graphics
+ xxxx xxx1 80x25 text
+
+
+ The usage of the above control register for various modes is:
+ xx10 1100 40x25 alpha B/W
+ xx10 1000 40x25 alpha color
+ xx10 1101 80x25 alpha B/W
+ xx10 1001 80x25 alpha color
+ xxx0 1110 320x200 graph B/W
+ xxx0 1010 320x200 graph color
+ xxx1 1110 640x200 graph B/W
+
+
+ PC1512 display notes
+
+ The PC1512 built-in display adaptor is an emulation of IBM's CGA. Unlike a
+ real CGA, it is not built around a real MC6845 controller, and so attempts
+ to get custom video modes out of it may not work as expected. Its 640x200
+ CGA mode can be set up to be a 16-color mode rather than mono.
+
+ If you program it with BIOS calls, the PC1512 behaves just like a real CGA,
+ except:
+
+ - The 'greyscale' text modes (0 and 2) behave just like the 'color'
+ ones (1 and 3). On a color monitor both are in color; on a mono
+ monitor both are in greyscale.
+ - Mode 5 (the 'greyscale' graphics mode) displays in color, using
+ an alternative color palette: Cyan, Red and White.
+ - The undocumented 160x100x16 "graphics" mode works correctly.
+
+ (source John Elliott http://www.seasip.info/AmstradXT/pc1512disp.html)
+
+
+ Cursor signal handling:
+
+ The alpha dots signal is set when a character pixel should be set. This signal is
+ also set when the cursor should be displayed. The following formula for alpha
+ dots is derived from the schematics:
+ ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( ( ( NOT AT7 ) OR CURSOR DLY OR -BLINK OR NOT ENABLE BLINK ) AND ( CHG DOTS ) )
+
+ -CURSOR BLINK = VSYNC DLY (LS393) (changes every 8 vsyncs)
+ -BLINK = -CURSOR BLINK (LS393) (changes every 16 vsyncs)
+ -CURSOR DLY = -CURSOR signal from mc6845 and LS174
+ CHG DOTS = character pixel (from character rom)
+
+ For non-blinking modes this formula reduces to:
+ ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( CHG DOTS )
+
+ This means the cursor switches on/off state every 8 vsyncs.
+
+
+ For blinking modes this formula reduces to:
+ ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( ( ( NOT AT7 ) OR CURSOR DLY OR -BLINK ) AND ( CHG DOTS ) )
+
+ So, at the cursor location the attribute blinking is ignored and only regular
+ cursor blinking takes place (state switches every 8 vsyncs). On non-cursor
+ locations with the highest attribute bits set the character will switch
+ on/off every 16 vsyncs. In all other cases the character is displayed as
+ usual.
+
+
+TODO:
+- Update more drivers in MESS and MAME and unify with src/emu/video/pc_cga.c
+- Separate out more cards/implementations
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/mc6845.h"
+#include "video/isa_cga.h"
+
+#define VERBOSE_CGA 0 /* CGA (Color Graphics Adapter) */
+
+#define CGA_PALETTE_SETS 83 /* one for colour, one for mono,
+ * 81 for colour composite */
+
+#define CGA_SCREEN_NAME "screen"
+#define CGA_MC6845_NAME "mc6845_cga"
+
+#define CGA_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_CGA>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",machine.time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+/***************************************************************************
+
+ Static declarations
+
+***************************************************************************/
+
+static INPUT_PORTS_START( cga )
+ PORT_START( "cga_config" )
+ PORT_CONFNAME( 0x03, 0x00, "CGA character set")
+ PORT_CONFSETTING(0x00, DEF_STR( Normal ))
+ PORT_CONFSETTING(0x01, "Alternative")
+ PORT_CONFNAME( 0x1C, 0x00, "CGA monitor type")
+ PORT_CONFSETTING(0x00, "Colour RGB")
+ PORT_CONFSETTING(0x04, "Mono RGB")
+ PORT_CONFSETTING(0x08, "Colour composite")
+ PORT_CONFSETTING(0x0C, "Television")
+ PORT_CONFSETTING(0x10, "LCD")
+ PORT_CONFNAME( 0xE0, 0x00, "CGA chipset")
+ PORT_CONFSETTING(0x00, "IBM")
+ PORT_CONFSETTING(0x20, "Amstrad PC1512")
+ PORT_CONFSETTING(0x40, "Amstrad PPC512")
+ PORT_CONFSETTING(0x60, "ATI")
+ PORT_CONFSETTING(0x80, "Paradise")
+INPUT_PORTS_END
+
+
+static INPUT_PORTS_START( pc1512 )
+ PORT_START( "cga_config" )
+ PORT_CONFNAME( 0x03, 0x03, "CGA character set")
+ PORT_CONFSETTING(0x00, "Greek")
+ PORT_CONFSETTING(0x01, "Danish 2")
+ PORT_CONFSETTING(0x02, "Danish 1")
+ PORT_CONFSETTING(0x03, "Default")
+ PORT_CONFNAME( 0x1C, 0x00, "CGA monitor type")
+ PORT_CONFSETTING(0x00, "Colour RGB")
+ PORT_CONFSETTING(0x04, "Mono RGB")
+ PORT_BIT ( 0xE0, 0x20, IPT_UNUSED ) /* Chipset is always PC1512 */
+INPUT_PORTS_END
+
+
+/* Dipswitch for font selection */
+#define CGA_FONT (ioport("cga_config")->read() & m_font_selection_mask)
+
+/* Dipswitch for monitor selection */
+#define CGA_MONITOR (ioport("cga_config")->read()&0x1C)
+#define CGA_MONITOR_RGB 0x00 /* Colour RGB */
+#define CGA_MONITOR_MONO 0x04 /* Greyscale RGB */
+#define CGA_MONITOR_COMPOSITE 0x08 /* Colour composite */
+#define CGA_MONITOR_TELEVISION 0x0C /* Television */
+#define CGA_MONITOR_LCD 0x10 /* LCD, eg PPC512 */
+
+
+/* Dipswitch for chipset selection */
+/* TODO: Get rid of this; these should be handled by separate classes */
+#define CGA_CHIPSET (ioport("cga_config")->read() & 0xE0)
+#define CGA_CHIPSET_IBM 0x00 /* Original IBM CGA */
+#define CGA_CHIPSET_PC1512 0x20 /* PC1512 CGA subset */
+#define CGA_CHIPSET_PC200 0x40 /* PC200 in CGA mode */
+#define CGA_CHIPSET_ATI 0x60 /* ATI (supports Plantronics) */
+#define CGA_CHIPSET_PARADISE 0x80 /* Paradise (used in PC1640) */
+
+
+/* CGA palettes
+ *
+ * The first 16 are for RGB monitors
+ * The next 16 are for greyscale modes
+ * The next 16 are for text modes on colour composite
+ * The next 16*16 are Mode 6 (colour composite) }
+ * The next 64*16 are Mode 4 (colour composite) } both indexed by the CGA colour select register 0x3D9
+ *
+ */
+
+const unsigned char cga_palette[16 * CGA_PALETTE_SETS][3] =
+{
+/* RGB colours */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xaa }, { 0x00, 0xaa, 0x00 }, { 0x00, 0xaa, 0xaa },
+ { 0xaa, 0x00, 0x00 }, { 0xaa, 0x00, 0xaa }, { 0xaa, 0x55, 0x00 }, { 0xaa, 0xaa, 0xaa },
+ { 0x55, 0x55, 0x55 }, { 0x55, 0x55, 0xff }, { 0x55, 0xff, 0x55 }, { 0x55, 0xff, 0xff },
+ { 0xff, 0x55, 0x55 }, { 0xff, 0x55, 0xff }, { 0xff, 0xff, 0x55 }, { 0xff, 0xff, 0xff },
+/* Greyscale */
+ { 0x00, 0x00, 0x00 }, { 0x11, 0x11, 0x11 }, { 0x44, 0x44, 0x44 }, { 0x55, 0x55, 0x55 },
+ { 0x22, 0x22, 0x22 }, { 0x33, 0x33, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x77, 0x77, 0x77 },
+ { 0x88, 0x88, 0x88 }, { 0x99, 0x99, 0x99 }, { 0xCC, 0xCC, 0xCC }, { 0xDD, 0xDD, 0xDD },
+ { 0xAA, 0xAA, 0xAA }, { 0xBB, 0xBB, 0xBB }, { 0xEE, 0xEE, 0xEE }, { 0xFF, 0xFF, 0xFF },
+/* Text mode, composite monitor */
+ { 0x00, 0x00, 0x00 }, { 0x0E, 0x00, 0x7A }, { 0x07, 0x55, 0x00 }, { 0x02, 0x65, 0x39 },
+ { 0x51, 0x00, 0x1A }, { 0x54, 0x00, 0x76 }, { 0x48, 0x63, 0x00 }, { 0x8c, 0x8c, 0x8c },
+ { 0x38, 0x38, 0x38 }, { 0x58, 0x49, 0xD5 }, { 0x5F, 0xAD, 0x26 }, { 0x5B, 0xB9, 0xAC },
+ { 0xAA, 0x4A, 0x5E }, { 0xA7, 0x55, 0xD2 }, { 0xA2, 0xB9, 0x31 }, { 0xE2, 0xE2, 0xE2 },
+/* Composite hi-res, colour reg = 0 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+/* Composite hi-res, colour reg = 1 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x04, 0x04 }, { 0x00, 0x00, 0x61 }, { 0x00, 0x00, 0x6b },
+ { 0x25, 0x00, 0x1E }, { 0x15, 0x00, 0x23 }, { 0x18, 0x00, 0x87 }, { 0x06, 0x00, 0x91 },
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x0b, 0x00 }, { 0x00, 0x00, 0x4C }, { 0x00, 0x02, 0x52 },
+ { 0x24, 0x00, 0x08 }, { 0x0E, 0x00, 0x0D }, { 0x18, 0x00, 0x6f }, { 0x07, 0x00, 0x7C },
+/* Composite hi-res, colour reg = 2 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x28, 0x00 }, { 0x01, 0x00, 0x46 }, { 0x00, 0x21, 0x36 },
+ { 0x22, 0x00, 0x01 }, { 0x00, 0x21, 0x00 }, { 0x1b, 0x00, 0x43 }, { 0x00, 0x22, 0x33 },
+ { 0x07, 0x0D, 0x00 }, { 0x00, 0x4B, 0x00 }, { 0x04, 0x0E, 0x00 }, { 0x00, 0x57, 0x00 },
+ { 0x25, 0x02, 0x00 }, { 0x01, 0x46, 0x00 }, { 0x30, 0x04, 0x00 }, { 0x04, 0x53, 0x00 },
+/* Composite hi-res, colour reg = 3 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x30, 0x00 }, { 0x00, 0x00, 0x8E }, { 0x00, 0x38, 0x87 },
+ { 0x2E, 0x00, 0x01 }, { 0x00, 0x21, 0x00 }, { 0x22, 0x00, 0x8C }, { 0x00, 0x35, 0x95 },
+ { 0x00, 0x0F, 0x00 }, { 0x00, 0x4F, 0x00 }, { 0x00, 0x0B, 0x3F }, { 0x00, 0x62, 0x45 },
+ { 0x29, 0x00, 0x00 }, { 0x00, 0x4E, 0x00 }, { 0x35, 0x04, 0x48 }, { 0x01, 0x62, 0x49 },
+/* Composite hi-res, colour reg = 4 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x06, 0x02 }, { 0x01, 0x00, 0x1f }, { 0x00, 0x00, 0x24 },
+ { 0x54, 0x00, 0x38 }, { 0x25, 0x00, 0x23 }, { 0x3A, 0x00, 0x4f }, { 0x29, 0x00, 0x56 },
+ { 0x10, 0x03, 0x00 }, { 0x06, 0x08, 0x00 }, { 0x15, 0x00, 0x00 }, { 0x02, 0x03, 0x00 },
+ { 0x82, 0x00, 0x00 }, { 0x49, 0x00, 0x00 }, { 0x5B, 0x00, 0x0b }, { 0x52, 0x00, 0x0c },
+/* Composite hi-res, colour reg = 5 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x2c, 0x00 }, { 0x06, 0x01, 0x57 }, { 0x00, 0x22, 0x42 },
+ { 0x33, 0x00, 0x01 }, { 0x00, 0x26, 0x00 }, { 0x3a, 0x00, 0x54 }, { 0x08, 0x1D, 0x54 },
+ { 0x13, 0x17, 0x00 }, { 0x00, 0x64, 0x00 }, { 0x29, 0x15, 0x00 }, { 0x00, 0x64, 0x00 },
+ { 0x59, 0x0A, 0x00 }, { 0x30, 0x61, 0x00 }, { 0x7A, 0x06, 0x00 }, { 0x4A, 0x64, 0x00 },
+/* Composite hi-res, colour reg = 6 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x33, 0x00 }, { 0x06, 0x00, 0x5E }, { 0x00, 0x22, 0x45 },
+ { 0x34, 0x00, 0x04 }, { 0x00, 0x1e, 0x00 }, { 0x3d, 0x00, 0x4c }, { 0x0c, 0x22, 0x58 },
+ { 0x18, 0x19, 0x00 }, { 0x00, 0x62, 0x00 }, { 0x2b, 0x14, 0x00 }, { 0x01, 0x64, 0x00 },
+ { 0x57, 0x0f, 0x00 }, { 0x29, 0x63, 0x00 }, { 0x78, 0x09, 0x00 }, { 0x51, 0x61, 0x00 },
+/* Composite hi-res, colour reg = 7 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x3C, 0x01 }, { 0x04, 0x00, 0xC5 }, { 0x00, 0x4C, 0xC7 },
+ { 0x6A, 0x00, 0x15 }, { 0x28, 0x28, 0x24 }, { 0x8A, 0x00, 0xF8 }, { 0x70, 0x61, 0xFF },
+ { 0x20, 0x33, 0x00 }, { 0x00, 0x85, 0x00 }, { 0x2E, 0x25, 0x28 }, { 0x00, 0x98, 0x3B },
+ { 0xb1, 0x11, 0x00 }, { 0x6A, 0x75, 0x00 }, { 0xcc, 0x16, 0x81 }, { 0x91, 0x8e, 0x91 },
+/* Composite hi-res, colour reg = 8 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x12, 0x0F }, { 0x04, 0x00, 0x5F }, { 0x00, 0x02, 0x67 },
+ { 0x31, 0x00, 0x01 }, { 0x04, 0x01, 0x04 }, { 0x37, 0x00, 0x52 }, { 0x17, 0x00, 0x6d },
+ { 0x00, 0x10, 0x00 }, { 0x00, 0x29, 0x00 }, { 0x04, 0x03, 0x04 }, { 0x00, 0x24, 0x16 },
+ { 0x2f, 0x00, 0x00 }, { 0x07, 0x23, 0x00 }, { 0x43, 0x00, 0x08 }, { 0x25, 0x23, 0x24 },
+/* Composite hi-res, colour reg = 9 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x19, 0x14 }, { 0x00, 0x00, 0xc2 }, { 0x00, 0x1c, 0xed },
+ { 0x5e, 0x00, 0x13 }, { 0x2c, 0x03, 0x3a }, { 0x78, 0x00, 0xfa }, { 0x49, 0x11, 0xff },
+ { 0x00, 0x15, 0x00 }, { 0x00, 0x40, 0x00 }, { 0x0d, 0x11, 0x68 }, { 0x00, 0x4f, 0x9c },
+ { 0x67, 0x00, 0x00 }, { 0x39, 0x36, 0x00 }, { 0x91, 0x05, 0xa6 }, { 0x62, 0x45, 0xdc },
+/* Composite hi-res, colour reg = A */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x4B, 0x08 }, { 0x05, 0x00, 0xAA }, { 0x00, 0x50, 0xc7 },
+ { 0x58, 0x00, 0x06 }, { 0x05, 0x44, 0x06 }, { 0x75, 0x00, 0xb0 }, { 0x2e, 0x4f, 0xdc },
+ { 0x0c, 0x2f, 0x00 }, { 0x00, 0xa7, 0x00 }, { 0x26, 0x2e, 0x03 }, { 0x00, 0xb4, 0x24 },
+ { 0x84, 0x1b, 0x00 }, { 0x2d, 0xa5, 0x00 }, { 0xa5, 0x2a, 0x16 }, { 0x5f, 0xb2, 0x2a },
+/* Composite hi-res, colour reg = B */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x59, 0x07 }, { 0x00, 0x08, 0xf0 }, { 0x00, 0x06, 0xfd },
+ { 0x69, 0x00, 0x09 }, { 0x0d, 0x4c, 0x10 }, { 0x8f, 0x00, 0xf4 }, { 0x38, 0x66, 0xff },
+ { 0x02, 0x27, 0x00 }, { 0x00, 0xac, 0x00 }, { 0x19, 0x2f, 0x6d }, { 0x00, 0xc5, 0x82 },
+ { 0x7b, 0x18, 0x00 }, { 0x30, 0xa7, 0x00 }, { 0xac, 0x2b, 0x81 }, { 0x5b, 0xc0, 0xa4 },
+/* Composite hi-res, colour reg = C */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x1C, 0x0C }, { 0x0a, 0x00, 0x7c }, { 0x00, 0x0d, 0x8f },
+ { 0x6e, 0x00, 0x18 }, { 0x48, 0x02, 0x4a }, { 0x95, 0x00, 0xc3 }, { 0x68, 0x01, 0xef },
+ { 0x12, 0x1d, 0x00 }, { 0x00, 0x53, 0x00 }, { 0x33, 0x21, 0x00 }, { 0x05, 0x52, 0x13 },
+ { 0xb4, 0x09, 0x00 }, { 0x87, 0x41, 0x00 }, { 0xd8, 0x07, 0x3a }, { 0xb0, 0x49, 0x63 },
+/* Composite hi-res, colour reg = D */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x1d, 0x17 }, { 0x00, 0x08, 0xcf }, { 0x00, 0x1b, 0xf2 },
+ { 0x83, 0x00, 0x30 }, { 0x4c, 0x08, 0x53 }, { 0xae, 0x00, 0xfa }, { 0x85, 0x0b, 0xff },
+ { 0x09, 0x19, 0x00 }, { 0x00, 0x57, 0x00 }, { 0x21, 0x15, 0x4f }, { 0x00, 0x5e, 0x89 },
+ { 0xb0, 0x04, 0x00 }, { 0x76, 0x4e, 0x00 }, { 0xe2, 0x0a, 0xa9 }, { 0xae, 0x56, 0xe1 },
+/* Composite hi-res, colour reg = E */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x57, 0x06 }, { 0x17, 0x00, 0xc3 }, { 0x00, 0x55, 0xd9 },
+ { 0x6f, 0x00, 0x06 }, { 0x18, 0x49, 0x0d }, { 0xa4, 0x00, 0xcd }, { 0x4e, 0x4c, 0xf7 },
+ { 0x1c, 0x3f, 0x00 }, { 0x00, 0xbf, 0x00 }, { 0x51, 0x35, 0x00 }, { 0x06, 0xc4, 0x1b },
+ { 0xb6, 0x2d, 0x00 }, { 0x73, 0xb2, 0x00 }, { 0xf5, 0x30, 0x21 }, { 0xaa, 0xbf, 0x2f },
+/* Composite hi-res, colour reg = F */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x68, 0x10 }, { 0x10, 0x00, 0xff }, { 0x00, 0x7c, 0xFF },
+ { 0xb3, 0x00, 0x2A }, { 0x53, 0x55, 0x51 }, { 0xf0, 0x00, 0xff }, { 0x95, 0x72, 0xff },
+ { 0x25, 0x3e, 0x00 }, { 0x00, 0xda, 0x00 }, { 0x58, 0x52, 0x56 }, { 0x00, 0xf8, 0x7f },
+ { 0xf8, 0x2c, 0x00 }, { 0xa8, 0xcf, 0x00 }, { 0xff, 0x41, 0xb8 }, { 0xed, 0xea, 0xed },
+/* Composite lo-res, colour reg = 0 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x26, 0x34 }, { 0x00, 0x00, 0x24 }, { 0x00, 0x25, 0x46 },
+ { 0x29, 0x03, 0x00 }, { 0x04, 0x55, 0x00 }, { 0x1f, 0x0c, 0x00 }, { 0x0e, 0x53, 0x03 },
+ { 0x50, 0x00, 0x00 }, { 0x33, 0x36, 0x2b }, { 0x51, 0x00, 0x0b }, { 0x43, 0x37, 0x44 },
+ { 0x60, 0x07, 0x00 }, { 0x3c, 0x61, 0x00 }, { 0x59, 0x1c, 0x00 }, { 0x4a, 0x64, 0x00 },
+/* Composite lo-res, colour reg = 1 */
+ { 0x07, 0x00, 0x7d }, { 0x00, 0x21, 0x4e }, { 0x15, 0x00, 0x36 }, { 0x04, 0x19, 0x77 },
+ { 0x16, 0x1a, 0x00 }, { 0x04, 0x55, 0x00 }, { 0x23, 0x0b, 0x00 }, { 0x13, 0x51, 0x03 },
+ { 0x41, 0x02, 0x3e }, { 0x2e, 0x33, 0x24 }, { 0x51, 0x00, 0x14 }, { 0x41, 0x33, 0x46 },
+ { 0x51, 0x2b, 0x00 }, { 0x3f, 0x60, 0x00 }, { 0x60, 0x17, 0x00 }, { 0x4d, 0x61, 0x00 },
+/* Composite lo-res, colour reg = 2 */
+ { 0x03, 0x55, 0x00 }, { 0x03, 0x55, 0x00 }, { 0x21, 0x0c, 0x00 }, { 0x11, 0x51, 0x03 },
+ { 0x03, 0x55, 0x00 }, { 0x03, 0x55, 0x00 }, { 0x21, 0x0c, 0x00 }, { 0x11, 0x51, 0x03 },
+ { 0x31, 0x37, 0x29 }, { 0x30, 0x36, 0x2a }, { 0x51, 0x00, 0x11 }, { 0x41, 0x34, 0x46 },
+ { 0x3c, 0x63, 0x00 }, { 0x3d, 0x63, 0x00 }, { 0x5f, 0x17, 0x00 }, { 0x4d, 0x61, 0x00 },
+/* Composite lo-res, colour reg = 3 */
+ { 0x04, 0x61, 0x4e }, { 0x05, 0x49, 0x02 }, { 0x1f, 0x04, 0x00 }, { 0x12, 0x47, 0x13 },
+ { 0x03, 0x68, 0x2f }, { 0x05, 0x54, 0x00 }, { 0x1e, 0x0e, 0x00 }, { 0x0f, 0x51, 0x01 },
+ { 0x26, 0x46, 0x73 }, { 0x2f, 0x34, 0x27 }, { 0x50, 0x00, 0x0b }, { 0x48, 0x31, 0x47 },
+ { 0x3e, 0x70, 0x1e }, { 0x40, 0x5f, 0x00 }, { 0x57, 0x1d, 0x00 }, { 0x4a, 0x62, 0x00 },
+/* Composite lo-res, colour reg = 4 */
+ { 0x52, 0x00, 0x14 }, { 0x2e, 0x32, 0x25 }, { 0x52, 0x00, 0x14 }, { 0x46, 0x2f, 0x47 },
+ { 0x1f, 0x09, 0x00 }, { 0x04, 0x55, 0x00 }, { 0x21, 0x0e, 0x00 }, { 0x11, 0x50, 0x02 },
+ { 0x52, 0x00, 0x14 }, { 0x2d, 0x33, 0x25 }, { 0x52, 0x00, 0x14 }, { 0x40, 0x36, 0x3f },
+ { 0x5c, 0x18, 0x00 }, { 0x40, 0x5f, 0x00 }, { 0x5e, 0x19, 0x00 }, { 0x4b, 0x62, 0x00 },
+/* Composite lo-res, colour reg = 5 */
+ { 0x51, 0x00, 0x81 }, { 0x2a, 0x2a, 0x3f }, { 0x4f, 0x00, 0x1c }, { 0x3b, 0x2b, 0x5c },
+ { 0x22, 0x1b, 0x13 }, { 0x04, 0x55, 0x00 }, { 0x21, 0x0e, 0x00 }, { 0x0e, 0x52, 0x04 },
+ { 0x4c, 0x03, 0x59 }, { 0x2e, 0x32, 0x25 }, { 0x51, 0x00, 0x0b }, { 0x3e, 0x37, 0x3d },
+ { 0x5d, 0x2a, 0x03 }, { 0x3d, 0x60, 0x00 }, { 0x5d, 0x19, 0x00 }, { 0x4a, 0x63, 0x00 },
+/* Composite lo-res, colour reg = 6 */
+ { 0x4b, 0x60, 0x00 }, { 0x41, 0x5f, 0x00 }, { 0x5b, 0x1a, 0x00 }, { 0x4b, 0x60, 0x00 },
+ { 0x0e, 0x51, 0x03 }, { 0x03, 0x55, 0x00 }, { 0x22, 0x0b, 0x00 }, { 0x12, 0x51, 0x03 },
+ { 0x41, 0x34, 0x47 }, { 0x31, 0x37, 0x29 }, { 0x50, 0x00, 0x10 }, { 0x3f, 0x32, 0x43 },
+ { 0x4b, 0x60, 0x00 }, { 0x3d, 0x61, 0x00 }, { 0x62, 0x16, 0x00 }, { 0x4b, 0x60, 0x00 },
+/* Composite lo-res, colour reg = 7 */
+ { 0x8b, 0x8b, 0x8b }, { 0x83, 0x5b, 0x00 }, { 0xa4, 0x1b, 0x00 }, { 0x92, 0x5a, 0x09 },
+ { 0x07, 0x79, 0x6f }, { 0x06, 0x55, 0x00 }, { 0x1f, 0x0d, 0x00 }, { 0x10, 0x52, 0x01 },
+ { 0x23, 0x62, 0xa4 }, { 0x2b, 0x33, 0x29 }, { 0x51, 0x00, 0x11 }, { 0x40, 0x36, 0x42 },
+ { 0x46, 0x86, 0x63 }, { 0x42, 0x5e, 0x00 }, { 0x5e, 0x17, 0x00 }, { 0x4a, 0x62, 0x00 },
+/* Composite lo-res, colour reg = 8 */
+ { 0x26, 0x26, 0x26 }, { 0x0a, 0x49, 0x00 }, { 0x25, 0x07, 0x00 }, { 0x16, 0x4c, 0x0e },
+ { 0x1c, 0x29, 0x12 }, { 0x06, 0x55, 0x00 }, { 0x21, 0x0c, 0x00 }, { 0x11, 0x51, 0x02 },
+ { 0x4d, 0x10, 0x5f }, { 0x2c, 0x33, 0x26 }, { 0x51, 0x00, 0x0f }, { 0x41, 0x35, 0x47 },
+ { 0x5a, 0x35, 0x00 }, { 0x43, 0x5f, 0x00 }, { 0x5f, 0x15, 0x00 }, { 0x4d, 0x62, 0x00 },
+/* Composite lo-res, colour reg = 9 */
+ { 0x92, 0x47, 0xd3 }, { 0x47, 0x47, 0x1b }, { 0x66, 0x00, 0x09 }, { 0x54, 0x44, 0x37 },
+ { 0x15, 0x4b, 0x8a }, { 0x05, 0x55, 0x00 }, { 0x00, 0x10, 0x00 }, { 0x10, 0x52, 0x02 },
+ { 0x40, 0x33, 0xd4 }, { 0x2f, 0x33, 0x26 }, { 0x51, 0x00, 0x0d }, { 0x3e, 0x37, 0x3e },
+ { 0x51, 0x59, 0x75 }, { 0x3b, 0x63, 0x00 }, { 0x5b, 0x1a, 0x00 }, { 0x49, 0x64, 0x00 },
+/* Composite lo-res, colour reg = A */
+ { 0x57, 0xac, 0x33 }, { 0x54, 0x7f, 0x00 }, { 0x7f, 0x2e, 0x00 }, { 0x6a, 0x77, 0x00 },
+ { 0x05, 0x80, 0x70 }, { 0x03, 0x54, 0x00 }, { 0x22, 0x0c, 0x00 }, { 0x13, 0x52, 0x00 },
+ { 0x31, 0x64, 0xbe }, { 0x30, 0x35, 0x2a }, { 0x52, 0x00, 0x12 }, { 0x41, 0x33, 0x46 },
+ { 0x3c, 0x91, 0x50 }, { 0x3c, 0x62, 0x00 }, { 0x60, 0x15, 0x00 }, { 0x4f, 0x61, 0x00 },
+/* Composite lo-res, colour reg = B */
+ { 0x5b, 0xb9, 0xa7 }, { 0x5b, 0x6d, 0x00 }, { 0x7f, 0x29, 0x00 }, { 0x6c, 0x6e, 0x00 },
+ { 0x05, 0x95, 0xcb }, { 0x04, 0x54, 0x00 }, { 0x23, 0x0a, 0x00 }, { 0x12, 0x51, 0x02 },
+ { 0x28, 0x77, 0xfb }, { 0x32, 0x37, 0x2f }, { 0x52, 0x00, 0x12 }, { 0x3e, 0x34, 0x40 },
+ { 0x3a, 0xa3, 0xaf }, { 0x3c, 0x63, 0x00 }, { 0x60, 0x15, 0x00 }, { 0x50, 0x61, 0x00 },
+/* Composite lo-res, colour reg = C */
+ { 0xaa, 0x45, 0x6a }, { 0x8c, 0x59, 0x00 }, { 0xa8, 0x1a, 0x00 }, { 0x96, 0x60, 0x05 },
+ { 0x20, 0x35, 0x41 }, { 0x03, 0x55, 0x00 }, { 0x22, 0x0b, 0x00 }, { 0x10, 0x52, 0x02 },
+ { 0x4f, 0x1e, 0xa2 }, { 0x2e, 0x34, 0x25 }, { 0x50, 0x00, 0x10 }, { 0x42, 0x36, 0x45 },
+ { 0x56, 0x48, 0x2a }, { 0x41, 0x5e, 0x00 }, { 0x5d, 0x19, 0x00 }, { 0x49, 0x64, 0x00 },
+/* Composite lo-res, colour reg = D */
+ { 0xa9, 0x54, 0xd6 }, { 0x85, 0x52, 0x09 }, { 0xa5, 0x17, 0x00 }, { 0x96, 0x52, 0x23 },
+ { 0x1e, 0x48, 0x9f }, { 0x06, 0x55, 0x00 }, { 0x1f, 0x0c, 0x00 }, { 0x0f, 0x52, 0x01 },
+ { 0x46, 0x35, 0xe1 }, { 0x2b, 0x32, 0x26 }, { 0x51, 0x00, 0x0e }, { 0x3e, 0x39, 0x3e },
+ { 0x5d, 0x58, 0x88 }, { 0x41, 0x60, 0x00 }, { 0x57, 0x1c, 0x00 }, { 0x4a, 0x62, 0x00 },
+/* Composite lo-res, colour reg = E */
+ { 0xa4, 0xbb, 0x30 }, { 0x9d, 0x84, 0x00 }, { 0xb6, 0x3f, 0x00 }, { 0xa1, 0x8c, 0x00 },
+ { 0x14, 0x7b, 0x8a }, { 0x06, 0x55, 0x00 }, { 0x21, 0x0b, 0x00 }, { 0x13, 0x51, 0x02 },
+ { 0x3f, 0x67, 0xd5 }, { 0x2d, 0x36, 0x29 }, { 0x52, 0x00, 0x11 }, { 0x41, 0x33, 0x46 },
+ { 0x4c, 0x8e, 0x6e }, { 0x3e, 0x61, 0x00 }, { 0x5f, 0x16, 0x00 }, { 0x4c, 0x61, 0x00 },
+/* Composite lo-res, colour reg = F */
+ { 0xe3, 0xe3, 0xe3 }, { 0xdb, 0x82, 0x00 }, { 0xf5, 0x43, 0x00 }, { 0xee, 0x83, 0x00 },
+ { 0x08, 0xa6, 0xf5 }, { 0x04, 0x53, 0x00 }, { 0x1c, 0x0d, 0x00 }, { 0x13, 0x52, 0x00 },
+ { 0x25, 0x91, 0xfc }, { 0x2c, 0x35, 0x30 }, { 0x51, 0x00, 0x0e }, { 0x3b, 0x36, 0x38 },
+ { 0x43, 0xb5, 0xf7 }, { 0x3b, 0x62, 0x00 }, { 0x56, 0x1c, 0x00 }, { 0x4d, 0x61, 0x00 },
+/* Composite lo-res, colour reg = 10 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x58, 0xb9 }, { 0x00, 0x11, 0x8a }, { 0x00, 0x4a, 0xe1 },
+ { 0x73, 0x22, 0x00 }, { 0x5a, 0xad, 0x2e }, { 0x78, 0x61, 0x0d }, { 0x6a, 0xa9, 0x4c },
+ { 0xac, 0x0a, 0x00 }, { 0x87, 0x8d, 0x80 }, { 0xab, 0x46, 0x6c }, { 0x95, 0x8b, 0x97 },
+ { 0xac, 0x30, 0x00 }, { 0x91, 0xbc, 0x16 }, { 0xb8, 0x6d, 0x07 }, { 0xa7, 0xb9, 0x2d },
+/* Composite lo-res, colour reg = 11 */
+ { 0x60, 0x00, 0x7c }, { 0x01, 0x54, 0xdb }, { 0x09, 0x11, 0xb9 }, { 0x07, 0x47, 0xf8 },
+ { 0x76, 0x46, 0x02 }, { 0x5a, 0xae, 0x2e }, { 0x78, 0x62, 0x0c }, { 0x68, 0xa9, 0x4b },
+ { 0x99, 0x2a, 0x09 }, { 0x87, 0x8d, 0x80 }, { 0xab, 0x46, 0x6b }, { 0x93, 0x89, 0x95 },
+ { 0xa4, 0x54, 0x00 }, { 0x93, 0xbb, 0x16 }, { 0xb9, 0x6b, 0x04 }, { 0xa4, 0xb9, 0x30 },
+/* Composite lo-res, colour reg = 12 */
+ { 0x07, 0x55, 0x00 }, { 0x03, 0x83, 0x70 }, { 0x1c, 0x3a, 0x42 }, { 0x0e, 0x81, 0x82 },
+ { 0x58, 0x7e, 0x00 }, { 0x5b, 0xad, 0x2f }, { 0x77, 0x60, 0x0f }, { 0x67, 0xac, 0x49 },
+ { 0x87, 0x5a, 0x00 }, { 0x89, 0x8c, 0x81 }, { 0xa9, 0x49, 0x5e }, { 0x9b, 0x8a, 0x96 },
+ { 0x9f, 0x83, 0x00 }, { 0x94, 0xb9, 0x19 }, { 0xb0, 0x72, 0x03 }, { 0xa5, 0xbb, 0x30 },
+/* Composite lo-res, colour reg = 13 */
+ { 0x03, 0x63, 0x48 }, { 0x04, 0x76, 0x8c }, { 0x1d, 0x34, 0x5a }, { 0x0d, 0x7a, 0x9c },
+ { 0x5a, 0x8e, 0x03 }, { 0x58, 0xac, 0x33 }, { 0x76, 0x60, 0x0b }, { 0x68, 0xaa, 0x4b },
+ { 0x7e, 0x6e, 0x3b }, { 0x88, 0x8c, 0x80 }, { 0xaa, 0x48, 0x64 }, { 0x94, 0x91, 0x92 },
+ { 0x94, 0x9b, 0x00 }, { 0x96, 0xb9, 0x16 }, { 0xb0, 0x73, 0x01 }, { 0xa7, 0xb8, 0x2e },
+/* Composite lo-res, colour reg = 14 */
+ { 0x52, 0x00, 0x13 }, { 0x29, 0x61, 0xb6 }, { 0x52, 0x1e, 0xa1 }, { 0x41, 0x63, 0xdb },
+ { 0x7b, 0x2f, 0x00 }, { 0x5d, 0xac, 0x2c }, { 0x77, 0x63, 0x0a }, { 0x67, 0xa9, 0x51 },
+ { 0xaf, 0x18, 0x00 }, { 0x83, 0x8a, 0x7d }, { 0xa9, 0x46, 0x66 }, { 0x9a, 0x8c, 0xa0 },
+ { 0xb1, 0x43, 0x00 }, { 0x9a, 0xb7, 0x19 }, { 0xb7, 0x6e, 0x05 }, { 0xa4, 0xb9, 0x2f },
+/* Composite lo-res, colour reg = 15 */
+ { 0x52, 0x00, 0x7a }, { 0x2e, 0x55, 0xdc }, { 0x4e, 0x1b, 0xb1 }, { 0x3c, 0x55, 0xec },
+ { 0x80, 0x3f, 0x00 }, { 0x5b, 0xad, 0x2e }, { 0x73, 0x61, 0x0a }, { 0x66, 0xaa, 0x50 },
+ { 0xa7, 0x29, 0x29 }, { 0x86, 0x8a, 0x7d }, { 0xa8, 0x48, 0x60 }, { 0x98, 0x8e, 0x9b },
+ { 0xc0, 0x4a, 0x00 }, { 0x9a, 0xb5, 0x18 }, { 0xb3, 0x72, 0x06 }, { 0xa2, 0xba, 0x31 },
+/* Composite lo-res, colour reg = 16 */
+ { 0x4d, 0x61, 0x00 }, { 0x3b, 0x91, 0x53 }, { 0x59, 0x46, 0x2c }, { 0x48, 0x95, 0x63 },
+ { 0x6c, 0x77, 0x00 }, { 0x5a, 0xac, 0x31 }, { 0x75, 0x63, 0x09 }, { 0x66, 0xa9, 0x4e },
+ { 0x8e, 0x6a, 0x0f }, { 0x87, 0x8b, 0x7f }, { 0xa9, 0x47, 0x66 }, { 0x9b, 0x8c, 0x9f },
+ { 0xab, 0x86, 0x00 }, { 0x9a, 0xb6, 0x18 }, { 0xae, 0x74, 0x01 }, { 0xa2, 0xba, 0x2f },
+/* Composite lo-res, colour reg = 17 */
+ { 0x8b, 0x8b, 0x8b }, { 0x7f, 0x89, 0x79 }, { 0xa4, 0x4a, 0x5c }, { 0x96, 0x8a, 0x95 },
+ { 0x5c, 0xa1, 0x36 }, { 0x5d, 0xad, 0x2b }, { 0x77, 0x62, 0x0a }, { 0x68, 0xa8, 0x4f },
+ { 0x83, 0x88, 0x6f }, { 0x85, 0x8d, 0x81 }, { 0xa9, 0x46, 0x69 }, { 0x99, 0x8b, 0x9f },
+ { 0x97, 0xb1, 0x22 }, { 0x99, 0xb7, 0x18 }, { 0xb8, 0x6c, 0x04 }, { 0xa2, 0xba, 0x2e },
+/* Composite lo-res, colour reg = 18 */
+ { 0x25, 0x25, 0x25 }, { 0x0b, 0x78, 0x8b }, { 0x25, 0x34, 0x5a }, { 0x14, 0x7d, 0x9d },
+ { 0x76, 0x4f, 0x00 }, { 0x5a, 0xac, 0x2e }, { 0x74, 0x64, 0x07 }, { 0x66, 0xaa, 0x49 },
+ { 0xa7, 0x37, 0x25 }, { 0x87, 0x8b, 0x80 }, { 0xa8, 0x48, 0x64 }, { 0x9a, 0x8f, 0x9a },
+ { 0xb6, 0x5a, 0x00 }, { 0x96, 0xba, 0x17 }, { 0xae, 0x73, 0x01 }, { 0xa2, 0xba, 0x30 },
+/* Composite lo-res, colour reg = 19 */
+ { 0x5d, 0x48, 0xd5 }, { 0x4a, 0x77, 0xb3 }, { 0x65, 0x35, 0x86 }, { 0x4d, 0x77, 0xc2 },
+ { 0x6f, 0x72, 0x53 }, { 0x5a, 0xac, 0x30 }, { 0x75, 0x62, 0x09 }, { 0x68, 0xa9, 0x48 },
+ { 0x9c, 0x57, 0xa1 }, { 0x87, 0x8b, 0x80 }, { 0xa7, 0x49, 0x62 }, { 0x92, 0x90, 0x92 },
+ { 0xab, 0x7d, 0x3a }, { 0x97, 0xb8, 0x17 }, { 0xb0, 0x74, 0x03 }, { 0xa2, 0xba, 0x2e },
+/* Composite lo-res, colour reg = 1A */
+ { 0x59, 0xad, 0x2e }, { 0x59, 0xad, 0x2e }, { 0x75, 0x64, 0x08 }, { 0x69, 0xa7, 0x4d },
+ { 0x59, 0xad, 0x2e }, { 0x59, 0xad, 0x2e }, { 0x75, 0x64, 0x08 }, { 0x69, 0xa7, 0x4d },
+ { 0x87, 0x8d, 0x82 }, { 0x85, 0x8b, 0x7d }, { 0xa9, 0x47, 0x67 }, { 0x99, 0x8c, 0x9d },
+ { 0x94, 0xba, 0x17 }, { 0x94, 0xba, 0x17 }, { 0xb6, 0x6e, 0x06 }, { 0xa2, 0xbb, 0x30 },
+/* Composite lo-res, colour reg = 1B */
+ { 0x5b, 0xb9, 0xa6 }, { 0x5c, 0xa2, 0x4a }, { 0x7a, 0x5c, 0x24 }, { 0x6a, 0x9a, 0x6c },
+ { 0x56, 0xbf, 0x8e }, { 0x59, 0xae, 0x31 }, { 0x78, 0x60, 0x0d }, { 0x68, 0xa9, 0x4f },
+ { 0x7f, 0xa3, 0xcd }, { 0x85, 0x8c, 0x80 }, { 0xaa, 0x47, 0x6a }, { 0x98, 0x8b, 0x9c },
+ { 0x93, 0xcd, 0x72 }, { 0x92, 0xbd, 0x14 }, { 0xb8, 0x6c, 0x06 }, { 0xa4, 0xb9, 0x2f },
+/* Composite lo-res, colour reg = 1C */
+ { 0xa9, 0x44, 0x63 }, { 0x85, 0x8a, 0x7f }, { 0xa9, 0x44, 0x63 }, { 0x99, 0x8e, 0x9d },
+ { 0x74, 0x5f, 0x0d }, { 0x5c, 0xad, 0x2c }, { 0x77, 0x63, 0x0a }, { 0x68, 0xa8, 0x4e },
+ { 0xa9, 0x44, 0x63 }, { 0x84, 0x8b, 0x7e }, { 0xa9, 0x44, 0x63 }, { 0x99, 0x8c, 0x9e },
+ { 0xad, 0x72, 0x01 }, { 0x9b, 0xb6, 0x1a }, { 0xb3, 0x6e, 0x05 }, { 0xa4, 0xb9, 0x2f },
+/* Composite lo-res, colour reg = 1D */
+ { 0xaa, 0x55, 0xd4 }, { 0x83, 0x81, 0x9b }, { 0xa6, 0x43, 0x7b }, { 0x95, 0x80, 0xbd },
+ { 0x76, 0x72, 0x66 }, { 0x5a, 0xad, 0x2c }, { 0x7b, 0x61, 0x0c }, { 0x68, 0xa9, 0x50 },
+ { 0xa5, 0x59, 0xaa }, { 0x87, 0x8e, 0x7f }, { 0xa9, 0x45, 0x6a }, { 0x97, 0x8b, 0x98 },
+ { 0xb2, 0x82, 0x48 }, { 0x93, 0xbb, 0x16 }, { 0xb9, 0x6d, 0x05 }, { 0xa4, 0xb9, 0x2f },
+/* Composite lo-res, colour reg = 1E */
+ { 0xa5, 0xb8, 0x2d }, { 0xa5, 0xb8, 0x2d }, { 0xb4, 0x70, 0x05 }, { 0xa5, 0xb8, 0x2d },
+ { 0x64, 0xaa, 0x4e }, { 0x5b, 0xad, 0x2c }, { 0x77, 0x63, 0x0b }, { 0x68, 0xa8, 0x4f },
+ { 0x94, 0x91, 0x95 }, { 0x83, 0x8a, 0x7b }, { 0xa9, 0x47, 0x67 }, { 0x98, 0x8a, 0x9e },
+ { 0xa5, 0xb8, 0x2d }, { 0x9a, 0xb6, 0x1a }, { 0xb2, 0x70, 0x05 }, { 0xa5, 0xb8, 0x2d },
+/* Composite lo-res, colour reg = 1F */
+ { 0xe3, 0xe3, 0xe3 }, { 0xde, 0xb1, 0x45 }, { 0xf8, 0x71, 0x3e }, { 0xeb, 0xb3, 0x5e },
+ { 0x58, 0xd3, 0xc4 }, { 0x5b, 0xad, 0x2d }, { 0x78, 0x63, 0x0b }, { 0x68, 0xa8, 0x4f },
+ { 0x7f, 0xb7, 0xf4 }, { 0x86, 0x8b, 0x7d }, { 0xa8, 0x46, 0x69 }, { 0x9a, 0x8c, 0x9f },
+ { 0x99, 0xe0, 0xbc }, { 0x99, 0xb6, 0x1a }, { 0xb8, 0x6d, 0x07 }, { 0xa5, 0xb8, 0x30 },
+/* Composite lo-res, colour reg = 20 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x3a, 0x85 }, { 0x00, 0x00, 0x6c }, { 0x00, 0x46, 0xce },
+ { 0x26, 0x01, 0x00 }, { 0x03, 0x61, 0x4a }, { 0x24, 0x16, 0x2a }, { 0x09, 0x72, 0x8d },
+ { 0x4d, 0x00, 0x00 }, { 0x2d, 0x45, 0x9c }, { 0x51, 0x00, 0x7c }, { 0x30, 0x58, 0xe1 },
+ { 0x9e, 0x0f, 0x00 }, { 0x86, 0x7b, 0x45 }, { 0xab, 0x29, 0x2c }, { 0x8b, 0x89, 0x88 },
+/* Composite lo-res, colour reg = 21 */
+ { 0x06, 0x00, 0x7C }, { 0x00, 0x3B, 0xA0 }, { 0x14, 0x00, 0x93 }, { 0x00, 0x49, 0xF7 },
+ { 0x19, 0x12, 0x13 }, { 0x02, 0x63, 0x3f }, { 0x25, 0x16, 0x2b }, { 0x09, 0x71, 0x93 },
+ { 0x46, 0x00, 0x65 }, { 0x28, 0x45, 0x93 }, { 0x50, 0x00, 0x80 }, { 0x32, 0x55, 0xe6 },
+ { 0x9c, 0x2d, 0x0c }, { 0x86, 0x78, 0x44 }, { 0xaa, 0x29, 0x33 }, { 0x92, 0x84, 0x84 },
+/* Composite lo-res, colour reg = 22 */
+ { 0x05, 0x56, 0x00 }, { 0x04, 0x69, 0x32 }, { 0x21, 0x1d, 0x13 }, { 0x07, 0x76, 0x7e },
+ { 0x05, 0x48, 0x03 }, { 0x03, 0x64, 0x43 }, { 0x24, 0x16, 0x28 }, { 0x08, 0x70, 0x92 },
+ { 0x45, 0x41, 0x74 }, { 0x27, 0x44, 0x92 }, { 0x4f, 0x00, 0x7f }, { 0x36, 0x58, 0xe8 },
+ { 0x85, 0x57, 0x02 }, { 0x87, 0x77, 0x45 }, { 0xa6, 0x2c, 0x2c }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 23 */
+ { 0x02, 0x61, 0x49 }, { 0x02, 0x61, 0x49 }, { 0x24, 0x15, 0x27 }, { 0x05, 0x73, 0x84 },
+ { 0x02, 0x61, 0x49 }, { 0x02, 0x61, 0x49 }, { 0x24, 0x15, 0x27 }, { 0x05, 0x73, 0x84 },
+ { 0x2a, 0x43, 0x96 }, { 0x2a, 0x43, 0x96 }, { 0x51, 0x00, 0x7d }, { 0x31, 0x5a, 0xdc },
+ { 0x86, 0x79, 0x3d }, { 0x86, 0x79, 0x3d }, { 0xa8, 0x2a, 0x21 }, { 0x8a, 0x8a, 0x8a },
+/* Composite lo-res, colour reg = 24 */
+ { 0x51, 0x00, 0x0e }, { 0x2b, 0x49, 0x76 }, { 0x4c, 0x04, 0x53 }, { 0x23, 0x5a, 0xf5 },
+ { 0x22, 0x05, 0x00 }, { 0x04, 0x06, 0x4b }, { 0x22, 0x13, 0x22 }, { 0x03, 0x74, 0x82 },
+ { 0x4e, 0x00, 0x25 }, { 0x2d, 0x46, 0x9d }, { 0x52, 0x00, 0x7c }, { 0x34, 0x59, 0xe3 },
+ { 0xaa, 0x17, 0x00 }, { 0x85, 0x79, 0x3d }, { 0xa7, 0x2e, 0x24 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 25 */
+ { 0x50, 0x00, 0x7e }, { 0x2d, 0x45, 0x9d }, { 0x50, 0x00, 0x7e }, { 0x30, 0x57, 0xde },
+ { 0x23, 0x16, 0x29 }, { 0x05, 0x61, 0x49 }, { 0x23, 0x13, 0x26 }, { 0x04, 0x75, 0x87 },
+ { 0x50, 0x00, 0x7e }, { 0x28, 0x44, 0x96 }, { 0x50, 0x00, 0x7e }, { 0x31, 0x59, 0xdf },
+ { 0xac, 0x28, 0x33 }, { 0x85, 0x79, 0x3c }, { 0xa7, 0x2d, 0x23 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 26 */
+ { 0x4f, 0x62, 0x00 }, { 0x3d, 0x71, 0x1f }, { 0x60, 0x2a, 0x07 }, { 0x43, 0x88, 0x69 },
+ { 0x13, 0x42, 0x19 }, { 0x05, 0x63, 0x46 }, { 0x24, 0x16, 0x27 }, { 0x07, 0x72, 0x91 },
+ { 0x3c, 0x2b, 0x5f }, { 0x2a, 0x45, 0x92 }, { 0x4f, 0x00, 0x82 }, { 0x36, 0x57, 0xe9 },
+ { 0x92, 0x5a, 0x0b }, { 0x87, 0x78, 0x45 }, { 0xa7, 0x2c, 0x2a }, { 0x8b, 0x8b, 0x8c },
+/* Composite lo-res, colour reg = 27 */
+ { 0x8b, 0x8b, 0x8b }, { 0x89, 0x78, 0x47 }, { 0xa8, 0x2a, 0x2d }, { 0x8b, 0x8b, 0x8b },
+ { 0x08, 0x71, 0x93 }, { 0x02, 0x62, 0x4a }, { 0x26, 0x16, 0x2a }, { 0x06, 0x73, 0x87 },
+ { 0x35, 0x58, 0xe6 }, { 0x2f, 0x45, 0x9e }, { 0x50, 0x00, 0x78 }, { 0x2f, 0x59, 0xe0 },
+ { 0x8b, 0x8b, 0x8b }, { 0x87, 0x7a, 0x46 }, { 0xaa, 0x29, 0x30 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 28 */
+ { 0x25, 0x25, 0x25 }, { 0x08, 0x5f, 0x4b }, { 0x2b, 0x15, 0x25 }, { 0x09, 0x71, 0x88 },
+ { 0x1e, 0x23, 0x26 }, { 0x04, 0x62, 0x47 }, { 0x21, 0x19, 0x28 }, { 0x06, 0x74, 0x88 },
+ { 0x48, 0x0b, 0x70 }, { 0x26, 0x42, 0x95 }, { 0x52, 0x00, 0x7c }, { 0x34, 0x58, 0xe6 },
+ { 0xa1, 0x37, 0x1c }, { 0x85, 0x78, 0x3e }, { 0xa6, 0x2e, 0x23 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 29 */
+ { 0x5e, 0x44, 0xd3 }, { 0x45, 0x61, 0x73 }, { 0x6c, 0x18, 0x53 }, { 0x4c, 0x72, 0xbf },
+ { 0x14, 0x45, 0xa3 }, { 0x04, 0x61, 0x49 }, { 0x22, 0x15, 0x25 }, { 0x06, 0x72, 0x8d },
+ { 0x41, 0x2d, 0xf6 }, { 0x27, 0x43, 0x96 }, { 0x51, 0x00, 0x7c }, { 0x34, 0x58, 0xe4 },
+ { 0x9b, 0x5a, 0xa5 }, { 0x85, 0x78, 0x3d }, { 0xa6, 0x2e, 0x23 }, { 0x8c, 0x8c, 0x8c },
+/* Composite lo-res, colour reg = 2A */
+ { 0x5c, 0xae, 0x2a }, { 0x58, 0x91, 0x00 }, { 0x7b, 0x41, 0x00 }, { 0x5e, 0xa0, 0x36 },
+ { 0x06, 0x78, 0x86 }, { 0x03, 0x62, 0x49 }, { 0x25, 0x14, 0x28 }, { 0x03, 0x74, 0x82 },
+ { 0x25, 0x5b, 0xcc }, { 0x2a, 0x43, 0x97 }, { 0x52, 0x00, 0x79 }, { 0x31, 0x5b, 0xe0 },
+ { 0x7e, 0x88, 0x7b }, { 0x86, 0x7b, 0x3e }, { 0xa7, 0x2c, 0x22 }, { 0x89, 0x89, 0x89 },
+/* Composite lo-res, colour reg = 2B */
+ { 0x58, 0xbb, 0x98 }, { 0x5a, 0x8c, 0x0a }, { 0x7f, 0x3b, 0x02 }, { 0x60, 0x9a, 0x4b },
+ { 0x03, 0x96, 0xce }, { 0x04, 0x61, 0x4a }, { 0x23, 0x14, 0x24 }, { 0x04, 0x75, 0x86 },
+ { 0x23, 0x76, 0xfe }, { 0x28, 0x43, 0x95 }, { 0x51, 0x00, 0x7b }, { 0x30, 0x59, 0xdb },
+ { 0x80, 0xab, 0xd2 }, { 0x85, 0x7a, 0x3d }, { 0xa8, 0x2e, 0x26 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 2C */
+ { 0xa9, 0x46, 0x66 }, { 0x7f, 0x6f, 0x37 }, { 0xa9, 0x27, 0x27 }, { 0x87, 0x82, 0x7f },
+ { 0x1e, 0x31, 0x5c }, { 0x04, 0x63, 0x44 }, { 0x23, 0x16, 0x2a }, { 0x08, 0x71, 0x92 },
+ { 0x4e, 0x1a, 0xb0 }, { 0x27, 0x46, 0x92 }, { 0x50, 0x00, 0x80 }, { 0x33, 0x56, 0xe7 },
+ { 0xa3, 0x4a, 0x58 }, { 0x87, 0x78, 0x46 }, { 0xab, 0x29, 0x34 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 2D */
+ { 0xa8, 0x53, 0xd8 }, { 0x82, 0x6c, 0x5f }, { 0xac, 0x25, 0x3f }, { 0x8d, 0x7f, 0xa8 },
+ { 0x21, 0x46, 0xb9 }, { 0x04, 0x61, 0x4d }, { 0x24, 0x13, 0x23 }, { 0x04, 0x75, 0x87 },
+ { 0x4c, 0x2e, 0xfe }, { 0x2a, 0x45, 0x99 }, { 0x52, 0x00, 0x78 }, { 0x32, 0x5a, 0xde },
+ { 0xa8, 0x53, 0xd8 }, { 0x84, 0x7c, 0x3d }, { 0xa7, 0x2d, 0x22 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 2E */
+ { 0xa4, 0xba, 0x2e }, { 0x8e, 0x9f, 0x00 }, { 0xbf, 0x4e, 0x00 }, { 0xa5, 0xae, 0x2d },
+ { 0x13, 0x71, 0xa6 }, { 0x03, 0x62, 0x4a }, { 0x24, 0x14, 0x28 }, { 0x05, 0x74, 0x83 },
+ { 0x32, 0x5d, 0xe0 }, { 0x2e, 0x46, 0x9c }, { 0x51, 0x00, 0x7c }, { 0x2f, 0x59, 0xe0 },
+ { 0x8a, 0x8d, 0x94 }, { 0x86, 0x7b, 0x40 }, { 0xa8, 0x2c, 0x22 }, { 0x8a, 0x8a, 0x8a },
+/* Composite lo-res, colour reg = 2F */
+ { 0xe4, 0xe4, 0xe4 }, { 0xdd, 0xa6, 0x0a }, { 0xf9, 0x53, 0x04 }, { 0xea, 0xae, 0x54 },
+ { 0x08, 0xa2, 0xfc }, { 0x03, 0x62, 0x48 }, { 0x24, 0x14, 0x28 }, { 0x05, 0x74, 0x84 },
+ { 0x27, 0x90, 0xff }, { 0x2a, 0x43, 0x95 }, { 0x52, 0x00, 0x79 }, { 0x34, 0x5a, 0xe3 },
+ { 0x85, 0xbb, 0xff }, { 0x85, 0x7a, 0x3d }, { 0xa7, 0x2c, 0x23 }, { 0x8a, 0x8a, 0x8a },
+/* Composite lo-res, colour reg = 30 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x63, 0xfe }, { 0x00, 0x1d, 0xe9 }, { 0x00, 0x81, 0xff },
+ { 0x7e, 0x16, 0x00 }, { 0x5b, 0xb9, 0xa5 }, { 0x79, 0x6a, 0x79 }, { 0x59, 0xce, 0xdc },
+ { 0xa8, 0x05, 0x00 }, { 0x84, 0x9e, 0xf3 }, { 0xaa, 0x54, 0xd3 }, { 0x8c, 0xb1, 0xff },
+ { 0xfb, 0x28, 0x00 }, { 0xde, 0xd2, 0x94 }, { 0xfc, 0x85, 0x7b }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 31 */
+ { 0x07, 0x00, 0x7c }, { 0x00, 0x70, 0xfe }, { 0x0d, 0x20, 0xff }, { 0x04, 0x7f, 0xff },
+ { 0x6f, 0x3b, 0x00 }, { 0x59, 0xbb, 0x9b }, { 0x79, 0x6c, 0x81 }, { 0x5d, 0xcb, 0xe4 },
+ { 0x99, 0x26, 0x29 }, { 0x83, 0x9d, 0xf2 }, { 0xaa, 0x54, 0xd4 }, { 0x88, 0xb0, 0xff },
+ { 0xf4, 0x57, 0x00 }, { 0xdf, 0xd3, 0x9a }, { 0xfe, 0x81, 0x7f }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 32 */
+ { 0x06, 0x55, 0x00 }, { 0x03, 0x99, 0xbe }, { 0x22, 0x46, 0xa4 }, { 0x09, 0xa4, 0xfa },
+ { 0x62, 0x6d, 0x00 }, { 0x59, 0xbb, 0x9b }, { 0x7a, 0x6d, 0x7e }, { 0x5c, 0xc8, 0xe7 },
+ { 0x8a, 0x4f, 0x11 }, { 0x80, 0x9b, 0xea }, { 0xa7, 0x55, 0xda }, { 0x8c, 0xad, 0xff },
+ { 0xdf, 0x7f, 0x00 }, { 0xe2, 0xd1, 0x9c }, { 0xfd, 0x81, 0x87 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 33 */
+ { 0x03, 0x63, 0x47 }, { 0x06, 0x91, 0xda }, { 0x23, 0x41, 0xbc }, { 0x06, 0xa5, 0xfa },
+ { 0x5d, 0x8a, 0x07 }, { 0x59, 0xbb, 0x9b }, { 0x7c, 0x6e, 0x80 }, { 0x5d, 0xc9, 0xe8 },
+ { 0x86, 0x6b, 0x60 }, { 0x81, 0x9d, 0xea }, { 0xa8, 0x55, 0xd8 }, { 0x8e, 0xae, 0xff },
+ { 0xdf, 0xa4, 0x0c }, { 0xe1, 0xd0, 0x9e }, { 0xfd, 0x81, 0x85 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 34 */
+ { 0x52, 0x00, 0x14 }, { 0x20, 0x7b, 0xf7 }, { 0x4e, 0x2f, 0xed }, { 0x22, 0x91, 0xff },
+ { 0x7f, 0x28, 0x00 }, { 0x5a, 0xbb, 0x9a }, { 0x79, 0x6d, 0x7f }, { 0x5e, 0xc8, 0xeb },
+ { 0xac, 0x13, 0x02 }, { 0x7e, 0x9c, 0xea }, { 0xa8, 0x54, 0xd6 }, { 0x8e, 0xae, 0xff },
+ { 0xf5, 0x43, 0x00 }, { 0xdf, 0xcf, 0x9d }, { 0xfd, 0x81, 0x88 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 35 */
+ { 0x50, 0x00, 0x7b }, { 0x22, 0x76, 0xfe }, { 0x4c, 0x2f, 0xff }, { 0x36, 0x85, 0xff },
+ { 0x7b, 0x3d, 0x00 }, { 0x5b, 0xbc, 0xa1 }, { 0x7b, 0x6c, 0x7f }, { 0x5d, 0xca, 0xe8 },
+ { 0xa9, 0x26, 0x3c }, { 0x81, 0x9c, 0xec }, { 0xa7, 0x54, 0xdc }, { 0x8b, 0xad, 0xff },
+ { 0xf8, 0x57, 0x03 }, { 0xe1, 0xd4, 0x9e }, { 0xfd, 0x80, 0x82 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 36 */
+ { 0x4c, 0x61, 0x00 }, { 0x39, 0xa2, 0xaf }, { 0x5b, 0x5a, 0x8c }, { 0x42, 0xb6, 0xf4 },
+ { 0x66, 0x6b, 0x00 }, { 0x5b, 0xba, 0xa4 }, { 0x7a, 0x6c, 0x7e }, { 0x5e, 0xca, 0xe8 },
+ { 0x91, 0x51, 0x1f }, { 0x85, 0x9d, 0xf4 }, { 0xaa, 0x55, 0xd7 }, { 0x88, 0xaf, 0xff },
+ { 0xea, 0x87, 0x00 }, { 0xde, 0xd4, 0x98 }, { 0xfd, 0x7f, 0x81 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 37 */
+ { 0x8b, 0x8b, 0x8b }, { 0x86, 0xa7, 0xde }, { 0xa6, 0x5a, 0xbf }, { 0x85, 0xbb, 0xff },
+ { 0x5f, 0x9b, 0x51 }, { 0x5a, 0xb9, 0xa7 }, { 0x78, 0x6a, 0x7b }, { 0x5b, 0xce, 0xdb },
+ { 0x8b, 0x7c, 0xae }, { 0x82, 0x9c, 0xf2 }, { 0xaa, 0x54, 0xd3 }, { 0x87, 0xb2, 0xff },
+ { 0xe7, 0xb0, 0x54 }, { 0xdc, 0xd2, 0x95 }, { 0xfc, 0x84, 0x77 }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 38 */
+ { 0x24, 0x24, 0x24 }, { 0x06, 0x91, 0xd8 }, { 0x2a, 0x44, 0xb9 }, { 0x0f, 0x9e, 0xfe },
+ { 0x7a, 0x49, 0x00 }, { 0x58, 0xbc, 0x98 }, { 0x7a, 0x6d, 0x7f }, { 0x5e, 0xc8, 0xeb },
+ { 0xa3, 0x36, 0x3a }, { 0x7f, 0x9c, 0xec }, { 0xa8, 0x54, 0xd7 }, { 0x8a, 0xad, 0xff },
+ { 0xf7, 0x64, 0x00 }, { 0xe1, 0xd1, 0x9c }, { 0xfd, 0x7f, 0x8b }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 39 */
+ { 0x62, 0x46, 0xd3 }, { 0x3d, 0x93, 0xf2 }, { 0x6b, 0x46, 0xeb }, { 0x4f, 0xa0, 0xff },
+ { 0x6f, 0x69, 0x6b }, { 0x58, 0xbb, 0x9b }, { 0x7b, 0x6e, 0x80 }, { 0x5e, 0xc8, 0xec },
+ { 0x9d, 0x53, 0xbd }, { 0x81, 0x9d, 0xf0 }, { 0xa8, 0x54, 0xd8 }, { 0x86, 0xb1, 0xff },
+ { 0xf4, 0x85, 0x5e }, { 0xdf, 0xd1, 0x9f }, { 0xfe, 0x7f, 0x88 }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 3A */
+ { 0x5a, 0xad, 0x2d }, { 0x58, 0xc1, 0x81 }, { 0x77, 0x74, 0x68 }, { 0x58, 0xcf, 0xd1 },
+ { 0x5d, 0xa0, 0x4d }, { 0x59, 0xbb, 0x9b }, { 0x7c, 0x6d, 0x7f }, { 0x5e, 0xc9, 0xeb },
+ { 0x83, 0x7d, 0x9e }, { 0x7f, 0x9c, 0xec }, { 0xa9, 0x54, 0xd6 }, { 0x8c, 0xae, 0xff },
+ { 0xde, 0xae, 0x4b }, { 0xdc, 0xd0, 0x98 }, { 0xfc, 0x81, 0x8a }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 3B */
+ { 0x59, 0xbc, 0x9c }, { 0x59, 0xbc, 0x9c }, { 0x7a, 0x6a, 0x79 }, { 0x59, 0xce, 0xd9 },
+ { 0x59, 0xbc, 0x9c }, { 0x59, 0xbc, 0x9c }, { 0x7b, 0x6b, 0x80 }, { 0x59, 0xcc, 0xd9 },
+ { 0x81, 0x9b, 0xec }, { 0x81, 0x9b, 0xec }, { 0xa9, 0x54, 0xd4 }, { 0x8e, 0xb2, 0xff },
+ { 0xdf, 0xcf, 0x9b }, { 0xdf, 0xcf, 0x9b }, { 0xfd, 0x85, 0x79 }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 3C */
+ { 0xaa, 0x46, 0x6a }, { 0x7a, 0xa3, 0xc7 }, { 0xa7, 0x58, 0xba }, { 0x84, 0xb5, 0xf8 },
+ { 0x78, 0x5b, 0x23 }, { 0x59, 0xbc, 0x9c }, { 0x7a, 0x6e, 0x81 }, { 0x5f, 0xc9, 0xeb },
+ { 0xa3, 0x44, 0x71 }, { 0x80, 0x9d, 0xec }, { 0xa8, 0x54, 0xd7 }, { 0x8a, 0xae, 0xff },
+ { 0xf8, 0x74, 0x1a }, { 0xdf, 0xd1, 0x9e }, { 0xfe, 0x81, 0x8b }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 3D */
+ { 0xaa, 0x53, 0xd1 }, { 0x80, 0x9c, 0xec }, { 0xaa, 0x53, 0xd1 }, { 0x88, 0xad, 0xff },
+ { 0x7a, 0x6b, 0x7e }, { 0x58, 0xbb, 0x9d }, { 0x7a, 0x6d, 0x81 }, { 0x5f, 0xc9, 0xe5 },
+ { 0xaa, 0x53, 0xd1 }, { 0x84, 0x9d, 0xf2 }, { 0xaa, 0x53, 0xd1 }, { 0x88, 0xad, 0xff },
+ { 0xfd, 0x85, 0x78 }, { 0xe0, 0xd2, 0x9e }, { 0xfe, 0x80, 0x87 }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 3E */
+ { 0xa1, 0xba, 0x2f }, { 0x90, 0xce, 0x70 }, { 0xb4, 0x80, 0x4b }, { 0x9d, 0xe0, 0xba },
+ { 0x6a, 0x9f, 0x68 }, { 0x5a, 0xba, 0x9f }, { 0x7a, 0x6b, 0x7a }, { 0x5a, 0xce, 0xdb },
+ { 0x91, 0x83, 0xae }, { 0x80, 0x9b, 0xef }, { 0xaa, 0x54, 0xd2 }, { 0x8c, 0xb1, 0xff },
+ { 0xeb, 0xb3, 0x59 }, { 0xdd, 0xd3, 0x94 }, { 0xfc, 0x85, 0x79 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 3F */
+ { 0xe4, 0xe4, 0xe4 }, { 0xdd, 0xd2, 0x93 }, { 0xfc, 0x85, 0x7a }, { 0xe4, 0xe4, 0xe4 },
+ { 0x59, 0xcc, 0xda }, { 0x59, 0xbb, 0x9c }, { 0x7b, 0x6d, 0x7f }, { 0x5c, 0xca, 0xe5 },
+ { 0x87, 0xb3, 0xff }, { 0x7f, 0x9a, 0xea }, { 0xa8, 0x54, 0xd4 }, { 0x8c, 0xb0, 0xff },
+ { 0xe4, 0xe4, 0xe4 }, { 0xdf, 0xd1, 0x98 }, { 0xfd, 0x84, 0x7d }, { 0xe4, 0xe4, 0xe4 },
+};
+
+
+static MC6845_UPDATE_ROW( cga_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ if ( cga->m_update_row )
+ {
+ cga->m_update_row( device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param );
+ }
+}
+
+
+static const mc6845_interface mc6845_cga_intf =
+{
+ CGA_SCREEN_NAME, /* screen number */
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ cga_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_cga_device, hsync_changed), /* on_hsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_cga_device, vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+#define CGA_HCLK (XTAL_14_31818MHz/8)
+#define CGA_LCLK (XTAL_14_31818MHz/16)
+
+
+static MACHINE_CONFIG_FRAGMENT( cga )
+ MCFG_SCREEN_ADD(CGA_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_14_31818MHz,912,0,640,262,0,200)
+ MCFG_SCREEN_UPDATE_DRIVER( isa8_cga_device, screen_update )
+
+ MCFG_PALETTE_LENGTH(/* CGA_PALETTE_SETS * 16*/ 65536 )
+
+ MCFG_MC6845_ADD(CGA_MC6845_NAME, MC6845, XTAL_14_31818MHz/8, mc6845_cga_intf)
+MACHINE_CONFIG_END
+
+
+ROM_START( cga )
+ /* IBM 1501981(CGA) and 1501985(MDA) Character rom */
+ ROM_REGION(0x2000,"gfx1", 0)
+ ROM_LOAD("5788005.u33", 0x00000, 0x2000, CRC(0bf56d70) SHA1(c2a8b10808bf51a3c123ba3eb1e9dd608231916f)) /* "AMI 8412PI // 5788005 // (C) IBM CORP. 1981 // KOREA" */
+ROM_END
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_CGA = &device_creator<isa8_cga_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_cga_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( cga );
+}
+
+ioport_constructor isa8_cga_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( cga );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_cga_device::device_rom_region() const
+{
+ return ROM_NAME( cga );
+}
+
+
+//-------------------------------------------------
+// isa8_cga_device - constructor
+//-------------------------------------------------
+
+isa8_cga_device::isa8_cga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_CGA, "IBM Color/Graphics Monitor Adapter", tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this),
+ m_vram_size( 0x4000 )
+{
+ m_chr_gen_offset[0] = m_chr_gen_offset[2] = 0x1800;
+ m_chr_gen_offset[1] = m_chr_gen_offset[3] = 0x1000;
+ m_font_selection_mask = 0x01;
+}
+
+isa8_cga_device::isa8_cga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this),
+ m_vram_size( 0x4000 )
+{
+ m_chr_gen_offset[0] = m_chr_gen_offset[2] = 0x1800;
+ m_chr_gen_offset[1] = m_chr_gen_offset[3] = 0x1000;
+ m_font_selection_mask = 0x01;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_cga_device::device_start()
+{
+ set_isa_device();
+ m_vram = auto_alloc_array(machine(), UINT8, m_vram_size);
+ m_update_row = NULL;
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_cga_device::io_read), this ), write8_delegate( FUNC(isa8_cga_device::io_write), this ) );
+ m_isa->install_bank(0xb8000, 0xb8000 + MIN(0x8000,m_vram_size) - 1, 0, m_vram_size & 0x4000, "bank_cga", m_vram);
+ m_superimpose = false;
+
+ /* Initialise the cga palette */
+ int i;
+
+ for ( i = 0; i < CGA_PALETTE_SETS * 16; i++ )
+ {
+ palette_set_color_rgb( machine(), i, cga_palette[i][0], cga_palette[i][1], cga_palette[i][2] );
+ }
+
+ i = 0x8000;
+ for ( int r = 0; r < 32; r++ )
+ {
+ for ( int g = 0; g < 32; g++ )
+ {
+ for ( int b = 0; b < 32; b++ )
+ {
+ palette_set_color_rgb( machine(), i, r << 3, g << 3, b << 3 );
+ i++;
+ }
+ }
+ }
+
+ astring tempstring;
+ m_chr_gen_base = memregion(subtag(tempstring, "gfx1"))->base();
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[1];
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_cga_device::device_reset()
+{
+ m_update_row = NULL;
+ m_framecnt = 0;
+ m_mode_control = 0;
+ m_vsync = 0;
+ m_hsync = 0;
+}
+
+/***************************************************************************
+
+ Methods
+
+***************************************************************************/
+
+
+const device_type ISA8_CGA_MC1502 = &device_creator<isa8_cga_mc1502_device>;
+
+//-------------------------------------------------
+// isa8_cga_mc1502_device - constructor
+//-------------------------------------------------
+
+isa8_cga_mc1502_device::isa8_cga_mc1502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_CGA_MC1502, "ISA8_CGA_MC1502", tag, owner, clock )
+{
+ m_vram_size = 0x8000;
+}
+
+
+ROM_START( mc1502 )
+ ROM_REGION(0x2000,"gfx1", 0)
+ ROM_LOAD( "symgen.rom", 0x0000, 0x2000, CRC(b2747a52) SHA1(6766d275467672436e91ac2997ac6b77700eba1e))
+ROM_END
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_cga_mc1502_device::device_rom_region() const
+{
+ return ROM_NAME( mc1502 );
+}
+
+UINT32 isa8_cga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+
+ mc6845->screen_update( screen, bitmap, cliprect);
+
+ /* Check for changes in font dipsetting */
+ switch ( CGA_FONT )
+ {
+ case 0:
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[0];
+ break;
+ case 1:
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[1];
+ break;
+ case 2:
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[2];
+ break;
+ case 3:
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[3];
+ break;
+ }
+ return 0;
+}
+
+
+const device_type ISA8_CGA_POISK1 = &device_creator<isa8_cga_poisk1_device>;
+
+//-------------------------------------------------
+// isa8_cga_poisk1_device - constructor
+//-------------------------------------------------
+
+isa8_cga_poisk1_device::isa8_cga_poisk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_CGA_POISK1, "ISA8_CGA_POISK1", tag, owner, clock )
+{
+ m_chr_gen_offset[0] = 0x0000;
+ m_font_selection_mask = 0;
+}
+
+ROM_START( cga_poisk1 )
+ ROM_REGION(0x2000,"gfx1", 0)
+ ROM_LOAD( "poisk.cga", 0x0000, 0x0800, CRC(f6eb39f0) SHA1(0b788d8d7a8e92cc612d044abcb2523ad964c200))
+ROM_END
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_cga_poisk1_device::device_rom_region() const
+{
+ return ROM_NAME( cga_poisk1 );
+}
+
+
+const device_type ISA8_CGA_POISK2 = &device_creator<isa8_cga_poisk2_device>;
+
+//-------------------------------------------------
+// isa8_cga_poisk2_device - constructor
+//-------------------------------------------------
+
+isa8_cga_poisk2_device::isa8_cga_poisk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_CGA_POISK2, "ISA8_CGA_POISK2", tag, owner, clock )
+{
+ m_chr_gen_offset[0] = 0x0000;
+ m_chr_gen_offset[1] = 0x0800;
+}
+
+ROM_START( cga_poisk2 )
+ ROM_REGION(0x2000,"gfx1", 0)
+ ROM_LOAD( "p2_ecga.rf4", 0x0000, 0x2000, CRC(d537f665) SHA1(d70f085b9b0cbd53df7c3122fbe7592998ba8fed))
+ROM_END
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_cga_poisk2_device::device_rom_region() const
+{
+ return ROM_NAME( cga_poisk2 );
+}
+
+
+/* for superimposing CGA over a different source video (i.e. tetriskr) */
+const device_type ISA8_CGA_SUPERIMPOSE = &device_creator<isa8_cga_superimpose_device>;
+
+//-------------------------------------------------
+// isa8_cga_superimpose_device - constructor
+//-------------------------------------------------
+
+isa8_cga_superimpose_device::isa8_cga_superimpose_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_CGA_SUPERIMPOSE, "ISA8_CGA_SUPERIMPOSE", tag, owner, clock )
+{
+ m_superimpose = true;
+}
+
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) with high intensity bg.
+ The character cell size is 16x8
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_inten_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_inten_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x0F;
+ UINT16 bg = attr >> 4;
+
+ if ( i == cursor_x && ( cga->m_framecnt & 0x08 ) )
+ {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) with high intensity bg.
+ The character cell size is 16x8. Composite monitor, greyscale.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_inten_comp_grey_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_inten_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = 0x10 + ( attr & 0x0F );
+ UINT16 bg = 0x10 + ( ( attr >> 4 ) & 0x07 );
+
+ if ( i == cursor_x && ( cga->m_framecnt & 0x08 ) )
+ {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) with high intensity bg.
+ The character cell size is 16x8
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_inten_alt_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_inten_alt_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x0F;
+
+ if ( i == cursor_x && ( cga->m_framecnt & 0x08 ) )
+ {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x40 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x20 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x10 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x08 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x04 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x02 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+ }
+}
+
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) and blinking colors.
+ The character cell size is 16x8
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_blink_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_blink_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x0F;
+ UINT16 bg = (attr >> 4) & 0x07;
+
+ if ( i == cursor_x )
+ {
+ if ( cga->m_framecnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ if ( ( attr & 0x80 ) && ( cga->m_framecnt & 0x10 ) )
+ {
+ data = 0x00;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+static MC6845_UPDATE_ROW( cga_text_blink_update_row_si )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_blink_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x0F;
+ UINT16 bg = (attr >> 4) & 0x07;
+ UINT8 xi;
+
+ if ( i == cursor_x )
+ {
+ if ( cga->m_framecnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ if ( ( attr & 0x80 ) && ( cga->m_framecnt & 0x10 ) )
+ {
+ data = 0x00;
+ }
+ }
+
+ for(xi=0;xi<8;xi++)
+ {
+ UINT8 pen_data, dot;
+
+ dot = (data & (1 << (7-xi)));
+ pen_data = dot ? fg : bg;
+ if(pen_data || dot)
+ *p = palette[pen_data];
+ p++;
+ }
+ }
+}
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) and blinking colors.
+ The character cell size is 16x8
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_blink_alt_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_blink_alt_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x07;
+ UINT16 bg = 0;
+
+ if ( i == cursor_x )
+ {
+ if ( cga->m_framecnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ if ( ( attr & 0x80 ) && ( cga->m_framecnt & 0x10 ) )
+ {
+ data = 0x00;
+ bg = ( attr >> 4 ) & 0x07;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+
+/* The lo-res (320x200) graphics mode on a colour composite monitor */
+
+static MC6845_UPDATE_ROW( cga_gfx_4bppl_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bppl_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+
+ data = videoram[ offset + 1 ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ }
+}
+
+
+/* The hi-res graphics mode on a colour composite monitor
+ *
+ * The different scaling factors mean that the '160x200' versions of screens
+ * are the same size as the normal colour ones.
+ */
+
+static const UINT8 yc_lut2[4] = { 0, 182, 71, 255 };
+
+static const UINT8 yc_lut[16][8] =
+{
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* black */
+ { 0, 0, 0, 0, 1, 1, 1, 1 }, /* blue */
+ { 0, 1, 1, 1, 1, 0, 0, 0 }, /* green */
+ { 0, 0, 1, 1, 1, 1, 0, 0 }, /* cyan */
+ { 1, 1, 0, 0, 0, 0, 1, 1 }, /* red */
+ { 1, 0, 0, 0, 0, 1, 1, 1 }, /* magenta */
+ { 1, 1, 1, 1, 0, 0, 0, 0 }, /* yellow */
+ { 1, 1, 1, 1, 1, 1, 1, 1 }, /* white */
+ /* Intensity set */
+ { 2, 2, 2, 2, 2, 2, 2, 2 }, /* black */
+ { 2, 2, 2, 2, 3, 3, 3, 3 }, /* blue */
+ { 2, 3, 3, 3, 3, 2, 2, 2 }, /* green */
+ { 2, 2, 3, 3, 3, 3, 2, 2 }, /* cyan */
+ { 3, 3, 2, 2, 2, 2, 3, 3 }, /* red */
+ { 3, 2, 2, 2, 2, 3, 3, 3 }, /* magenta */
+ { 3, 3, 3, 3, 2, 2, 2, 2 }, /* yellow */
+ { 3, 3, 3, 3, 3, 3, 3, 3 }, /* white */
+};
+
+static MC6845_UPDATE_ROW( cga_gfx_4bpph_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bpph_update_row",("\n"));
+
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+
+ data = videoram[ offset + 1 ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ }
+}
+
+
+/***************************************************************************
+ Draw graphics mode with 320x200 pixels (default) with 2 bits/pixel.
+ Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
+ cga fetches 2 byte per mc6845 access.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_gfx_2bpp_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_gfx_2bpp_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ data & 0x03 ]]; p++;
+
+ data = videoram[ offset+1 ];
+
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ data & 0x03 ]]; p++;
+ }
+}
+
+
+
+/***************************************************************************
+ Draw graphics mode with 640x200 pixels (default).
+ The cell size is 1x1 (1 scanline is the real default)
+ Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_gfx_1bpp_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 fg = cga->m_color_select & 0x0F;
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_gfx_1bpp_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[( data & 0x80 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x40 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x20 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x10 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x08 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x04 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x02 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+
+ data = videoram[ offset + 1 ];
+
+ *p = palette[( data & 0x80 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x40 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x20 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x10 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x08 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x04 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x02 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+ }
+}
+
+
+WRITE_LINE_MEMBER( isa8_cga_device::hsync_changed )
+{
+ m_hsync = state ? 1 : 0;
+}
+
+
+WRITE_LINE_MEMBER( isa8_cga_device::vsync_changed )
+{
+ m_vsync = state ? 9 : 0;
+ if ( state )
+ {
+ m_framecnt++;
+ }
+}
+
+
+void isa8_cga_device::set_palette_luts(void)
+{
+ /* Setup 2bpp palette lookup table */
+ if ( m_mode_control & 0x10 )
+ {
+ m_palette_lut_2bpp[0] = 0;
+ }
+ else
+ {
+ m_palette_lut_2bpp[0] = m_color_select & 0x0F;
+ }
+ if ( m_mode_control & 0x04 )
+ {
+ m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 3;
+ m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 4;
+ m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 7;
+ }
+ else
+ {
+ if ( m_color_select & 0x20 )
+ {
+ m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 3;
+ m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 5;
+ m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 7;
+ }
+ else
+ {
+ m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 2;
+ m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 4;
+ m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 6;
+ }
+ }
+ //logerror("2bpp lut set to %d,%d,%d,%d\n", cga.palette_lut_2bpp[0], cga.palette_lut_2bpp[1], cga.palette_lut_2bpp[2], cga.palette_lut_2bpp[3]);
+}
+
+/*
+ * rW CGA mode control register (see #P138)
+ *
+ * x x x 0 1 0 0 0 - 320x200, 40x25 text. Colour on RGB and composite monitors.
+ * x x x 0 1 0 0 1 - 640x200, 80x25 text. Colour on RGB and composite monitors.
+ * x x x 0 1 0 1 0 - 320x200 graphics. Colour on RGB and composite monitors.
+ * x x x 0 1 0 1 1 - unknown/invalid.
+ * x x x 0 1 1 0 0 - 320x200, 40x25 text. Colour on RGB, greyscale on composite monitors.
+ * x x x 0 1 1 0 1 - 640x200, 80x25 text. Colour on RGB, greyscale on composite monitors.
+ * x x x 0 1 1 1 0 - 320x200 graphics. Alternative palette on RGB, greyscale on composite monitors.
+ * x x x 0 1 1 1 1 - unknown/invalid.
+ * x x x 1 1 0 0 0 - unknown/invalid.
+ * x x x 1 1 0 0 1 - unknown/invalid.
+ * x x x 1 1 0 1 0 - 160x200/640x200 graphics. 640x200 ?? on RGB monitor, 160x200 on composite monitor.
+ * x x x 1 1 0 1 1 - unknown/invalid.
+ * x x x 1 1 1 0 0 - unknown/invalid.
+ * x x x 1 1 1 0 1 - unknown/invalid.
+ * x x x 1 1 1 1 0 - 640x200 graphics. Colour on black on RGB monitor, monochrome on composite monitor.
+ * x x x 1 1 1 1 1 - unknown/invalid.
+ */
+void isa8_cga_device::mode_control_w(UINT8 data)
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+ UINT8 monitor = CGA_MONITOR;
+
+ m_mode_control = data;
+
+ //logerror("mode set to %02X\n", cga.mode_control & 0x3F );
+ switch ( m_mode_control & 0x3F )
+ {
+ case 0x08: case 0x09: case 0x0C: case 0x0D:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( monitor == CGA_MONITOR_COMPOSITE )
+ {
+ if ( m_mode_control & 0x04 )
+ {
+ /* Composite greyscale */
+ m_update_row = cga_text_inten_comp_grey_update_row;
+ }
+ else
+ {
+ /* Composite colour */
+ m_update_row = cga_text_inten_update_row;
+ }
+ }
+ else
+ {
+ /* RGB colour */
+ m_update_row = cga_text_inten_update_row;
+ }
+ break;
+ case 0x0A: case 0x0B: case 0x2A: case 0x2B:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( monitor == CGA_MONITOR_COMPOSITE )
+ {
+ m_update_row = cga_gfx_4bppl_update_row;
+ }
+ else
+ {
+ m_update_row = cga_gfx_2bpp_update_row;
+ }
+ break;
+ case 0x0E: case 0x0F: case 0x2E: case 0x2F:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_gfx_2bpp_update_row;
+ break;
+ case 0x18: case 0x19: case 0x1C: case 0x1D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_inten_alt_update_row;
+ break;
+ case 0x1A: case 0x1B: case 0x3A: case 0x3B:
+ mc6845->set_hpixels_per_column( 16 );
+ if ( monitor == CGA_MONITOR_COMPOSITE )
+ {
+ m_update_row = cga_gfx_4bpph_update_row;
+ }
+ else
+ {
+ m_update_row = cga_gfx_1bpp_update_row;
+ }
+ break;
+ case 0x1E: case 0x1F: case 0x3E: case 0x3F:
+ mc6845->set_hpixels_per_column( 16 );
+ m_update_row = cga_gfx_1bpp_update_row;
+ break;
+ case 0x28: case 0x29: case 0x2C: case 0x2D:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( monitor == CGA_MONITOR_COMPOSITE )
+ {
+ if ( m_mode_control & 0x04 )
+ {
+ /* Composite greyscale */
+ m_update_row = m_superimpose ? cga_text_blink_update_row_si : cga_text_blink_update_row;
+ }
+ else
+ {
+ /* Composite colour */
+ m_update_row = m_superimpose ? cga_text_blink_update_row_si : cga_text_blink_update_row;
+ }
+ }
+ else
+ {
+ /* RGB colour */
+ m_update_row = m_superimpose ? cga_text_blink_update_row_si : cga_text_blink_update_row;
+ }
+ break;
+ case 0x38: case 0x39: case 0x3C: case 0x3D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_blink_alt_update_row;
+ break;
+ default:
+ m_update_row = NULL;
+ break;
+ }
+
+ // The lowest bit of the mode register selects, among others, the
+ // input clock to the 6845.
+ mc6845->set_clock( ( m_mode_control & 1 ) ? CGA_HCLK : CGA_LCLK );
+
+ set_palette_luts();
+}
+
+
+
+/*
+ * Select Plantronics modes
+ */
+void isa8_cga_device::plantronics_w(UINT8 data)
+{
+ if ( ( CGA_CHIPSET ) != CGA_CHIPSET_ATI) return;
+
+ data &= 0x70; /* Only bits 6-4 are used */
+ m_plantronics = data;
+}
+
+
+
+/*************************************************************************
+ *
+ * CGA
+ * color graphics adapter
+ *
+ *************************************************************************/
+
+WRITE8_MEMBER( isa8_cga_device::char_ram_write )
+{
+ logerror("write char ram %04x %02x\n",offset,data);
+ m_chr_gen_base[offset + 0x0000] = data;
+ m_chr_gen_base[offset + 0x0800] = data;
+ m_chr_gen_base[offset + 0x1000] = data;
+ m_chr_gen_base[offset + 0x1800] = data;
+}
+
+
+READ8_MEMBER( isa8_cga_device::char_ram_read )
+{
+ return m_chr_gen_base[offset];
+}
+
+
+READ8_MEMBER( isa8_cga_device::io_read )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+ UINT8 data = 0xff;
+
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+ case 1: case 3: case 5: case 7:
+ data = mc6845->register_r( space, offset );
+ break;
+ case 10:
+ data = m_vsync | ( ( data & 0x40 ) >> 4 ) | m_hsync;
+ break;
+ case 0x0f:
+ data = m_p3df;
+ break;
+ }
+ return data;
+}
+
+
+
+WRITE8_MEMBER( isa8_cga_device::io_write )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+
+ switch(offset) {
+ case 0: case 2: case 4: case 6:
+ mc6845->address_w( space, offset, data );
+ break;
+ case 1: case 3: case 5: case 7:
+ mc6845->register_w( space, offset, data );
+ break;
+ case 8:
+ mode_control_w(data);
+ break;
+ case 9:
+ m_color_select = data;
+ set_palette_luts();
+ break;
+ case 0x0d:
+ plantronics_w(data);
+ break;
+ case 0x0f:
+ // Not sure if some all CGA cards have ability to upload char definition
+ // The original CGA card had a char rom
+ // TODO: This should be moved to card implementations that actually had this feature
+ m_p3df = data;
+ if (data & 1) {
+ address_space *space_prg = machine().firstcpu->memory().space(AS_PROGRAM);
+
+ space_prg->install_readwrite_handler(0xb8000, 0xb87ff, read8_delegate( FUNC(isa8_cga_device::char_ram_read), this), write8_delegate(FUNC(isa8_cga_device::char_ram_write), this) );
+ } else {
+ m_isa->install_bank(0xb8000, 0xb8000 + MIN(0x8000,m_vram_size) - 1, 0, m_vram_size & 0x4000, "bank_cga", m_vram);
+ }
+ break;
+
+ }
+}
+
+
+
+/* Old plantronics rendering code, leaving it uncommented until we have re-implemented it */
+
+//
+// From choosevideomode:
+//
+// /* Plantronics high-res */
+// if ((cga.mode_control & 2) && (cga.plantronics & 0x20))
+// proc = cga_pgfx_2bpp;
+// /* Plantronics low-res */
+// if ((cga.mode_control & 2) && (cga.plantronics & 0x10))
+// proc = cga_pgfx_4bpp;
+//
+
+//INLINE void pgfx_plot_unit_4bpp(bitmap_ind16 &bitmap,
+// int x, int y, int offs)
+//{
+// int color, values[2];
+// int i;
+//
+// if (cga.plantronics & 0x40)
+// {
+// values[0] = videoram[offs | 0x4000];
+// values[1] = videoram[offs];
+// }
+// else
+// {
+// values[0] = videoram[offs];
+// values[1] = videoram[offs | 0x4000];
+// }
+// for (i=3; i>=0; i--)
+// {
+// color = ((values[0] & 0x3) << 1) |
+// ((values[1] & 2) >> 1) |
+// ((values[1] & 1) << 3);
+// bitmap.pix16(y, x+i) = Machine->pens[color];
+// values[0]>>=2;
+// values[1]>>=2;
+// }
+//}
+//
+//
+//
+///***************************************************************************
+// Draw graphics mode with 640x200 pixels (default) with 2 bits/pixel.
+// Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
+// Second plane at CGA_base + 0x4000 / 0x6000
+//***************************************************************************/
+//
+//static void cga_pgfx_4bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc)
+//{
+// int i, sx, sy, sh;
+// int offs = mscrtc6845_get_start(crtc)*2;
+// int lines = mscrtc6845_get_char_lines(crtc);
+// int height = mscrtc6845_get_char_height(crtc);
+// int columns = mscrtc6845_get_char_columns(crtc)*2;
+//
+// for (sy=0; sy<lines; sy++,offs=(offs+columns)&0x1fff)
+// {
+// for (sh=0; sh<height; sh++, offs|=0x2000)
+// {
+// // char line 0 used as a12 line in graphic mode
+// if (!(sh & 1))
+// {
+// for (i=offs, sx=0; sx<columns; sx++, i=(i+1)&0x1fff)
+// {
+// pgfx_plot_unit_4bpp(bitmap, sx*4, sy*height+sh, i);
+// }
+// }
+// else
+// {
+// for (i=offs|0x2000, sx=0; sx<columns; sx++, i=((i+1)&0x1fff)|0x2000)
+// {
+// pgfx_plot_unit_4bpp(bitmap, sx*4, sy*height+sh, i);
+// }
+// }
+// }
+// }
+//}
+//
+//
+//
+//INLINE void pgfx_plot_unit_2bpp(bitmap_ind16 &bitmap,
+// int x, int y, const UINT16 *palette, int offs)
+//{
+// int i;
+// UINT8 bmap[2], values[2];
+// UINT16 *dest;
+//
+// if (cga.plantronics & 0x40)
+// {
+// values[0] = videoram[offs];
+// values[1] = videoram[offs | 0x4000];
+// }
+// else
+// {
+// values[0] = videoram[offs | 0x4000];
+// values[1] = videoram[offs];
+// }
+// bmap[0] = bmap[1] = 0;
+// for (i=3; i>=0; i--)
+// {
+// bmap[0] = bmap[0] << 1; if (values[0] & 0x80) bmap[0] |= 1;
+// bmap[0] = bmap[0] << 1; if (values[1] & 0x80) bmap[0] |= 1;
+// bmap[1] = bmap[1] << 1; if (values[0] & 0x08) bmap[1] |= 1;
+// bmap[1] = bmap[1] << 1; if (values[1] & 0x08) bmap[1] |= 1;
+// values[0] = values[0] << 1;
+// values[1] = values[1] << 1;
+// }
+//
+// dest = &bitmap.pix16(y, x);
+// *(dest++) = palette[(bmap[0] >> 6) & 0x03];
+// *(dest++) = palette[(bmap[0] >> 4) & 0x03];
+// *(dest++) = palette[(bmap[0] >> 2) & 0x03];
+// *(dest++) = palette[(bmap[0] >> 0) & 0x03];
+// *(dest++) = palette[(bmap[1] >> 6) & 0x03];
+// *(dest++) = palette[(bmap[1] >> 4) & 0x03];
+// *(dest++) = palette[(bmap[1] >> 2) & 0x03];
+// *(dest++) = palette[(bmap[1] >> 0) & 0x03];
+//}
+//
+//
+//
+///***************************************************************************
+// Draw graphics mode with 320x200 pixels (default) with 2 bits/pixel.
+// Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
+// cga fetches 2 byte per mscrtc6845 access (not modeled here)!
+//***************************************************************************/
+//
+//static void cga_pgfx_2bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc)
+//{
+// int i, sx, sy, sh;
+// int offs = mscrtc6845_get_start(crtc)*2;
+// int lines = mscrtc6845_get_char_lines(crtc);
+// int height = mscrtc6845_get_char_height(crtc);
+// int columns = mscrtc6845_get_char_columns(crtc)*2;
+// int colorset = cga.color_select & 0x3F;
+// const UINT16 *palette;
+//
+// /* Most chipsets use bit 2 of the mode control register to
+// * access a third palette. But not consistently. */
+// pc_cga_check_palette();
+// switch(CGA_CHIPSET)
+// {
+// /* The IBM Professional Graphics Controller behaves like
+// * the PC1512, btw. */
+// case CGA_CHIPSET_PC1512:
+// if ((colorset < 32) && (cga.mode_control & 4)) colorset += 64;
+// break;
+//
+// case CGA_CHIPSET_IBM:
+// case CGA_CHIPSET_PC200:
+// case CGA_CHIPSET_ATI:
+// case CGA_CHIPSET_PARADISE:
+// if (cga.mode_control & 4) colorset = (colorset & 0x1F) + 64;
+// break;
+// }
+//
+//
+// /* The fact that our palette is located in cga_colortable is a vestigial
+// * aspect from when we were doing that ugly trick where drawgfx() would
+// * handle graphics drawing. Truthfully, we should probably be using
+// * palette_set_color_rgb() here and not doing the palette lookup in the loop
+// */
+// palette = &cga_colortable[256*2 + 16*2] + colorset * 4;
+//
+// for (sy=0; sy<lines; sy++,offs=(offs+columns)&0x1fff) {
+//
+// for (sh=0; sh<height; sh++)
+// {
+// if (!(sh&1)) { // char line 0 used as a12 line in graphic mode
+// for (i=offs, sx=0; sx<columns; sx++, i=(i+1)&0x1fff)
+// {
+// pgfx_plot_unit_2bpp(bitmap, sx*8, sy*height+sh, palette, i);
+// }
+// }
+// else
+// {
+// for (i=offs|0x2000, sx=0; sx<columns; sx++, i=((i+1)&0x1fff)|0x2000)
+// {
+// pgfx_plot_unit_2bpp(bitmap, sx*8, sy*height+sh, palette, i);
+// }
+// }
+// }
+// }
+//}
+
+
+static MC6845_UPDATE_ROW( pc1512_gfx_4bpp_update_row )
+{
+ isa8_cga_pc1512_device *cga = downcast<isa8_cga_pc1512_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT16 offset_base = ra << 13;
+ int j;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"pc1512_gfx_4bpp_update_row",("\n"));
+ for ( j = 0; j < x_count; j++ )
+ {
+ UINT16 offset = offset_base | ( ( ma + j ) & 0x1FFF );
+ UINT16 i = ( cga->m_color_select & 8 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[3] | offset ] << 3 : 0;
+ UINT16 r = ( cga->m_color_select & 4 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[2] | offset ] << 2 : 0;
+ UINT16 g = ( cga->m_color_select & 2 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[1] | offset ] << 1 : 0;
+ UINT16 b = ( cga->m_color_select & 1 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[0] | offset ] : 0;
+
+ *p = palette[( ( i & 0x400 ) | ( r & 0x200 ) | ( g & 0x100 ) | ( b & 0x80 ) ) >> 7]; p++;
+ *p = palette[( ( i & 0x200 ) | ( r & 0x100 ) | ( g & 0x080 ) | ( b & 0x40 ) ) >> 6]; p++;
+ *p = palette[( ( i & 0x100 ) | ( r & 0x080 ) | ( g & 0x040 ) | ( b & 0x20 ) ) >> 5]; p++;
+ *p = palette[( ( i & 0x080 ) | ( r & 0x040 ) | ( g & 0x020 ) | ( b & 0x10 ) ) >> 4]; p++;
+ *p = palette[( ( i & 0x040 ) | ( r & 0x020 ) | ( g & 0x010 ) | ( b & 0x08 ) ) >> 3]; p++;
+ *p = palette[( ( i & 0x020 ) | ( r & 0x010 ) | ( g & 0x008 ) | ( b & 0x04 ) ) >> 2]; p++;
+ *p = palette[( ( i & 0x010 ) | ( r & 0x008 ) | ( g & 0x004 ) | ( b & 0x02 ) ) >> 1]; p++;
+ *p = palette[ ( i & 0x008 ) | ( r & 0x004 ) | ( g & 0x002 ) | ( b & 0x01 ) ]; p++;
+ }
+}
+
+
+WRITE8_MEMBER( isa8_cga_pc1512_device::io_write )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+
+ switch (offset)
+ {
+ case 0: case 2: case 4: case 6:
+ data &= 0x1F;
+ mc6845->address_w( space, offset, data );
+ m_mc6845_address = data;
+ break;
+
+ case 1: case 3: case 5: case 7:
+ if ( ! m_mc6845_locked_register[m_mc6845_address] )
+ {
+ mc6845->register_w( space, offset, data );
+ if ( isa8_cga_pc1512_device::mc6845_writeonce_register[m_mc6845_address] )
+ {
+ m_mc6845_locked_register[m_mc6845_address] = 1;
+ }
+ }
+ break;
+
+ case 0x8:
+ /* Check if we're changing to graphics mode 2 */
+ if ( ( m_mode_control & 0x12 ) != 0x12 && ( data & 0x12 ) == 0x12 )
+ {
+ m_write = 0x0F;
+ }
+ else
+ {
+ membank("bank1")->set_base(m_vram + isa8_cga_pc1512_device::vram_offset[0]);
+ }
+ m_mode_control = data;
+ switch( m_mode_control & 0x3F )
+ {
+ case 0x08: case 0x09: case 0x0C: case 0x0D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_inten_update_row;
+ break;
+ case 0x0A: case 0x0B: case 0x2A: case 0x2B:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( ( CGA_MONITOR ) == CGA_MONITOR_COMPOSITE )
+ {
+ m_update_row = cga_gfx_4bppl_update_row;
+ }
+ else
+ {
+ m_update_row = cga_gfx_2bpp_update_row;
+ }
+ break;
+ case 0x0E: case 0x0F: case 0x2E: case 0x2F:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_gfx_2bpp_update_row;
+ break;
+ case 0x18: case 0x19: case 0x1C: case 0x1D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_inten_alt_update_row;
+ break;
+ case 0x1A: case 0x1B: case 0x3A: case 0x3B:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = pc1512_gfx_4bpp_update_row;
+ break;
+ case 0x1E: case 0x1F: case 0x3E: case 0x3F:
+ mc6845->set_hpixels_per_column( 16 );
+ m_update_row = cga_gfx_1bpp_update_row;
+ break;
+ case 0x28: case 0x29: case 0x2C: case 0x2D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_blink_update_row;
+ break;
+ case 0x38: case 0x39: case 0x3C: case 0x3D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_blink_alt_update_row;
+ break;
+ default:
+ m_update_row = NULL;
+ break;
+ }
+ break;
+
+ case 0xd:
+ m_write = data;
+ break;
+
+ case 0xe:
+ m_read = data;
+ if ( ( m_mode_control & 0x12 ) == 0x12 )
+ {
+ membank("bank1")->set_base(m_vram + isa8_cga_pc1512_device::vram_offset[data & 3]);
+ }
+ break;
+
+ default:
+ isa8_cga_device::io_write(space, offset,data);
+ break;
+ }
+}
+
+
+READ8_MEMBER( isa8_cga_pc1512_device::io_read )
+{
+ UINT8 data;
+
+ switch (offset)
+ {
+ case 0xd:
+ data = m_write;
+ break;
+
+ case 0xe:
+ data = m_read;
+ break;
+
+ default:
+ data = isa8_cga_device::io_read(space, offset);
+ break;
+ }
+ return data;
+}
+
+
+WRITE8_MEMBER( isa8_cga_pc1512_device::vram_w )
+{
+ if ( ( m_mode_control & 0x12 ) == 0x12 )
+ {
+ if (m_write & 1)
+ m_vram[offset+isa8_cga_pc1512_device::vram_offset[0]] = data; /* blue plane */
+ if (m_write & 2)
+ m_vram[offset+isa8_cga_pc1512_device::vram_offset[1]] = data; /* green */
+ if (m_write & 4)
+ m_vram[offset+isa8_cga_pc1512_device::vram_offset[2]] = data; /* red */
+ if (m_write & 8)
+ m_vram[offset+isa8_cga_pc1512_device::vram_offset[3]] = data; /* intensity (text, 4color) */
+ }
+ else
+ {
+ m_vram[offset + isa8_cga_pc1512_device::vram_offset[0]] = data;
+ }
+}
+
+
+const device_type ISA8_CGA_PC1512 = &device_creator<isa8_cga_pc1512_device>;
+
+const offs_t isa8_cga_pc1512_device::vram_offset[4]= { 0x0000, 0x4000, 0x8000, 0xC000 };
+const UINT8 isa8_cga_pc1512_device::mc6845_writeonce_register[31] =
+{
+ 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+//-------------------------------------------------
+// isa8_cga_pc1512_device - constructor
+//-------------------------------------------------
+
+isa8_cga_pc1512_device::isa8_cga_pc1512_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_CGA_PC1512, "ISA8_CGA_PC1512", tag, owner, clock )
+{
+ m_vram_size = 0x10000;
+ m_chr_gen_offset[0] = 0x0000;
+ m_chr_gen_offset[1] = 0x0800;
+ m_chr_gen_offset[2] = 0x1000;
+ m_chr_gen_offset[3] = 0x1800;
+}
+
+
+const rom_entry *isa8_cga_pc1512_device::device_rom_region() const
+{
+ return NULL;
+}
+
+
+ioport_constructor isa8_cga_pc1512_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( pc1512 );
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_cga_pc1512_device::device_start()
+{
+ isa8_cga_device::device_start();
+
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_cga_pc1512_device::io_read), this ), write8_delegate( FUNC(isa8_cga_pc1512_device::io_write), this ) );
+ m_isa->install_bank(0xb8000, 0xbbfff, 0, 0, "bank1", m_vram);
+
+ address_space *space = machine().firstcpu->memory().space( AS_PROGRAM );
+
+ space->install_write_handler( 0xb8000, 0xbbfff, 0, 0x0C000, write8_delegate( FUNC(isa8_cga_pc1512_device::vram_w), this ) );
+}
+
+void isa8_cga_pc1512_device::device_reset()
+{
+ isa8_cga_device::device_reset();
+
+ m_write = 0x0f;
+ m_read = 0;
+ m_mc6845_address = 0;
+ for ( int i = 0; i < 31; i++ )
+ {
+ m_mc6845_locked_register[i] = 0;
+ }
+
+ membank("bank1")->set_base(m_vram + isa8_cga_pc1512_device::vram_offset[0]);
+}
+
diff --git a/src/mess/video/isa_cga.h b/src/mess/video/isa_cga.h
new file mode 100644
index 00000000000..f40bb5ddb7a
--- /dev/null
+++ b/src/mess/video/isa_cga.h
@@ -0,0 +1,187 @@
+#pragma once
+
+#ifndef __ISA_CGA_H__
+#define __ISA_CGA_H__
+
+#include "emu.h"
+#include "machine/isa.h"
+#include "video/mc6845.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_cga_device
+
+class isa8_cga_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+ friend class isa8_cga_superimpose_device;
+ friend class isa8_cga_mc1502_device;
+ friend class isa8_cga_poisk1_device;
+ friend class isa8_cga_poisk2_device;
+ friend class isa8_cga_pc1512_device;
+
+public:
+ // construction/destruction
+ isa8_cga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ isa8_cga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "cga"; }
+public:
+ void mode_control_w(UINT8 data);
+ void set_palette_luts();
+ void plantronics_w(UINT8 data);
+ virtual DECLARE_READ8_MEMBER( io_read );
+ virtual DECLARE_WRITE8_MEMBER( io_write );
+ DECLARE_READ8_MEMBER( char_ram_read );
+ DECLARE_WRITE8_MEMBER( char_ram_write );
+ DECLARE_WRITE_LINE_MEMBER( hsync_changed );
+ DECLARE_WRITE_LINE_MEMBER( vsync_changed );
+ UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+public:
+ int m_framecnt;
+
+ UINT8 m_mode_control; /* wo 0x3d8 */
+ UINT8 m_color_select; /* wo 0x3d9 */
+ UINT8 m_status; /* ro 0x3da */
+
+ mc6845_update_row_func m_update_row;
+ UINT8 m_palette_lut_2bpp[4];
+ offs_t m_chr_gen_offset[4];
+ UINT8 m_font_selection_mask;
+ UINT8 *m_chr_gen_base;
+ UINT8 *m_chr_gen;
+ UINT8 m_vsync;
+ UINT8 m_hsync;
+ size_t m_vram_size;
+ UINT8 *m_vram;
+ bool m_superimpose;
+ UINT8 m_p3df; /* This should be moved into the appropriate subclass */
+ UINT8 m_plantronics; /* This should be moved into the appropriate subclass */
+};
+
+// device type definition
+extern const device_type ISA8_CGA;
+
+
+// ======================> isa8_cga_superimpose_device
+
+class isa8_cga_superimpose_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_cga_superimpose_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual void device_config_complete() { m_shortname = "cga_superimpose"; }
+};
+
+// device type definition
+extern const device_type ISA8_CGA_SUPERIMPOSE;
+
+
+// ======================> isa8_cga_mc1502_device
+
+class isa8_cga_mc1502_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_cga_mc1502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual void device_config_complete() { m_shortname = "cga_mc1502"; }
+};
+
+// device type definition
+extern const device_type ISA8_CGA_MC1502;
+
+
+// ======================> isa8_poisk1_device
+
+class isa8_cga_poisk1_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_cga_poisk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual void device_config_complete() { m_shortname = "cga_poisk1"; }
+};
+
+// device type definition
+extern const device_type ISA8_CGA_POISK1;
+
+
+// ======================> isa8_poisk2_device
+
+class isa8_cga_poisk2_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_cga_poisk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual void device_config_complete() { m_shortname = "cga_poisk2"; }
+};
+
+// device type definition
+extern const device_type ISA8_CGA_POISK2;
+
+
+// ======================> isa8_pc1512_device
+
+class isa8_cga_pc1512_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_cga_pc1512_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+ virtual const rom_entry *device_rom_region() const;
+ virtual void device_config_complete() { m_shortname = "cga_pc1512"; }
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+public:
+ UINT8 m_write;
+ UINT8 m_read;
+ UINT8 m_mc6845_address;
+ UINT8 m_mc6845_locked_register[31];
+
+public:
+ // Static information
+ // mapping of the 4 planes into videoram
+ // (text data should be readable at videoram+0)
+ static const offs_t vram_offset[4];
+ static const UINT8 mc6845_writeonce_register[31];
+
+ virtual DECLARE_READ8_MEMBER( io_read );
+ virtual DECLARE_WRITE8_MEMBER( io_write );
+
+ DECLARE_WRITE8_MEMBER( vram_w );
+};
+
+// device type definition
+extern const device_type ISA8_CGA_PC1512;
+
+
+#endif /* __ISA_CGA_H__ */
+
diff --git a/src/mess/video/isa_ega.c b/src/mess/video/isa_ega.c
new file mode 100644
index 00000000000..6acba3d1f03
--- /dev/null
+++ b/src/mess/video/isa_ega.c
@@ -0,0 +1,1408 @@
+/***************************************************************************
+
+ Enhanced Graphics Adapter (EGA) section
+
+TODO - Write documentation
+
+"Regular" register on an EGA graphics card:
+
+ 3C2 - 7 6 5 4 3 2 1 0 - Misc Output Register - Write Only
+ | | | | | | | |
+ | | | | | | | +-- 3Bx/3Dx I/O port select
+ | | | | | | | 0 = 3Bx for CRTC I/O, 3BA for status reg 1
+ | | | | | | | 1 = 3Dx for CRTC I/O, 3DA for status reg 1
+ | | | | | | +---- enable ram
+ | | | | | | 0 = disable ram from the processor
+ | | | | | | 1 = enable ram to respond to addresses
+ | | | | | | designated by the Control Data Select
+ | | | | | | value in the Graphics Controllers.
+ | | | | | +------ clock select bit 0
+ | | | | +-------- clock select bit 1
+ | | | | 00 = 14MHz from Processor I/O channel
+ | | | | 01 = 16MHz on-bord clock
+ | | | | 10 = External clock from feature connector
+ | | | | 11 = reserved/unused
+ | | | +---------- disable video drivers
+ | | | 0 = activate internal video drivers
+ | | | 1 = disable internal video drivers
+ | | +------------ page bit for odd/even. Selects between 2 pages
+ | | of 64KB of memory when in odd/even mode.
+ | | 0 = select low page
+ | | 1 = select high page
+ | +-------------- horizontal retrace polarity
+ | 0 = select positive
+ | 1 = select negative
+ +---------------- vertical retrace polarity
+ 0 = select positive
+ 1 = select negative
+
+
+ 3C2 - 7 6 5 4 3 2 1 0 - Input Status Reg 0 - Read Only
+ | | | | | | | |
+ | | | | | | | +-- reserved/unused
+ | | | | | | +---- reserved/unused
+ | | | | | +------ reserved/unused
+ | | | | +-------- reserved/unused
+ | | | +---------- switch sense
+ | | | 0 = switch is closed
+ | | | 1 = allows processor to read the 4 config switches
+ | | | on the EGA adapter. The setting of CLKSEL determines
+ | | | switch to read.
+ | | +------------ input from FEAT0 on the feature connector
+ | +-------------- input from FEAT1 on the feature connector
+ +---------------- CRT Interrupt
+ 0 = vertical retrace if occuring
+ 1 = video is being displayed
+
+
+ Configuration switches
+ SW1 SW2 SW3 SW4
+ OFF OFF OFF ON - EGA, Color 80x25 (5153)
+ - EGA (primary) + MDA, Color 80x25 + Monochrome
+ OFF OFF ON OFF - EGA, Monochrome (5151)
+ - EGA (primary) + CGA, Monochrome + Color 80x25
+ OFF OFF ON ON - EGA + MDA (primary), 5154 + Enhanced Monochrome
+ OFF ON OFF ON - EGA + CGA (primary), Monochrome + Color 80x25
+ OFF ON ON OFF - EGA, Enhanced Color - Enhanced Mode (5154)
+ - EGA (primary) + MDA, 5154 monitor + Enhanced Monochrome
+ OFF ON ON ON - EGA + MDA (primary), Color 80x25 + Monochrome
+ ON OFF OFF ON - EGA, Color 40x25 (5153)
+ - EGA (primary) + MDA, Color 40x25 + Monochrome
+ ON OFF ON OFF - EGA (primary) + CGA, Monochrome + Color 40x25
+ ON OFF ON ON - EGA + MDA (primary), 5154 + Normal Monochrome
+ ON ON OFF ON - EGA + CGA (primary), Monochrome + Color 40x25
+ ON ON ON OFF - EGA, Enhanced Color - Enhanced Mode (5154)
+ - EGA (primary) + MDA, 5154 monitor + Normal Monochrome
+ ON ON ON ON - EGA + MDA (primary), Color 40x25 + Monochrome
+
+
+ 3XA - 7 6 5 4 3 2 1 0 - Feature Control Register - Write Only
+ | | | | | | | |
+ | | | | | | | +-- output to FEAT0 of the feature connector
+ | | | | | | +---- output to FEAT1 of the feature connector
+ | | | | | +------ reserved/unused
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+ 3XA - 7 6 5 4 3 2 1 0 - Input Status Reg 1 - Read Only
+ | | | | | | | |
+ | | | | | | | +-- display enable
+ | | | | | | | 0 = indicates the CRT raster is in a horizontal or vertical retrace
+ | | | | | | | 1 = otherwise
+ | | | | | | +---- light pen strobe
+ | | | | | | 0 = light pen trigger has not been set
+ | | | | | | 1 = light pen trigger has been set
+ | | | | | +------ light pen switch
+ | | | | | 0 = switch is closed
+ | | | | | 1 = switch is open
+ | | | | +-------- vertical blank
+ | | | | 0 = video information is being displayed
+ | | | | 1 = CRT is in vertical blank
+ | | | +---------- diagnostic usage, output depends on AR12 video status mux bits
+ | | | mux bits - output
+ | | | 00 - blue
+ | | | 01 - I blue
+ | | | 10 - I red
+ | | | 11 - unknown
+ | | +------------ diagnostic usage, output depends on AR12 video status mux bits
+ | | mux bits - output
+ | | 00 - red
+ | | 01 - green
+ | | 10 - I green
+ | | 11 - unknown
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+
+The EGA graphics card introduces a lot of new indexed registers to handle the
+enhanced graphics. These new indexed registers can be divided into three
+groups:
+- attribute registers
+- sequencer registers
+- graphics controllers registers
+
+
+Attribute Registers AR00 - AR13
+
+The Attribute Registers are all accessed through I/O port 0x3C0. The first
+write to I/O port 0x3C0 sets the index register. The next write to I/O port
+0x3C0 actually sets the data to the indexed register.
+
+ 3C0 - 7 6 5 4 3 2 1 0 - Attribute Access Register
+ | | | | | | | |
+ | | | | | | | +-- index bit 0
+ | | | | | | +---- index bit 1
+ | | | | | +------ index bit 2
+ | | | | +-------- index bit 3
+ | | | +---------- index bit 4
+ | | +------------ palette source
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ AR00-AR0F - 7 6 5 4 3 2 1 0 - Palette Register #00 - #0F
+ | | | | | | | |
+ | | | | | | | +-- MSB B
+ | | | | | | +---- MSB G
+ | | | | | +------ MSB R
+ | | | | +-------- LSB B
+ | | | +---------- LSB G
+ | | +------------ LSB R
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ AR10 - 7 6 5 4 3 2 1 0 - Mode Control Register
+ | | | | | | | |
+ | | | | | | | +-- Text/Graphics select
+ | | | | | | +---- Monochrome/Color select
+ | | | | | +------ 9th dot setting
+ | | | | +-------- Blink Enable
+ | | | +---------- reserved/unsued
+ | | +------------ 0 = line compare does not affect pixel output
+ | | 1 = line compare does affect pixel output
+ | +-------------- 0 = pixel changes every dot clock
+ | 1 = pixel changes every other dot clock
+ +---------------- reserved/unused
+
+
+ AR11 - 7 6 5 4 3 2 1 0 - Overscan Color Register
+ | | | | | | | |
+ | | | | | | | +-- MSB B
+ | | | | | | +---- MSB G
+ | | | | | +------ MSB R
+ | | | | +-------- LSB B
+ | | | +---------- LSB G
+ | | +------------ LSB R
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ AR12 - 7 6 5 4 3 2 1 0 - Color Plane Enable Register
+ | | | | | | | |
+ | | | | | | | +-- Enable plane 0
+ | | | | | | +---- Enable plane 1
+ | | | | | +------ Enable plane 2
+ | | | | +-------- Enable plane 3
+ | | | +---------- Video Status Mux bit 0
+ | | +------------ Video Status Mux bit 1
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ AR13 - 7 6 5 4 3 2 1 0 - Horizontal Panning Register
+ | | | | | | | |
+ | | | | | | | +-- Pixel left shift bit 0
+ | | | | | | +---- Pixel left shift bit 1
+ | | | | | +------ Pixel left shift bit 2
+ | | | | +-------- Pixel left shift bit 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+Sequencer Registers SR00 - SR04
+
+The Sequencer Registers are accessed through an index register located at I/O
+port 0x3C4, and a data register located at I/O port 0x3C5.
+
+ 3C4 - 7 6 5 4 3 2 1 0 - Sequencer Index Register - Write Only
+ | | | | | | | |
+ | | | | | | | +-- index bit 0
+ | | | | | | +---- index bit 1
+ | | | | | +------ index bit 2
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ 3C5 - 7 6 5 4 3 2 1 0 - Sequencer Data Register - Write Only
+ | | | | | | | |
+ | | | | | | | +-- data bit 0
+ | | | | | | +---- data bit 1
+ | | | | | +------ data bit 2
+ | | | | +-------- data bit 3
+ | | | +---------- data bit 4
+ | | +------------ data bit 5
+ | +-------------- data bit 6
+ +---------------- data bit 7
+
+
+ SR00 - 7 6 5 4 3 2 1 0 - Reset Control Register
+ | | | | | | | |
+ | | | | | | | +-- Must be 1 for normal operation
+ | | | | | | +---- Must be 1 for normal operation
+ | | | | | +------ reserved/unused
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ SR01 - 7 6 5 4 3 2 1 0 - Clocking Mode
+ | | | | | | | |
+ | | | | | | | +-- 0 = 9 dots per char, 1 = 8 dots per char
+ | | | | | | +---- clock frequency, 0 = 4 out of 5 memory cycles, 1 = 2 out of 5 memory cycles
+ | | | | | +------ shift load
+ | | | | +-------- 0 = normal dot clock, 1 = master dot clock / 2
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ SR02 - 7 6 5 4 3 2 1 0 - Map Mask
+ | | | | | | | |
+ | | | | | | | +-- 1 = enable map 0 for writing
+ | | | | | | +---- 1 = enable map 1 for writing
+ | | | | | +------ 1 = enable map 2 for writing
+ | | | | +-------- 1 = enable map 3 for writing
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ SR03 - 7 6 5 4 3 2 1 0 - Character Map Select
+ | | | | | | | |
+ | | | | | | | +-- character map select B bit 0
+ | | | | | | +---- character map select B bit 1
+ | | | | | | Selects the map used to generate alpha characters when
+ | | | | | | attribute bit 3 is set to 0
+ | | | | | | 00 = map 0 - 1st 8KB of plane 2 bank 0
+ | | | | | | 01 = map 1 - 2nd 8KB of plane 2 bank 1
+ | | | | | | 10 = map 2 - 3rd 8KB of plane 2 bank 2
+ | | | | | | 11 = map 3 - 4th 8KB of plane 2 bank 3
+ | | | | | +------ character map select A bit 0
+ | | | | +-------- character map select A bit 1
+ | | | | Selects the map used to generate alpha characters when
+ | | | | attribute bit 3 is set to 1
+ | | | | 00 = map 0 - 1st 8KB of plane 2 bank 0
+ | | | | 01 = map 1 - 2nd 8KB of plane 2 bank 1
+ | | | | 10 = map 2 - 3rd 8KB of plane 2 bank 2
+ | | | | 11 = map 3 - 4th 8KB of plane 2 bank 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ SR04 - 7 6 5 4 3 2 1 0 - Memory Mode Register
+ | | | | | | | |
+ | | | | | | | +-- 0 = graphics mode, 1 = text mode
+ | | | | | | +---- 0 = no memory extension, 1 = memory extension
+ | | | | | +------ 0 = odd/even storage, 1 = sequential storage
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+Graphics Controller Registers GR00 - GR08
+
+The Graphics Controller Registers are accessed through an index register
+located at I/O port 0x3CE, and a data register located at I/O port 0x3CF.
+
+ GR00 - 7 6 5 4 3 2 1 0 - Set/Reset Register
+ | | | | | | | |
+ | | | | | | | +-- set/reset for plane 0
+ | | | | | | +---- set/reset for plane 1
+ | | | | | +------ set/reset for plane 2
+ | | | | +-------- set/reset for plane 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR01 - 7 6 5 4 3 2 1 0 - Enable Set/Reset Register
+ | | | | | | | |
+ | | | | | | | +-- enable set/reset for plane 0
+ | | | | | | +---- enable set/reset for plane 1
+ | | | | | +------ enable set/reset for plane 2
+ | | | | +-------- enable set/reset for plane 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR02 - 7 6 5 4 3 2 1 0 - Color Compare Register
+ | | | | | | | |
+ | | | | | | | +-- color compare 0
+ | | | | | | +---- color compare 1
+ | | | | | +------ color compare 2
+ | | | | +-------- color compare 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR03 - 7 6 5 4 3 2 1 0 - Data Rotate Register
+ | | | | | | | |
+ | | | | | | | +-- number of positions to rotate bit 0
+ | | | | | | +---- number of positions to rotate bit 1
+ | | | | | +------ number of positions to rotate bit 2
+ | | | | +-------- function select bit 0
+ | | | +---------- function select bit 1
+ | | | 00 = data overwrites in specified color
+ | | | 01 = data ANDed with latched data
+ | | | 10 = data ORed with latched data
+ | | | 11 = data XORed with latched data
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR04 - 7 6 5 4 3 2 1 0 - Read Map Select Register
+ | | | | | | | |
+ | | | | | | | +-- plane select bit 0
+ | | | | | | +---- plane select bit 1
+ | | | | | +------ reserved/unused
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR05 - 7 6 5 4 3 2 1 0 - Mode Register
+ | | | | | | | |
+ | | | | | | | +-- write mode bit 0
+ | | | | | | +---- write mode bit 1
+ | | | | | | 00 = write 8 bits of value in set/reset register if enabled,
+ | | | | | | otherwise write rotated processor data
+ | | | | | | 01 = write with contents of processor latches
+ | | | | | | 10 = memory plane 0-3 filled with 8 bits of value of data bit 0-3
+ | | | | | | 11 = reserved/unused
+ | | | | | +------ test condition
+ | | | | | 0 = normal operation
+ | | | | | 1 = put outputs in high impedance state
+ | | | | +-------- read mode
+ | | | | 0 = read from plane selected by GR04
+ | | | | 1 = do color compare
+ | | | +---------- odd/even addressing mode
+ | | +------------ shift register mode
+ | | 0 = sequential
+ | | 1 = even bits from even maps, odd bits from odd maps
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR06 - 7 6 5 4 3 2 1 0 - Miscellaneous Register
+ | | | | | | | |
+ | | | | | | | +-- 0 = text mode, 1 = graphics mode
+ | | | | | | +---- chain odd maps to even
+ | | | | | +------ memory map bit 0
+ | | | | +-------- memory map bit 1
+ | | | | 00 = 0xA0000, 128KB
+ | | | | 01 = 0xA0000, 64KB
+ | | | | 10 = 0xB0000, 32KB
+ | | | | 11 = 0xB8000, 32KB
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR07 - 7 6 5 4 3 2 1 0 - Color Plane Ignore Register
+ | | | | | | | |
+ | | | | | | | +-- ignore color plane 0
+ | | | | | | +---- ignore color plane 1
+ | | | | | +------ ignore color plane 2
+ | | | | +-------- ignore color plane 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR08 - 7 6 5 4 3 2 1 0 - Bit Mask Register
+ | | | | | | | |
+ | | | | | | | +-- write enable bit 0
+ | | | | | | +---- write enable bit 1
+ | | | | | +------ write enable bit 2
+ | | | | +-------- write enable bit 3
+ | | | +---------- write enable bit 4
+ | | +------------ write enable bit 5
+ | +-------------- write enable bit 6
+ +---------------- write enable bit 7
+
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/isa_ega.h"
+
+#define VERBOSE_EGA 1
+
+#define EGA_SCREEN_NAME "ega_screen"
+#define EGA_CRTC_NAME "crtc_ega_ega"
+
+/*
+ Prototypes
+*/
+static SCREEN_UPDATE_IND16( pc_ega );
+static CRTC_EGA_UPDATE_ROW( ega_update_row );
+
+static CRTC_EGA_INTERFACE( crtc_ega_ega_intf )
+{
+ EGA_SCREEN_NAME, /* screen number */
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ ega_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ega_device, de_changed), /* on_de_chaged */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ega_device, hsync_changed), /* on_hsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ega_device, vsync_changed), /* on vsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ega_device, vblank_changed) /* on_vblank_changed */
+};
+
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_ega )
+ MCFG_SCREEN_ADD(EGA_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(16257000,912,0,640,262,0,200)
+ MCFG_SCREEN_UPDATE_STATIC( pc_ega )
+
+ MCFG_PALETTE_LENGTH( 64 )
+ MCFG_CRTC_EGA_ADD(EGA_CRTC_NAME, 16257000/8, crtc_ega_ega_intf)
+MACHINE_CONFIG_END
+
+ROM_START( ega )
+ ROM_REGION(0x4000, "user1", 0)
+ ROM_LOAD("6277356.u44", 0x0000, 0x4000, CRC(dc146448) SHA1(dc0794499b3e499c5777b3aa39554bbf0f2cc19b))
+ ROM_REGION(0x4000, "user2", ROMREGION_ERASE00)
+ROM_END
+
+/*
+0000 - MONOC PRIMARY, EGA COLOR, 40x25
+0001 - MONOC PRIMARY, EGA COLOR, 80x25
+0010 - MONOC PRIMARY, EGA HI RES EMULATE (SAME AS 0001)
+0011 - MONOC PRIMARY, EGA HI RES ENHANCED
+0100 - COLOR 40 PRIMARY, EGA MONOCHROME
+0101 - COLOR 80 PRIMARY, EGA MONOCHROME
+
+0110 - MONOC SECONDARY, EGA COLOR, 40x24
+0111 - MONOC SECONDARY, EGA COLOR, 80x25
+1000 - MONOC SECONDARY, EGA HI RES EMULATE (SAME AS 0111)
+1001 - MONOC SECONDARY, EGA HI RES ENHANCED
+1010 - COLOR 40 SECONDARY, EGA
+1011 - COLOR 80 SECONDARY, EGA
+
+1100 - RESERVED
+1101 - RESERVED
+1110 - RESERVED
+1111 - RESERVED
+*/
+
+INPUT_PORTS_START( ega )
+ PORT_START( "config" )
+ PORT_CONFNAME( 0x0f, 0x09, "dipswitches" )
+ PORT_CONFSETTING( 0x00, "0000 - MDA PRIMARY, EGA COLOR, 40x25" ) /* DIAG: ?? 40 cols, RGBI */
+ PORT_CONFSETTING( 0x08, "0001 - MDA PRIMARY, EGA COLOR, 80x25" ) /* DIAG: ?? 80 cols, RGBI */
+ PORT_CONFSETTING( 0x04, "0010 - MDA PRIMARY, EGA HI RES EMULATE (SAME AS 0001)" ) /* DIAG: ?? 80 cols, RGBI */
+ PORT_CONFSETTING( 0x0c, "0011 - MDA PRIMARY, EGA HI RES ENHANCED" ) /* DIAG: Color Display 40 cols, RrGgBb */
+ PORT_CONFSETTING( 0x02, "0100 - CGA 40 PRIMARY, EGA MONOCHROME" ) /* DIAG: ??, Mono RGBI */
+ PORT_CONFSETTING( 0x0a, "0101 - CGA 80 PRIMARY, EGA MONOCHROME" ) /* DIAG: ??, Mono RGBI */
+ PORT_CONFSETTING( 0x06, "0110 - MDA SECONDARY, EGA COLOR, 40x25" ) /* DIAG: Color Display 40 cols, RGBI */
+ PORT_CONFSETTING( 0x0e, "0111 - MDA SECONDARY, EGA COLOR, 80x25" ) /* DIAG: Color Display 80 cols, RGBI */
+ PORT_CONFSETTING( 0x01, "1000 - MDA SECONDARY, EGA HI RES EMULATE (SAME AS 0111)" ) /* DIAG: Color Display 80 cols, RGBI */
+ PORT_CONFSETTING( 0x09, "1001 - MDA SECONDARY, EGA HI RES ENHANCED" ) /* DIAG: Color Display 40 cols, RrGgBb */
+ PORT_CONFSETTING( 0x05, "1010 - COLOR 40 SECONDARY, EGA" ) /* DIAG: Monochrome display, Mono RGBI */
+ PORT_CONFSETTING( 0x0d, "1011 - COLOR 80 SECONDARY, EGA" ) /* DIAG: Monochrome display, Mono RGBI */
+ PORT_CONFSETTING( 0x03, "1100 - RESERVED" ) /* ??, RGBI */
+ PORT_CONFSETTING( 0x0b, "1101 - RESERVED" ) /* ??, RGBI */
+ PORT_CONFSETTING( 0x07, "1110 - RESERVED" ) /* ??, RGBI */
+ PORT_CONFSETTING( 0x0f, "1111 - RESERVED" ) /* ??, RGBI */
+INPUT_PORTS_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_EGA = &device_creator<isa8_ega_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_ega_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_ega );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_ega_device::device_rom_region() const
+{
+ return ROM_NAME( ega );
+}
+
+ioport_constructor isa8_ega_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( ega );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_ega_device - constructor
+//-------------------------------------------------
+
+isa8_ega_device::isa8_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_EGA, "IBM Enhanced Graphics Adapter", tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this)
+{
+ m_shortname = "ega";
+}
+
+isa8_ega_device::isa8_ega_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_ega_device::device_start()
+{
+ astring tempstring;
+
+ set_isa_device();
+
+ for (int i = 0; i < 64; i++ )
+ {
+ UINT8 r = ( ( i & 0x04 ) ? 0xAA : 0x00 ) + ( ( i & 0x20 ) ? 0x55 : 0x00 );
+ UINT8 g = ( ( i & 0x02 ) ? 0xAA : 0x00 ) + ( ( i & 0x10 ) ? 0x55 : 0x00 );
+ UINT8 b = ( ( i & 0x01 ) ? 0xAA : 0x00 ) + ( ( i & 0x08 ) ? 0x55 : 0x00 );
+
+ palette_set_color_rgb( machine(), i, r, g, b );
+ }
+
+ UINT8 *dst = memregion(subtag(tempstring, "user2" ))->base() + 0x0000;
+ UINT8 *src = memregion(subtag(tempstring, "user1" ))->base() + 0x3fff;
+ int i;
+
+ /* Perform the EGA bios address line swaps */
+ for( i = 0; i < 0x4000; i++ )
+ {
+ *dst++ = *src--;
+ }
+ /* Install 256KB Video ram on our EGA card */
+ m_vram = machine().memory().region_alloc(subtag(tempstring,"vram"), 256*1024, 1, ENDIANNESS_LITTLE);
+
+ m_videoram = m_vram->base();
+ m_plane[0] = m_videoram + 0x00000;
+ m_plane[1] = m_videoram + 0x10000;
+ m_plane[2] = m_videoram + 0x20000;
+ m_plane[3] = m_videoram + 0x30000;
+
+ m_crtc_ega = subdevice<crtc_ega_device>(EGA_CRTC_NAME);
+
+ m_isa->install_rom(this, 0xc0000, 0xc3fff, 0, 0, "ega", "user2");
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_w), this));
+ m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_w), this));
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_w), this));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_ega_device::device_reset()
+{
+ m_feature_control = 0;
+
+ memset(&m_attribute,0,sizeof(m_attribute));
+ memset(&m_sequencer,0,sizeof(m_sequencer));
+ memset(&m_graphics_controller,0,sizeof(m_graphics_controller));
+
+ m_frame_cnt = 0;
+ m_hsync = 0;
+ m_vsync = 0;
+ m_vblank = 0;
+ m_display_enable = 0;
+
+ install_banks();
+
+ m_update_row = NULL;
+ m_misc_output = 0;
+ m_attribute.index_write = 1;
+
+ /* Set up default palette */
+ m_attribute.data[0] = 0;
+ m_attribute.data[1] = 1;
+ m_attribute.data[2] = 2;
+ m_attribute.data[3] = 3;
+ m_attribute.data[4] = 4;
+ m_attribute.data[5] = 5;
+ m_attribute.data[6] = 0x14;
+ m_attribute.data[7] = 7;
+ m_attribute.data[8] = 0x38;
+ m_attribute.data[9] = 0x39;
+ m_attribute.data[10] = 0x3A;
+ m_attribute.data[11] = 0x3B;
+ m_attribute.data[12] = 0x3C;
+ m_attribute.data[13] = 0x3D;
+ m_attribute.data[14] = 0x3E;
+ m_attribute.data[15] = 0x3F;
+
+}
+
+void isa8_ega_device::install_banks()
+{
+ switch ( m_graphics_controller.data[6] & 0x0c )
+ {
+ case 0x00: /* 0xA0000, 128KB */
+ if ( m_misc_output & 0x02 )
+ {
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this));
+ }
+ else
+ {
+ m_isa->unmap_bank(0xa0000, 0xaffff,0,0);
+ m_isa->unmap_bank(0xb0000, 0xb7fff,0,0);
+ m_isa->unmap_bank(0xb8000, 0xbffff,0,0);
+ }
+ break;
+ case 0x04: /* 0xA0000, 64KB */
+ if ( m_misc_output & 0x02 )
+ {
+ m_isa->install_memory(0xa0000, 0xaffff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this));
+ }
+ else
+ {
+ m_isa->unmap_bank(0xa0000, 0xaffff,0,0);
+ }
+ /* These unmaps may break multi graphics card support */
+ m_isa->unmap_bank(0xb0000, 0xb7fff,0,0);
+ m_isa->unmap_bank(0xb8000, 0xbffff,0,0);
+ break;
+ case 0x08: /* 0xB0000, 32KB */
+ if ( m_misc_output & 0x02 )
+ {
+ m_isa->install_memory(0xb0000, 0xb7fff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this));
+ }
+ else
+ {
+ m_isa->unmap_bank(0xb0000, 0xb7fff,0,0);
+ }
+ /* These unmaps may break multi graphics card support */
+ m_isa->unmap_bank(0xa0000, 0xaffff,0,0);
+ m_isa->unmap_bank(0xb8000, 0xbffff,0,0);
+ break;
+ case 0x0c: /* 0xB8000, 32KB */
+ if ( m_misc_output & 0x02 )
+ {
+ m_isa->install_memory(0xb8000, 0xbffff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this));
+ }
+ else
+ {
+ m_isa->unmap_bank(0xb8000, 0xbffff,0,0);
+ }
+ /* These unmaps may break multi graphics card support */
+ m_isa->unmap_bank(0xa0000, 0xaffff,0,0);
+ m_isa->unmap_bank(0xb0000, 0xb7fff,0,0);
+ break;
+ }
+}
+
+static SCREEN_UPDATE_IND16( pc_ega )
+{
+ isa8_ega_device *ega = dynamic_cast<isa8_ega_device*>(screen.owner());
+ ega->m_crtc_ega->screen_update( screen, bitmap, cliprect);
+ return 0;
+}
+
+
+static CRTC_EGA_UPDATE_ROW( ega_update_row )
+{
+ isa8_ega_device *ega = dynamic_cast<isa8_ega_device*>(device->owner());
+ if ( ega->m_update_row )
+ {
+ ega->m_update_row( device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param );
+ }
+}
+
+
+WRITE_LINE_MEMBER( isa8_ega_device::de_changed )
+{
+ m_display_enable = state ? 1 : 0;
+}
+
+
+WRITE_LINE_MEMBER( isa8_ega_device::hsync_changed )
+{
+ m_hsync = state ? 1 : 0;
+}
+
+
+WRITE_LINE_MEMBER( isa8_ega_device::vsync_changed )
+{
+ m_vsync = state ? 1 : 0;
+ if ( state )
+ {
+ m_frame_cnt++;
+ }
+}
+
+
+WRITE_LINE_MEMBER( isa8_ega_device::vblank_changed )
+{
+ m_vblank = state ? 8 : 0;
+}
+
+
+static CRTC_EGA_UPDATE_ROW( pc_ega_graphics )
+{
+ isa8_ega_device *ega = dynamic_cast<isa8_ega_device*>(device->owner());
+ UINT16 *p = &bitmap.pix16(y);
+
+// logerror( "pc_ega_graphics: y = %d, x_count = %d, ma = %d, ra = %d\n", y, x_count, ma, ra );
+
+ if ( ega->m_graphics_controller.data[5] & 0x10 )
+ {
+ // Odd/Even mode (CGA compatible)
+
+ for ( int i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) & 0x1fff ) | ( ( y & 1 ) << 12 );
+ UINT8 data = ega->m_plane[0][offset];
+
+ *p = ega->m_attribute.data[ ( data >> 6 ) ]; p++;
+ *p = ega->m_attribute.data[ ( data >> 4 ) & 0x03 ]; p++;
+ *p = ega->m_attribute.data[ ( data >> 2 ) & 0x03 ]; p++;
+ *p = ega->m_attribute.data[ data & 0x03 ]; p++;
+
+ data = ega->m_plane[1][offset];
+
+ *p = ega->m_attribute.data[ ( data >> 6 ) ]; p++;
+ *p = ega->m_attribute.data[ ( data >> 4 ) & 0x03 ]; p++;
+ *p = ega->m_attribute.data[ ( data >> 2 ) & 0x03 ]; p++;
+ *p = ega->m_attribute.data[ data & 0x03 ]; p++;
+ }
+ }
+ else
+ {
+ // EGA mode
+
+ UINT8 mask = ega->m_attribute.data[0x12] & 0x0f;
+
+ for ( int i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ma + i;
+ UINT16 data0 = ega->m_plane[0][offset];
+ UINT16 data1 = ega->m_plane[1][offset] << 1;
+ UINT16 data2 = ega->m_plane[2][offset] << 2;
+ UINT16 data3 = ega->m_plane[3][offset] << 3;
+
+ for ( int j = 7; j >= 0; j-- )
+ {
+ UINT16 col = ( data0 & 0x01 ) | ( data1 & 0x02 ) | ( data2 & 0x04 ) | ( data3 & 0x08 );
+
+ col &= mask;
+
+ p[j] = ega->m_attribute.data[col];
+
+ data0 >>= 1;
+ data1 >>= 1;
+ data2 >>= 1;
+ data3 >>= 1;
+ }
+ p += 8;
+ }
+ }
+}
+
+
+static CRTC_EGA_UPDATE_ROW( pc_ega_text )
+{
+ isa8_ega_device *ega = dynamic_cast<isa8_ega_device*>(device->owner());
+ UINT16 *p = &bitmap.pix16(y);
+ int i;
+
+// logerror( "pc_ega_text: y = %d, x_count = %d, ma = %d, ra = %d\n", y, x_count, ma, ra );
+
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ma + i;
+ UINT8 chr = ega->m_plane[0][ offset ];
+ UINT8 attr = ega->m_plane[1][ offset ];
+ UINT8 data = 0;
+ UINT16 fg = ega->m_attribute.data[ attr & 0x07 ];
+ UINT16 bg = ega->m_attribute.data[ ( attr >> 4 ) & 0x07 ];
+
+ /* If character set A and B are equal attribute bit 3 is used as intensity */
+ if ( ega->m_charA == ega->m_charB )
+ {
+ /* intensity selector */
+ data = ega->m_charB[ chr * 32 + ra ];
+ fg += ( attr & 0x08 ) ? 0x38 : 0x00;
+ }
+ else
+ {
+ /* character set selector */
+ data = ( attr & 0x08 ) ? ega->m_charA[ chr * 32 + ra ] : ega->m_charB[ chr * 32 + ra ];
+ }
+
+ if ( i == cursor_x )
+ {
+ if ( ega->m_frame_cnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ /* Check for blinking */
+ if ( ( ega->m_attribute.data[0x10] & 0x08 ) && ( attr & 0x80 ) && ( ega->m_frame_cnt & 0x10 ) )
+ {
+ data = 0x00;
+ }
+ }
+
+ *p = ( data & 0x80 ) ? fg : bg; p++;
+ *p = ( data & 0x40 ) ? fg : bg; p++;
+ *p = ( data & 0x20 ) ? fg : bg; p++;
+ *p = ( data & 0x10 ) ? fg : bg; p++;
+ *p = ( data & 0x08 ) ? fg : bg; p++;
+ *p = ( data & 0x04 ) ? fg : bg; p++;
+ *p = ( data & 0x02 ) ? fg : bg; p++;
+ *p = ( data & 0x01 ) ? fg : bg; p++;
+ }
+}
+
+
+void isa8_ega_device::change_mode()
+{
+ int clock, pixels;
+
+ m_update_row = NULL;
+
+ /* Check for graphics mode */
+ if ( ( m_attribute.data[0x10] & 0x01 ) &&
+ ! ( m_sequencer.data[0x04] & 0x01 ) &&
+ ( m_graphics_controller.data[0x06] & 0x01 ) )
+ {
+ if ( VERBOSE_EGA )
+ {
+ logerror("change_mode(): Switch to graphics mode\n");
+ }
+
+ m_update_row = pc_ega_graphics;
+ }
+
+ /* Check for text mode */
+ if ( ! ( m_attribute.data[0x10] & 0x01 ) &&
+ ( m_sequencer.data[0x04] & 0x01 ) &&
+ ! ( m_graphics_controller.data[0x06] & 0x01 ) )
+ {
+ if ( VERBOSE_EGA )
+ {
+ logerror("chnage_mode(): Switching to text mode\n");
+ }
+
+ m_update_row = pc_ega_text;
+
+ /* Set character maps */
+ if ( m_sequencer.data[0x04] & 0x02 )
+ {
+ m_charA = m_plane[2] + ( ( m_sequencer.data[0x03] & 0x0c ) >> 1 ) * 0x2000;
+ m_charB = m_plane[2] + ( m_sequencer.data[0x03] & 0x03 ) * 0x2000;
+ }
+ else
+ {
+ m_charA = m_plane[2];
+ m_charB = m_plane[2];
+ }
+ }
+
+ /* Check for changes to the crtc input clock and number of pixels per clock */
+ clock = ( ( m_misc_output & 0x0c ) ? 16257000 : XTAL_14_31818MHz );
+ pixels = ( ( m_sequencer.data[0x01] & 0x01 ) ? 8 : 9 );
+
+ if ( m_sequencer.data[0x01] & 0x08 )
+ {
+ clock >>= 1;
+ }
+ m_crtc_ega->set_clock( clock / pixels );
+ m_crtc_ega->set_hpixels_per_column( pixels );
+
+if ( ! m_update_row )
+ logerror("unknown video mode\n");
+}
+
+
+READ8_MEMBER( isa8_ega_device::read )
+{
+ UINT8 data = 0xFF;
+
+ if ( !space.debugger_access() && ! ( m_sequencer.data[4] & 0x04 ) )
+ {
+ /* Fill read latches */
+ m_read_latch[0] = m_plane[0][offset & 0xffff];
+ m_read_latch[1] = m_plane[1][offset & 0xffff];
+ m_read_latch[2] = m_plane[2][offset & 0xffff];
+ m_read_latch[3] = m_plane[3][offset & 0xffff];
+ }
+
+ if ( m_graphics_controller.data[5] & 0x08 )
+ {
+ // Read mode #1
+ popmessage("ega: Read mode 1 not supported yet!");
+ printf("EGA: Read mode 1 not supported yet!\n");
+ }
+ else
+ {
+ // Read mode #0
+ if ( m_sequencer.data[4] & 0x04 )
+ {
+ // Normal addressing mode
+ data = m_plane[ m_graphics_controller.data[4] & 0x03 ][offset & 0xffff];
+ }
+ else
+ {
+ // Odd/Even addressing mode
+ data = m_plane[offset & 1][(offset & 0xffff) >> 1];
+ }
+ }
+
+ return data;
+}
+
+
+UINT8 isa8_ega_device::alu_op( UINT8 data, UINT8 latch_data )
+{
+ UINT8 mask = m_graphics_controller.data[8];
+
+ switch( m_graphics_controller.data[3] & 0x18 )
+ {
+ case 0x00: // Unmodified
+ return ( data & mask ) | ( latch_data & ~mask );
+
+ case 0x08: // AND
+ return ( data | ~mask ) & latch_data;
+
+ case 0x10: // OR
+ return ( data & mask ) | latch_data;
+
+ case 0x18: // XOR
+ return ( data & mask ) ^ latch_data;
+ }
+ return 0;
+}
+
+
+WRITE8_MEMBER( isa8_ega_device::write )
+{
+ UINT8 d[4];
+ UINT8 alu[4];
+ UINT8 target_mask = m_graphics_controller.data[8];
+
+ alu[0] =alu[1] = alu[2] = alu[3] = 0;
+
+ switch( m_graphics_controller.data[5] & 0x03 )
+ {
+ case 0: // Write mode 0
+ // Pass through barrel shifter
+ data = ( ( ( data << 8 ) | data ) >> ( m_graphics_controller.data[3] & 0x07 ) ) & 0xFF;
+
+ d[0] = d[1] = d[2] = d[3] = data;
+
+ /* Apply Set/Reset settings */
+ if ( m_graphics_controller.data[1] & 0x01 )
+ {
+ d[0] = ( m_graphics_controller.data[0] & 0x01 ) ? 0xff : 0x00;
+ }
+ if ( m_graphics_controller.data[1] & 0x02 )
+ {
+ d[1] = ( m_graphics_controller.data[0] & 0x02 ) ? 0xff : 0x00;
+ }
+ if ( m_graphics_controller.data[1] & 0x04 )
+ {
+ d[2] = ( m_graphics_controller.data[0] & 0x04 ) ? 0xff : 0x00;
+ }
+ if ( m_graphics_controller.data[1] & 0x08 )
+ {
+ d[3] = ( m_graphics_controller.data[0] & 0x08 ) ? 0xff : 0x00;
+ }
+
+ // Pass through ALUs
+ alu[0] = alu_op( d[0], m_read_latch[0] );
+ alu[1] = alu_op( d[1], m_read_latch[1] );
+ alu[2] = alu_op( d[2], m_read_latch[2] );
+ alu[3] = alu_op( d[3], m_read_latch[3] );
+
+ break;
+
+ case 1: // Write mode 1
+ alu[0] = m_read_latch[0];
+ alu[1] = m_read_latch[1];
+ alu[2] = m_read_latch[2];
+ alu[3] = m_read_latch[3];
+ target_mask = 0xff;
+ return;
+
+ case 2: // Write mode 2
+ d[0] = ( data & 0x01 ) ? 0xff : 0x00;
+ d[1] = ( data & 0x02 ) ? 0xff : 0x00;
+ d[2] = ( data & 0x04 ) ? 0xff : 0x00;
+ d[3] = ( data & 0x08 ) ? 0xff : 0x00;
+
+ alu[0] = alu_op( d[0], m_read_latch[0] );
+ alu[1] = alu_op( d[1], m_read_latch[1] );
+ alu[2] = alu_op( d[2], m_read_latch[2] );
+ alu[3] = alu_op( d[3], m_read_latch[3] );
+ break;
+
+ case 3: // Write mode 3
+ popmessage("EGA: Write mode 3 not supported!");
+ return;
+ }
+
+ offset &= 0xffff;
+
+ //
+ // Plane selection
+ // TODO: Get this logic clearer. The documentation is unclear on the exact magic combination of bits.
+ //
+ if ( m_sequencer.data[4] & 0x04 )
+ {
+ // Sequential addressing mode
+ if ( m_sequencer.data[2] & 0x01 )
+ {
+ // Plane 0
+ // Bit selection
+ m_plane[0][offset] = ( m_plane[0][offset] & ~ target_mask ) | ( alu[0] & target_mask );
+ }
+ if ( m_sequencer.data[2] & 0x02 )
+ {
+ // Plane 1
+ // Bit selection
+ m_plane[1][offset] = ( m_plane[1][offset] & ~ target_mask ) | ( alu[1] & target_mask );
+ }
+ if ( m_sequencer.data[2] & 0x04 )
+ {
+ // Plane 2
+ // Bit selection
+ m_plane[2][offset] = ( m_plane[2][offset] & ~ target_mask ) | ( alu[2] & target_mask );
+ }
+ if ( m_sequencer.data[2] & 0x08 )
+ {
+ // Plane 3
+ // Bit selection
+ m_plane[3][offset] = ( m_plane[3][offset] & ~ target_mask ) | ( alu[3] & target_mask );
+ }
+ }
+ else
+ {
+ // Odd/Even addressing mode
+ if ( offset & 1 )
+ {
+ // Odd addresses go to planes 1 and 3
+
+ offset >>= 1;
+
+ if ( m_sequencer.data[2] & 0x02 )
+ {
+ // Plane 1
+ // Bit selection
+ m_plane[1][offset] = ( m_plane[1][offset] & ~ target_mask ) | ( alu[1] & target_mask );
+ }
+ if ( ( m_sequencer.data[2] & 0x08 ) && ! ( m_sequencer.data[4] & 0x01 ) )
+ {
+ // Plane 3
+ // Bit selection
+ m_plane[3][offset] = ( m_plane[3][offset] & ~ target_mask ) | ( alu[3] & target_mask );
+ }
+ }
+ else
+ {
+ // Even addresses go to planes 0 and 2
+
+ offset >>= 1;
+
+ if ( m_sequencer.data[2] & 0x01 )
+ {
+ // Plane 0
+ // Bit selection
+ m_plane[0][offset] = ( m_plane[0][offset] & ~ target_mask ) | ( alu[0] & target_mask );
+ }
+ if ( ( m_sequencer.data[2] & 0x04 ) && ! ( m_sequencer.data[4] & 0x01 ) )
+ {
+ // Plane 2
+ // Bit selection
+ m_plane[2][offset] = ( m_plane[2][offset] & ~ target_mask ) | ( alu[2] & target_mask );
+ }
+ }
+ }
+}
+
+
+READ8_MEMBER( isa8_ega_device::pc_ega8_3X0_r )
+{
+ int data = 0xff;
+
+ switch ( offset )
+ {
+ /* CRT Controller - address register */
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+
+ /* CRT Controller - data register */
+ case 1: case 3: case 5: case 7:
+ data = m_crtc_ega->register_r( space, offset );
+ break;
+
+ /* Input Status Register 1 */
+ case 10:
+ data = m_vblank | ( m_hsync | m_vsync ); // m_display_enable;
+
+ if ( m_display_enable )
+ {
+ /* For the moment i'm putting in some bogus data */
+ static int pixel_data;
+
+ pixel_data = ( pixel_data + 1 ) & 0x03;
+ data |= ( pixel_data << 4 );
+ }
+
+ /* Reset the attirubte writing flip flop to let the next write go to the index reigster */
+ m_attribute.index_write = 1;
+ break;
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER( isa8_ega_device::pc_ega8_3X0_w )
+{
+ if ( VERBOSE_EGA )
+ {
+// logerror("pc_ega_3X0_w: offset = %02x, data = %02x\n", offset, data );
+ }
+
+ switch ( offset )
+ {
+ /* CRT Controller - address register */
+ case 0: case 2: case 4: case 6:
+ m_crtc_ega->address_w( space, offset, data );
+ break;
+
+ /* CRT Controller - data register */
+ case 1: case 3: case 5: case 7:
+ m_crtc_ega->register_w( space, offset, data );
+ break;
+
+ /* Set Light Pen Flip Flop */
+ case 9:
+ break;
+
+ /* Feature Control */
+ case 10:
+ m_feature_control = data;
+ break;
+
+ /* Clear Light Pen Flip Flop */
+ case 11:
+ break;
+ }
+}
+
+
+
+READ8_MEMBER(isa8_ega_device::pc_ega8_3b0_r )
+{
+ return ( m_misc_output & 0x01 ) ? 0xFF : pc_ega8_3X0_r(space, offset);
+}
+
+
+READ8_MEMBER(isa8_ega_device::pc_ega8_3d0_r )
+{
+ return ( m_misc_output & 0x01 ) ? pc_ega8_3X0_r(space, offset) : 0xFF;
+}
+
+
+WRITE8_MEMBER(isa8_ega_device::pc_ega8_3b0_w )
+{
+ if ( ! ( m_misc_output & 0x01 ) )
+ {
+ pc_ega8_3X0_w( space, offset, data );
+ }
+}
+
+
+WRITE8_MEMBER(isa8_ega_device::pc_ega8_3d0_w )
+{
+ if ( m_misc_output & 0x01 )
+ {
+ pc_ega8_3X0_w( space, offset, data );
+ }
+}
+
+
+READ8_MEMBER(isa8_ega_device::pc_ega8_3c0_r )
+{
+ int data = 0xff;
+
+ if ( VERBOSE_EGA )
+ {
+// logerror("pc_ega_3c0_r: offset = %02x\n", offset );
+ }
+
+ switch ( offset )
+ {
+ /* Attributes Controller */
+ case 0:
+ break;
+
+ /* Feature Read */
+ case 2:
+ {
+ UINT8 dips = ioport("config")->read();
+
+ data = ( data & 0x0f );
+ data |= ( ( m_feature_control & 0x03 ) << 5 );
+ data |= ( m_vsync ? 0x00 : 0x80 );
+ data |= ( ( ( dips >> ( ( ( m_misc_output & 0x0c ) >> 2 ) ) ) & 0x01 ) << 4 );
+ }
+ break;
+
+ /* Sequencer */
+ case 4:
+ break;
+ case 5:
+ break;
+
+ /* Graphics Controller */
+ case 14:
+ break;
+ case 15:
+ break;
+ }
+ return data;
+}
+
+
+WRITE8_MEMBER(isa8_ega_device::pc_ega8_3c0_w )
+{
+ static const UINT8 ar_reg_mask[0x20] =
+ {
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x7F, 0x3F, 0x3F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const UINT8 sr_reg_mask[0x08] =
+ {
+ 0x03, 0x0F, 0x0F, 0x0F, 0x07, 0x00, 0x00, 0x00
+ };
+ static const UINT8 gr_reg_mask[0x10] =
+ {
+ 0x0F, 0x0F, 0x0F, 0x1F, 0x07, 0x3F, 0x0F, 0x0F,
+ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ int index = 0;
+
+ if ( VERBOSE_EGA )
+ {
+// logerror("pc_ega_3c0_w: offset = %02x, data = %02x\n", offset, data );
+ }
+
+ switch ( offset )
+ {
+ /* Attributes Controller */
+ case 0:
+ if ( m_attribute.index_write )
+ {
+ m_attribute.index = data;
+ }
+ else
+ {
+ index = m_attribute.index & 0x1F;
+
+ logerror("AR%02X = 0x%02x\n", index, data );
+
+ /* Clear unused bits */
+ m_attribute.data[ index ] = data & ar_reg_mask[ index ];
+
+ switch ( index )
+ {
+ case 0x10: /* AR10 */
+ change_mode();
+ break;
+ }
+ }
+ m_attribute.index_write ^= 0x01;
+ break;
+
+ /* Misccellaneous Output */
+ case 2:
+ m_misc_output = data;
+ install_banks();
+ change_mode();
+ break;
+
+ /* Sequencer */
+ case 4:
+ m_sequencer.index = data;
+ break;
+ case 5:
+ index = m_sequencer.index & 0x07;
+
+ logerror("SR%02X = 0x%02x\n", index & 0x07, data );
+
+ /* Clear unused bits */
+ m_sequencer.data[ index ] = data & sr_reg_mask[ index ];
+
+ switch ( index )
+ {
+ case 0x01: /* SR01 */
+ case 0x03: /* SR03 */
+ case 0x04: /* SR04 */
+ change_mode();
+ break;
+ }
+ break;
+
+ /* Graphics Controller */
+ case 14:
+ m_graphics_controller.index = data;
+ break;
+ case 15:
+ index = m_graphics_controller.index & 0x0F;
+
+ logerror("GR%02X = 0x%02x\n", index, data );
+
+ /* Clear unused bits */
+ m_graphics_controller.data[ index ] = data & gr_reg_mask[ index ];
+
+ switch ( index )
+ {
+ case 0x06: /* GR06 */
+ change_mode();
+ install_banks();
+ break;
+ }
+ break;
+ }
+}
diff --git a/src/mess/video/isa_ega.h b/src/mess/video/isa_ega.h
new file mode 100644
index 00000000000..4717b1af6f7
--- /dev/null
+++ b/src/mess/video/isa_ega.h
@@ -0,0 +1,106 @@
+#pragma once
+
+#ifndef __ISA_EGA_H__
+#define __ISA_EGA_H__
+
+#include "emu.h"
+#include "machine/isa.h"
+#include "video/crtc_ega.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_ega_device
+
+class isa8_ega_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ isa8_ega_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ DECLARE_READ8_MEMBER(read);
+ DECLARE_WRITE8_MEMBER(write);
+ DECLARE_READ8_MEMBER(pc_ega8_3b0_r);
+ DECLARE_WRITE8_MEMBER(pc_ega8_3b0_w);
+ DECLARE_READ8_MEMBER(pc_ega8_3c0_r);
+ DECLARE_WRITE8_MEMBER(pc_ega8_3c0_w);
+ DECLARE_READ8_MEMBER(pc_ega8_3d0_r);
+ DECLARE_WRITE8_MEMBER(pc_ega8_3d0_w);
+ DECLARE_WRITE_LINE_MEMBER(de_changed);
+ DECLARE_WRITE_LINE_MEMBER(hsync_changed);
+ DECLARE_WRITE_LINE_MEMBER(vsync_changed);
+ DECLARE_WRITE_LINE_MEMBER(vblank_changed);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ UINT8 alu_op( UINT8 data, UINT8 latch_data );
+
+public:
+ crtc_ega_device *m_crtc_ega;
+
+ void install_banks();
+ void change_mode();
+ DECLARE_WRITE8_MEMBER(pc_ega8_3X0_w);
+ DECLARE_READ8_MEMBER(pc_ega8_3X0_r);
+
+ crtc_ega_update_row_func m_update_row;
+
+ /* Video memory and related variables */
+ memory_region *m_vram;
+ UINT8 *m_plane[4];
+ UINT8 m_read_latch[4];
+ UINT8 *m_videoram;
+ UINT8 *m_charA;
+ UINT8 *m_charB;
+
+ /* Registers */
+ UINT8 m_misc_output;
+ UINT8 m_feature_control;
+
+ /* Attribute registers AR00 - AR14
+ */
+ struct {
+ UINT8 index;
+ UINT8 data[32];
+ UINT8 index_write;
+ } m_attribute;
+
+ /* Sequencer registers SR00 - SR04
+ */
+ struct {
+ UINT8 index;
+ UINT8 data[8];
+ } m_sequencer;
+
+ /* Graphics controller registers GR00 - GR08
+ */
+ struct {
+ UINT8 index;
+ UINT8 data[16];
+ } m_graphics_controller;
+
+ UINT8 m_frame_cnt;
+ UINT8 m_hsync;
+ UINT8 m_vsync;
+ UINT8 m_vblank;
+ UINT8 m_display_enable;
+};
+
+
+// device type definition
+extern const device_type ISA8_EGA;
+
+#endif /* __ISA_EGA_H__ */
+
diff --git a/src/mess/video/isa_mda.c b/src/mess/video/isa_mda.c
new file mode 100644
index 00000000000..29696a386e3
--- /dev/null
+++ b/src/mess/video/isa_mda.c
@@ -0,0 +1,740 @@
+/***************************************************************************
+
+ Monochrome Display Adapter (MDA) section
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_mda.h"
+#include "video/mc6845.h"
+#include "machine/pc_lpt.h"
+
+#define MDA_SCREEN_NAME "mda_screen"
+#define MDA_MC6845_NAME "mc6845_mda"
+
+/*
+ Hercules video card
+ */
+#define HERCULES_SCREEN_NAME "hercules_screen"
+#define HERCULES_MC6845_NAME "mc6845_hercules"
+
+#define VERBOSE_MDA 0 /* MDA (Monochrome Display Adapter) */
+
+#define MDA_CLOCK 16257000
+
+#define MDA_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_MDA>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",device->machine().time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+static const unsigned char mda_palette[4][3] =
+{
+ { 0x00,0x00,0x00 },
+ { 0x00,0x55,0x00 },
+ { 0x00,0xaa,0x00 },
+ { 0x00,0xff,0x00 }
+};
+
+static MC6845_UPDATE_ROW( mda_update_row );
+
+/* F4 Character Displayer */
+static const gfx_layout pc_16_charlayout =
+{
+ 8, 16, /* 8 x 16 characters */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ { 0 }, /* no bitplanes */
+ /* x offsets */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 2048*8, 2049*8, 2050*8, 2051*8, 2052*8, 2053*8, 2054*8, 2055*8 },
+ 8*8 /* every char takes 2 x 8 bytes */
+};
+
+static const gfx_layout pc_8_charlayout =
+{
+ 8, 8, /* 8 x 8 characters */
+ 512, /* 512 characters */
+ 1, /* 1 bits per pixel */
+ { 0 }, /* no bitplanes */
+ /* x offsets */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8 /* every char takes 8 bytes */
+};
+
+static GFXDECODE_START( pcmda )
+ GFXDECODE_ENTRY( "mda:gfx1", 0x0000, pc_16_charlayout, 1, 1 )
+ GFXDECODE_ENTRY( "mda:gfx1", 0x1000, pc_8_charlayout, 1, 1 )
+GFXDECODE_END
+
+static const mc6845_interface mc6845_mda_intf =
+{
+ MDA_SCREEN_NAME, /* screen number */
+ 9, /* number of pixels per video memory address */
+ NULL, /* begin_update */
+ mda_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_mda_device, hsync_changed), /* on_hsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_mda_device, vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+static WRITE_LINE_DEVICE_HANDLER(pc_cpu_line)
+{
+ isa8_mda_device *mda = downcast<isa8_mda_device *>(device->owner());
+ mda->m_isa->irq7_w(state);
+}
+static const pc_lpt_interface pc_lpt_config =
+{
+ DEVCB_LINE(pc_cpu_line)
+};
+
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_mda )
+ MCFG_SCREEN_ADD( MDA_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(MDA_CLOCK, 882, 0, 720, 370, 0, 350 )
+ MCFG_SCREEN_UPDATE_DEVICE( MDA_MC6845_NAME, mc6845_device, screen_update )
+
+ MCFG_PALETTE_LENGTH( 4 )
+
+ MCFG_MC6845_ADD( MDA_MC6845_NAME, MC6845, MDA_CLOCK/9, mc6845_mda_intf)
+
+ //MCFG_GFXDECODE(pcmda)
+
+ MCFG_PC_LPT_ADD("lpt", pc_lpt_config)
+MACHINE_CONFIG_END
+
+ROM_START( mda )
+ /* IBM 1501981(CGA) and 1501985(MDA) Character rom */
+ ROM_REGION(0x08100,"gfx1", 0)
+ ROM_LOAD("5788005.u33", 0x00000, 0x02000, CRC(0bf56d70) SHA1(c2a8b10808bf51a3c123ba3eb1e9dd608231916f)) /* "AMI 8412PI // 5788005 // (C) IBM CORP. 1981 // KOREA" */
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_MDA = &device_creator<isa8_mda_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_mda_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_mda );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_mda_device::device_rom_region() const
+{
+ return ROM_NAME( mda );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_mda_device - constructor
+//-------------------------------------------------
+
+isa8_mda_device::isa8_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_MDA, "IBM Monochrome Display and Printer Adapter", tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this)
+{
+ m_shortname = "isa_ibm_mda";
+}
+
+isa8_mda_device::isa8_mda_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this)
+{
+ m_shortname = "isa_ibm_mda";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_mda_device::device_start()
+{
+ set_isa_device();
+ m_videoram = auto_alloc_array(machine(), UINT8, 0x1000);
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate( FUNC(isa8_mda_device::io_read), this ), write8_delegate( FUNC(isa8_mda_device::io_write), this ) );
+ m_isa->install_bank(0xb0000, 0xb0fff, 0, 0x07000, "bank_mda", m_videoram);
+
+ /* Initialise the mda palette */
+ for(int i = 0; i < (sizeof(mda_palette) / 3); i++)
+ palette_set_color_rgb(machine(), i, mda_palette[i][0], mda_palette[i][1], mda_palette[i][2]);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_mda_device::device_reset()
+{
+ m_update_row = NULL;
+ m_framecnt = 0;
+ m_mode_control = 0;
+ m_vsync = 0;
+ m_hsync = 0;
+ m_pixel = 0;
+
+ astring tempstring;
+ m_chr_gen = memregion(subtag(tempstring, "gfx1"))->base();
+}
+
+/***************************************************************************
+
+ Monochrome Display Adapter (MDA) section
+
+***************************************************************************/
+
+/***************************************************************************
+ Draw text mode with 80x25 characters (default) and intense background.
+ The character cell size is 9x15. Column 9 is column 8 repeated for
+ character codes 176 to 223.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( mda_text_inten_update_row )
+{
+ isa8_mda_device *mda = downcast<isa8_mda_device *>(device->owner());
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
+ int i;
+
+ if ( y == 0 ) MDA_LOG(1,"mda_text_inten_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF;
+ UINT8 chr = mda->m_videoram[ offset ];
+ UINT8 attr = mda->m_videoram[ offset + 1 ];
+ UINT8 data = mda->m_chr_gen[ chr_base + chr * 8 ];
+ UINT8 fg = ( attr & 0x08 ) ? 3 : 2;
+ UINT8 bg = 0;
+
+ if ( ( attr & ~0x88 ) == 0 )
+ {
+ data = 0x00;
+ }
+
+ switch( attr )
+ {
+ case 0x70:
+ bg = 2;
+ fg = 0;
+ break;
+ case 0x78:
+ bg = 2;
+ fg = 1;
+ break;
+ case 0xF0:
+ bg = 3;
+ fg = 0;
+ break;
+ case 0xF8:
+ bg = 3;
+ fg = 1;
+ break;
+ }
+
+ if ( ( i == cursor_x && ( mda->m_framecnt & 0x08 ) ) || ( attr & 0x07 ) == 0x01 )
+ {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ if ( ( chr & 0xE0 ) == 0xC0 )
+ {
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+ else
+ {
+ *p = palette[bg]; p++;
+ }
+ }
+}
+
+
+/***************************************************************************
+ Draw text mode with 80x25 characters (default) and blinking characters.
+ The character cell size is 9x15. Column 9 is column 8 repeated for
+ character codes 176 to 223.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( mda_text_blink_update_row )
+{
+ isa8_mda_device *mda = downcast<isa8_mda_device *>(device->owner());
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
+ int i;
+
+ if ( y == 0 ) MDA_LOG(1,"mda_text_blink_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF;
+ UINT8 chr = mda->m_videoram[ offset ];
+ UINT8 attr = mda->m_videoram[ offset + 1 ];
+ UINT8 data = mda->m_chr_gen[ chr_base + chr * 8 ];
+ UINT8 fg = ( attr & 0x08 ) ? 3 : 2;
+ UINT8 bg = 0;
+
+ if ( ( attr & ~0x88 ) == 0 )
+ {
+ data = 0x00;
+ }
+
+ switch( attr )
+ {
+ case 0x70:
+ case 0xF0:
+ bg = 2;
+ fg = 0;
+ break;
+ case 0x78:
+ case 0xF8:
+ bg = 2;
+ fg = 1;
+ break;
+ }
+
+ if ( ( attr & 0x07 ) == 0x01 )
+ {
+ data = 0xFF;
+ }
+
+ if ( i == cursor_x )
+ {
+ if ( mda->m_framecnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ if ( ( attr & 0x80 ) && ( mda->m_framecnt & 0x10 ) )
+ {
+ data = 0x00;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ if ( ( chr & 0xE0 ) == 0xC0 )
+ {
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+ else
+ {
+ *p = palette[bg]; p++;
+ }
+ }
+}
+
+
+static MC6845_UPDATE_ROW( mda_update_row )
+{
+ isa8_mda_device *mda = downcast<isa8_mda_device *>(device->owner());
+ if ( mda->m_update_row )
+ {
+ mda->m_update_row( device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param );
+ }
+}
+
+
+WRITE_LINE_MEMBER( isa8_mda_device::hsync_changed )
+{
+ m_hsync = state ? 1 : 0;
+}
+
+
+WRITE_LINE_MEMBER( isa8_mda_device::vsync_changed )
+{
+ m_vsync = state ? 0x80 : 0;
+ if ( state )
+ {
+ m_framecnt++;
+ }
+}
+
+
+/*
+ * rW MDA mode control register (see #P138)
+ */
+WRITE8_MEMBER( isa8_mda_device::mode_control_w )
+{
+ m_mode_control = data;
+
+ switch( m_mode_control & 0x2a )
+ {
+ case 0x08:
+ m_update_row = mda_text_inten_update_row;
+ break;
+ case 0x28:
+ m_update_row = mda_text_blink_update_row;
+ break;
+ default:
+ m_update_row = NULL;
+ }
+}
+
+
+/* R- CRT status register (see #P139)
+ * (EGA/VGA) input status 1 register
+ * 7 HGC vertical sync in progress
+ * 6-4 adapter 000 hercules
+ * 001 hercules+
+ * 101 hercules InColor
+ * else unknown
+ * 3 pixel stream (0 black, 1 white)
+ * 2-1 reserved
+ * 0 horizontal drive enable
+ */
+READ8_MEMBER( isa8_mda_device::status_r)
+{
+ // Faking pixel stream here
+ m_pixel++;
+
+ return 0xF0 | (m_pixel & 0x08) | m_hsync;
+}
+
+
+/*************************************************************************
+ *
+ * MDA
+ * monochrome display adapter
+ *
+ *************************************************************************/
+WRITE8_MEMBER( isa8_mda_device::io_write)
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(MDA_MC6845_NAME);
+ device_t *lpt = subdevice("lpt");
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ mc6845->address_w( space, offset, data );
+ break;
+ case 1: case 3: case 5: case 7:
+ mc6845->register_w( space, offset, data );
+ break;
+ case 8:
+ mode_control_w(space, offset, data);
+ break;
+ case 12: case 13: case 14:
+ pc_lpt_w(lpt, offset - 12, data);
+ break;
+ }
+}
+
+READ8_MEMBER( isa8_mda_device::io_read)
+{
+ int data = 0xff;
+ mc6845_device *mc6845 = subdevice<mc6845_device>(MDA_MC6845_NAME);
+ device_t *lpt = subdevice("lpt");
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+ case 1: case 3: case 5: case 7:
+ data = mc6845->register_r( space, offset );
+ break;
+ case 10:
+ data = status_r(space, offset);
+ break;
+ /* 12, 13, 14 are the LPT ports */
+ case 12: case 13: case 14:
+ data = pc_lpt_r(lpt, offset - 12);
+ break;
+ }
+ return data;
+}
+
+
+/***************************************************************************
+
+ Hercules Display Adapter section (re-uses parts from the MDA section)
+
+***************************************************************************/
+
+/*
+When the Hercules changes to graphics mode, the number of pixels per access and
+clock divider should be changed. The currect mc6845 implementation does not
+allow this.
+
+The divder/pixels per 6845 clock is 9 for text mode and 16 for graphics mode.
+*/
+
+static const mc6845_interface mc6845_hercules_intf =
+{
+ HERCULES_SCREEN_NAME, /* screen number */
+ 9, /* number of pixels per video memory address */
+ NULL, /* begin_update */
+ mda_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_mda_device, hsync_changed), /* on_hsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_mda_device, vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+static GFXDECODE_START( pcherc )
+ GFXDECODE_ENTRY( "hercules:gfx1", 0x0000, pc_16_charlayout, 1, 1 )
+GFXDECODE_END
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_hercules )
+ MCFG_SCREEN_ADD( HERCULES_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(MDA_CLOCK, 882, 0, 720, 370, 0, 350 )
+ MCFG_SCREEN_UPDATE_DEVICE( HERCULES_MC6845_NAME, mc6845_device, screen_update )
+
+ MCFG_PALETTE_LENGTH( 4 )
+
+ MCFG_MC6845_ADD( HERCULES_MC6845_NAME, MC6845, MDA_CLOCK/9, mc6845_hercules_intf)
+
+ //MCFG_GFXDECODE(pcherc)
+
+ MCFG_PC_LPT_ADD("lpt", pc_lpt_config)
+MACHINE_CONFIG_END
+
+ROM_START( hercules )
+ ROM_REGION(0x1000,"gfx1", 0)
+ ROM_LOAD("um2301.bin", 0x00000, 0x1000, CRC(0827bdac) SHA1(15f1aceeee8b31f0d860ff420643e3c7f29b5ffc))
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_HERCULES = &device_creator<isa8_hercules_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_hercules_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_hercules );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_hercules_device::device_rom_region() const
+{
+ return ROM_NAME( hercules );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_hercules_device - constructor
+//-------------------------------------------------
+
+isa8_hercules_device::isa8_hercules_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_mda_device(mconfig, ISA8_HERCULES, "Hercules Graphics Card", tag, owner, clock)
+{
+ m_shortname = "isa_hercules";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_hercules_device::device_start()
+{
+ m_videoram = auto_alloc_array(machine(), UINT8, 0x10000);
+ set_isa_device();
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate( FUNC(isa8_hercules_device::io_read), this ), write8_delegate( FUNC(isa8_hercules_device::io_write), this ) );
+ m_isa->install_bank(0xb0000, 0xbffff, 0, 0, "bank_hercules", m_videoram);
+
+ /* Initialise the mda palette */
+ for(int i = 0; i < (sizeof(mda_palette) / 3); i++)
+ palette_set_color_rgb(machine(), i, mda_palette[i][0], mda_palette[i][1], mda_palette[i][2]);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_hercules_device::device_reset()
+{
+ isa8_mda_device::device_reset();
+ m_configuration_switch = 0;
+
+ astring tempstring;
+ m_chr_gen = memregion(subtag(tempstring, "gfx1"))->base();
+}
+
+/***************************************************************************
+ Draw graphics with 720x348 pixels (default); so called Hercules gfx.
+ The memory layout is divided into 4 banks where of size 0x2000.
+ Every bank holds data for every n'th scanline, 8 pixels per byte,
+ bit 7 being the leftmost.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( hercules_gfx_update_row )
+{
+ isa8_hercules_device *herc = downcast<isa8_hercules_device *>(device->owner());
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT16 gfx_base = ( ( herc->m_mode_control & 0x80 ) ? 0x8000 : 0x0000 ) | ( ( ra & 0x03 ) << 13 );
+ int i;
+ if ( y == 0 ) MDA_LOG(1,"hercules_gfx_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT8 data = herc->m_videoram[ gfx_base + ( ( ma + i ) << 1 ) ];
+
+ *p = palette[( data & 0x80 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x40 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x20 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x10 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x08 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x04 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x02 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x01 ) ? 2 : 0]; p++;
+
+ data = herc->m_videoram[ gfx_base + ( ( ma + i ) << 1 ) + 1 ];
+
+ *p = palette[( data & 0x80 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x40 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x20 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x10 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x08 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x04 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x02 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x01 ) ? 2 : 0]; p++;
+ }
+}
+
+
+WRITE8_MEMBER( isa8_hercules_device::mode_control_w )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(HERCULES_MC6845_NAME);
+
+ m_mode_control = data;
+
+ switch( m_mode_control & 0x2a )
+ {
+ case 0x08:
+ m_update_row = mda_text_inten_update_row;
+ break;
+ case 0x28:
+ m_update_row = mda_text_blink_update_row;
+ break;
+ case 0x0A: /* Hercules modes */
+ case 0x2A:
+ m_update_row = hercules_gfx_update_row;
+ break;
+ default:
+ m_update_row = NULL;
+ }
+
+ mc6845->set_clock( m_mode_control & 0x02 ? MDA_CLOCK / 16 : MDA_CLOCK / 9 );
+ mc6845->set_hpixels_per_column( m_mode_control & 0x02 ? 16 : 9 );
+}
+
+
+WRITE8_MEMBER( isa8_hercules_device::io_write )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(HERCULES_MC6845_NAME);
+ device_t *lpt = subdevice("lpt");
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ mc6845->address_w( space, offset, data );
+ break;
+ case 1: case 3: case 5: case 7:
+ mc6845->register_w( space, offset, data );
+ break;
+ case 8:
+ mode_control_w(space, offset, data);
+ break;
+ case 12: case 13: case 14:
+ pc_lpt_w(lpt, offset - 12, data);
+ break;
+ case 15:
+ m_configuration_switch = data;
+ break;
+ }
+}
+
+
+/* R- CRT status register (see #P139)
+ * (EGA/VGA) input status 1 register
+ * 7 HGC vertical sync in progress
+ * 6-4 adapter 000 hercules
+ * 001 hercules+
+ * 101 hercules InColor
+ * else unknown
+ * 3 pixel stream (0 black, 1 white)
+ * 2-1 reserved
+ * 0 horizontal drive enable
+ */
+READ8_MEMBER( isa8_hercules_device::status_r )
+{
+ // Faking pixel stream here
+ m_pixel++;
+
+ return m_vsync | ( m_pixel & 0x08 ) | m_hsync;
+}
+
+
+READ8_MEMBER( isa8_hercules_device::io_read )
+{
+ int data = 0xff;
+ mc6845_device *mc6845 = subdevice<mc6845_device>(HERCULES_MC6845_NAME);
+ device_t *lpt = subdevice("lpt");
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+ case 1: case 3: case 5: case 7:
+ data = mc6845->register_r( space, offset );
+ break;
+ case 10:
+ data = status_r(space, offset);
+ break;
+ /* 12, 13, 14 are the LPT ports */
+ case 12: case 13: case 14:
+ data = pc_lpt_r(lpt, offset - 12);
+ break;
+ }
+ return data;
+}
diff --git a/src/mess/video/isa_mda.h b/src/mess/video/isa_mda.h
new file mode 100644
index 00000000000..cf8d4ce88ad
--- /dev/null
+++ b/src/mess/video/isa_mda.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#ifndef __ISA_MDA_H__
+#define __ISA_MDA_H__
+
+#include "emu.h"
+#include "machine/isa.h"
+#include "video/mc6845.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_mda_device
+
+class isa8_mda_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ friend class isa8_hercules_device;
+
+ // construction/destruction
+ isa8_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ isa8_mda_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_WRITE_LINE_MEMBER(hsync_changed);
+ DECLARE_WRITE_LINE_MEMBER(vsync_changed);
+ virtual DECLARE_READ8_MEMBER(io_read);
+ virtual DECLARE_WRITE8_MEMBER(io_write);
+ virtual DECLARE_READ8_MEMBER(status_r);
+ virtual DECLARE_WRITE8_MEMBER(mode_control_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+public:
+ int m_framecnt;
+
+ UINT8 m_mode_control;
+
+ mc6845_update_row_func m_update_row;
+ UINT8 *m_chr_gen;
+ UINT8 m_vsync;
+ UINT8 m_hsync;
+ UINT8 *m_videoram;
+ UINT8 m_pixel;
+};
+
+
+// device type definition
+extern const device_type ISA8_MDA;
+
+// ======================> isa8_hercules_device
+
+class isa8_hercules_device :
+ public isa8_mda_device
+{
+public:
+ // construction/destruction
+ isa8_hercules_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ virtual DECLARE_READ8_MEMBER(io_read);
+ virtual DECLARE_WRITE8_MEMBER(io_write);
+ virtual DECLARE_READ8_MEMBER(status_r);
+ virtual DECLARE_WRITE8_MEMBER(mode_control_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ // internal state
+public:
+ UINT8 m_configuration_switch; //hercules
+};
+
+
+// device type definition
+extern const device_type ISA8_HERCULES;
+
+#endif /* __ISA_MDA_H__ */
diff --git a/src/mess/video/isa_svga_cirrus.c b/src/mess/video/isa_svga_cirrus.c
new file mode 100644
index 00000000000..2a8c9636a33
--- /dev/null
+++ b/src/mess/video/isa_svga_cirrus.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+
+ ISA SVGA Cirrus Logic wrapper
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_svga_cirrus.h"
+#include "video/pc_vga.h"
+
+ROM_START( dm_clgd5430 )
+ ROM_REGION(0x8000,"dm_clgd5430", 0)
+ ROM_LOAD("speedstar_pro_se_v1.00.u2", 0x00000, 0x8000, CRC(ed79572c) SHA1(15131e2b2db7a34971083a250e4a21ab7bd64a9d) )
+ ROM_IGNORE( 0x8000 )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_SVGA_CIRRUS = &device_creator<isa8_svga_cirrus_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_svga_cirrus_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_vga_isa );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_svga_cirrus_device::device_rom_region() const
+{
+ return ROM_NAME( dm_clgd5430 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_vga_device - constructor
+//-------------------------------------------------
+
+isa8_svga_cirrus_device::isa8_svga_cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_SVGA_CIRRUS, "Diamond Multimedia Graphics Card", tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this)
+{
+ m_shortname = "dm_clgd5430";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+static READ8_HANDLER( input_port_0_r ) { return 0xff; } //return space->machine().root_device().ioport("IN0")->read(); }
+
+void isa8_svga_cirrus_device::device_start()
+{
+ set_isa_device();
+
+ video_start_vga( machine() );
+
+ pc_vga_init(machine(), input_port_0_r, NULL);
+
+ int i;
+ for (i = 0; i < 0x100; i++)
+ palette_set_color_rgb(machine(), i, 0, 0, 0);
+ pc_video_start(machine());
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "dm_clgd5430");
+
+ m_isa->install_device(0x03b0, 0x03bf, 0, 0, FUNC(vga_port_03b0_r), FUNC(vga_port_03b0_w));
+ m_isa->install_device(0x03c0, 0x03cf, 0, 0, FUNC(vga_port_03c0_r), FUNC(vga_port_03c0_w));
+ m_isa->install_device(0x03d0, 0x03df, 0, 0, FUNC(vga_port_03d0_r), FUNC(vga_port_03d0_w));
+// m_isa->install_device(0x9ae8, 0x9aeb, 0, 0, FUNC(s3_port_9ae8_r), FUNC(s3_port_9ae8_w));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, FUNC(vga_mem_r), FUNC(vga_mem_w));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_svga_cirrus_device::device_reset()
+{
+ pc_vga_reset(machine());
+}
diff --git a/src/mess/video/isa_svga_cirrus.h b/src/mess/video/isa_svga_cirrus.h
new file mode 100644
index 00000000000..e57a37f7b8e
--- /dev/null
+++ b/src/mess/video/isa_svga_cirrus.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#ifndef __ISA_SVGA_CIRRUS_H__
+#define __ISA_SVGA_CIRRUS_H__
+
+#include "emu.h"
+#include "machine/isa.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_vga_device
+
+class isa8_svga_cirrus_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_svga_cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+};
+
+
+// device type definition
+extern const device_type ISA8_SVGA_CIRRUS;
+
+#endif /* __ISA_VGA_H__ */
diff --git a/src/mess/video/isa_svga_s3.c b/src/mess/video/isa_svga_s3.c
new file mode 100644
index 00000000000..5e5b29418a9
--- /dev/null
+++ b/src/mess/video/isa_svga_s3.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+
+ ISA SVGA S3 wrapper
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_svga_s3.h"
+#include "video/pc_vga.h"
+
+ROM_START( s3_764 )
+ ROM_REGION(0x8000,"s3_764", 0)
+ ROM_LOAD("s3_764.bin", 0x00000, 0x8000, CRC(4f10aac7) SHA1(c77b3f11cc15679121314823588887dd547cd715) )
+ ROM_IGNORE( 0x8000 )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_SVGA_S3 = &device_creator<isa8_svga_s3_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_svga_s3_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_vga_isa );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_svga_s3_device::device_rom_region() const
+{
+ return ROM_NAME( s3_764 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_vga_device - constructor
+//-------------------------------------------------
+
+isa8_svga_s3_device::isa8_svga_s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_SVGA_S3, "SVGA S3 Graphics Card", tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this)
+{
+ m_shortname = "s3_764";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+static READ8_HANDLER( input_port_0_r ) { return 0xff; } //return space->machine().root_device().ioport("IN0")->read(); }
+
+void isa8_svga_s3_device::device_start()
+{
+ set_isa_device();
+
+ video_start_vga( machine() );
+
+ pc_vga_init(machine(), input_port_0_r, NULL);
+
+ int i;
+ for (i = 0; i < 0x100; i++)
+ palette_set_color_rgb(machine(), i, 0, 0, 0);
+ pc_video_start(machine());
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "s3_764");
+
+ m_isa->install_device(0x03b0, 0x03bf, 0, 0, FUNC(s3_port_03b0_r), FUNC(s3_port_03b0_w));
+ m_isa->install_device(0x03c0, 0x03cf, 0, 0, FUNC(s3_port_03c0_r), FUNC(s3_port_03c0_w));
+ m_isa->install_device(0x03d0, 0x03df, 0, 0, FUNC(s3_port_03d0_r), FUNC(s3_port_03d0_w));
+ m_isa->install_device(0x9ae8, 0x9aeb, 0, 0, FUNC(s3_port_9ae8_r), FUNC(s3_port_9ae8_w));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, FUNC(s3_mem_r), FUNC(s3_mem_w));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_svga_s3_device::device_reset()
+{
+ pc_vga_reset(machine());
+}
diff --git a/src/mess/video/isa_svga_s3.h b/src/mess/video/isa_svga_s3.h
new file mode 100644
index 00000000000..98b714ab8a2
--- /dev/null
+++ b/src/mess/video/isa_svga_s3.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#ifndef __ISA_SVGA_S3_H__
+#define __ISA_SVGA_S3_H__
+
+#include "emu.h"
+#include "machine/isa.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_vga_device
+
+class isa8_svga_s3_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_svga_s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+};
+
+
+// device type definition
+extern const device_type ISA8_SVGA_S3;
+
+#endif /* __ISA_VGA_H__ */
diff --git a/src/mess/video/isa_svga_tseng.c b/src/mess/video/isa_svga_tseng.c
new file mode 100644
index 00000000000..151bab29839
--- /dev/null
+++ b/src/mess/video/isa_svga_tseng.c
@@ -0,0 +1,91 @@
+/***************************************************************************
+
+ ISA SVGA Tseng wrapper
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_svga_tseng.h"
+#include "video/pc_vga.h"
+
+ROM_START( et4000 )
+ ROM_REGION(0x8000,"et4000", 0)
+ ROM_LOAD("et4000.bin", 0x00000, 0x8000, CRC(f1e817a8) SHA1(945d405b0fb4b8f26830d495881f8587d90e5ef9) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_SVGA_ET4K = &device_creator<isa8_svga_et4k_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_svga_et4k_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_vga_isa );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_svga_et4k_device::device_rom_region() const
+{
+ return ROM_NAME( et4000 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_vga_device - constructor
+//-------------------------------------------------
+
+isa8_svga_et4k_device::isa8_svga_et4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_SVGA_ET4K, "SVGA Tseng ET4000 Graphics Card", tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this)
+{
+ m_shortname = "et4000";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+static READ8_HANDLER( input_port_0_r ) { return 0xff; } //return space->machine().root_device().ioport("IN0")->read(); }
+
+void isa8_svga_et4k_device::device_start()
+{
+ set_isa_device();
+
+ video_start_vga( machine() );
+
+ pc_vga_init(machine(), input_port_0_r, NULL);
+
+ int i;
+ for (i = 0; i < 0x100; i++)
+ palette_set_color_rgb(machine(), i, 0, 0, 0);
+ pc_video_start(machine());
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "et4000", "et4000");
+
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, FUNC(tseng_et4k_03b0_r), FUNC(tseng_et4k_03b0_w));
+ m_isa->install_device(0x3c0, 0x3cf, 0, 0, FUNC(tseng_et4k_03c0_r), FUNC(tseng_et4k_03c0_w));
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, FUNC(tseng_et4k_03d0_r), FUNC(tseng_et4k_03d0_w));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, FUNC(tseng_mem_r), FUNC(tseng_mem_w));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_svga_et4k_device::device_reset()
+{
+ pc_vga_reset(machine());
+}
diff --git a/src/mess/video/isa_svga_tseng.h b/src/mess/video/isa_svga_tseng.h
new file mode 100644
index 00000000000..101d0c2355c
--- /dev/null
+++ b/src/mess/video/isa_svga_tseng.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#ifndef __ISA_SVGA_ET4K_H__
+#define __ISA_SVGA_ET4K_H__
+
+#include "emu.h"
+#include "machine/isa.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_vga_device
+
+class isa8_svga_et4k_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_svga_et4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+};
+
+
+// device type definition
+extern const device_type ISA8_SVGA_ET4K;
+
+#endif /* __ISA_SVGA_ET4K_H__ */
diff --git a/src/mess/video/k1ge.c b/src/mess/video/k1ge.c
new file mode 100644
index 00000000000..d06bec73bd8
--- /dev/null
+++ b/src/mess/video/k1ge.c
@@ -0,0 +1,928 @@
+/******************************************************************************
+
+K1GE/K2GE graphics emulation
+
+The K1GE graphics were used in the Neogeo pocket mono; the K2GE graphics were
+used in the Neogeo pocket color.
+
+******************************************************************************/
+
+#include "emu.h"
+#include "k1ge.h"
+
+typedef struct k1ge k1ge_t;
+struct k1ge
+{
+ const k1ge_interface *intf;
+ screen_device *screen;
+ devcb_resolved_write8 vblank_pin_w;
+ devcb_resolved_write8 hblank_pin_w;
+ UINT8 *vram;
+ UINT8 wba_h, wba_v, wsi_h, wsi_v;
+
+ void (*draw)( device_t *device, int line );
+
+ emu_timer *timer;
+ emu_timer *hblank_on_timer;
+ bitmap_ind16 *bitmap;
+};
+
+
+PALETTE_INIT( k1ge )
+{
+ int i;
+
+ for ( i = 0; i < 8; i++ )
+ {
+ int j = ( i << 5 ) | ( i << 2 ) | ( i >> 1 );
+
+ palette_set_color_rgb( machine, 7-i, j, j, j );
+ }
+}
+
+
+PALETTE_INIT( k2ge )
+{
+ int r,g,b;
+
+ for ( b = 0; b < 16; b++ )
+ {
+ for ( g = 0; g < 16; g++ )
+ {
+ for ( r = 0; r < 16; r++ )
+ {
+ palette_set_color_rgb( machine, ( b << 8 ) | ( g << 4 ) | r, ( r << 4 ) | r, ( g << 4 ) | g, ( b << 4 ) | b );
+ }
+ }
+ }
+}
+
+
+INLINE k1ge_t *get_safe_token( device_t *device )
+{
+ assert( device != NULL );
+ assert( device->type() == K1GE || device->type() == K2GE );
+
+ return ( k1ge_t *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+READ8_DEVICE_HANDLER( k1ge_r )
+{
+ k1ge_t *k1ge = get_safe_token( device );
+ UINT8 data = k1ge->vram[offset & 0x7ff];
+
+ switch( offset )
+ {
+ case 0x008: /* RAS.H */
+ data = k1ge->screen->hpos() >> 2;
+ break;
+ case 0x009: /* RAS.V */
+ data = k1ge->screen->vpos();
+ break;
+ }
+ return data;
+}
+
+
+WRITE8_DEVICE_HANDLER( k1ge_w )
+{
+ k1ge_t *k1ge = get_safe_token( device );
+
+ switch( offset )
+ {
+ case 0x000:
+ if (!k1ge->vblank_pin_w.isnull())
+ k1ge->vblank_pin_w(0, ( data & 0x80 ) ? ( ( k1ge->vram[0x010] & 0x40 ) ? 1 : 0 ) : 0 );
+ break;
+ case 0x030:
+ data &= 0x80;
+ break;
+ case 0x101: case 0x102: case 0x103:
+ case 0x105: case 0x106: case 0x107:
+ case 0x109: case 0x10a: case 0x10b:
+ case 0x10d: case 0x10e: case 0x10f:
+ case 0x111: case 0x112: case 0x113:
+ case 0x115: case 0x116: case 0x117:
+ data &= 0x07;
+ break;
+ case 0x7e2:
+ if ( k1ge->vram[0x7f0] != 0xAA )
+ return;
+ data &= 0x80;
+ break;
+ }
+
+ /* Only the lower 4 bits of the palette entry high bytes can be written */
+ if ( offset >= 0x0200 && offset < 0x0400 && ( offset & 1 ) )
+ {
+ data &= 0x0f;
+ }
+
+ k1ge->vram[offset & 0x7ff] = data;
+}
+
+
+INLINE void k1ge_draw_scroll_plane( k1ge_t *k1ge, UINT16 *p, UINT16 base, int line, int scroll_x, int scroll_y, int pal_base )
+{
+ int i;
+ int offset_x = ( scroll_x >> 3 ) * 2;
+ int px = scroll_x & 0x07;
+ UINT16 map_data;
+ UINT16 hflip;
+ UINT16 pcode;
+ UINT16 tile_addr;
+ UINT16 tile_data;
+
+ base += ( ( ( ( scroll_y + line ) >> 3 ) * 0x0040 ) & 0x7ff );
+
+ /* setup */
+ map_data = k1ge->vram[ base + offset_x ] | ( k1ge->vram[ base + offset_x + 1 ] << 8 );
+ hflip = map_data & 0x8000;
+ pcode = pal_base + ( ( map_data & 0x2000 ) ? 4 : 0 );
+ tile_addr = 0x2000 + ( ( map_data & 0x1ff ) * 16 );
+ if ( map_data & 0x4000 )
+ tile_addr += ( 7 - ( ( scroll_y + line ) & 0x07 ) ) * 2;
+ else
+ tile_addr += ( ( scroll_y + line ) & 0x07 ) * 2;
+ tile_data = k1ge->vram[ tile_addr ] | ( k1ge->vram[ tile_addr + 1 ] << 8 );
+ if ( hflip )
+ tile_data >>= 2 * ( scroll_x & 0x07 );
+ else
+ tile_data <<= 2 * ( scroll_x & 0x07 );
+
+ /* draw pixels */
+ for ( i = 0; i < 160; i++ )
+ {
+ UINT16 col;
+
+ if ( hflip )
+ {
+ col = tile_data & 0x0003;
+ tile_data >>= 2;
+ }
+ else
+ {
+ col = tile_data >> 14;
+ tile_data <<= 2;
+ }
+
+ if ( col )
+ {
+ p[ i ] = k1ge->vram[ pcode + col ];
+ }
+
+ px++;
+ if ( px >= 8 )
+ {
+ offset_x = ( offset_x + 2 ) & 0x3f;
+ map_data = k1ge->vram[ base + offset_x ] | ( k1ge->vram[ base + offset_x + 1 ] << 8 );
+ hflip = map_data & 0x8000;
+ pcode = pal_base + ( ( map_data & 0x2000 ) ? 4 : 0 );
+ tile_addr = 0x2000 + ( ( map_data & 0x1ff ) * 16 );
+ if ( map_data & 0x4000 )
+ tile_addr += ( 7 - ( ( scroll_y + line ) & 0x07 ) ) * 2;
+ else
+ tile_addr += ( ( scroll_y + line ) & 0x07 ) * 2;
+ tile_data = k1ge->vram[ tile_addr ] | ( k1ge->vram[ tile_addr + 1 ] << 8 );
+ px = 0;
+ }
+ }
+}
+
+
+INLINE void k1ge_draw_sprite_plane( k1ge_t *k1ge, UINT16 *p, UINT16 priority, int line, int scroll_x, int scroll_y )
+{
+ struct {
+ UINT16 spr_data;
+ UINT8 x;
+ UINT8 y;
+ } spr[64];
+ int num_sprites = 0;
+ UINT8 spr_y = 0;
+ UINT8 spr_x = 0;
+ int i;
+
+ priority <<= 11;
+
+ /* Select sprites */
+ for ( i = 0; i < 256; i += 4 )
+ {
+ UINT16 spr_data = k1ge->vram[ 0x800 + i ] | ( k1ge->vram[ 0x801 + i ] << 8 );
+ UINT8 x = k1ge->vram[ 0x802 + i ];
+ UINT8 y = k1ge->vram[ 0x803 + i ];
+
+ spr_x = ( spr_data & 0x0400 ) ? ( spr_x + x ) : ( scroll_x + x );
+ spr_y = ( spr_data & 0x0200 ) ? ( spr_y + y ) : ( scroll_y + y );
+
+ if ( ( spr_data & 0x1800 ) == priority )
+ {
+ if ( ( line >= spr_y || spr_y > 0xf8 ) && line < ( ( spr_y + 8 ) & 0xff ) )
+ {
+ spr[num_sprites].spr_data = spr_data;
+ spr[num_sprites].y = spr_y;
+ spr[num_sprites].x = spr_x;
+ num_sprites++;
+ }
+ }
+ }
+
+ /* Draw sprites */
+ for ( i = num_sprites-1; i >= 0; i-- )
+ {
+ int j;
+ UINT16 tile_addr;
+ UINT16 tile_data;
+ UINT16 pcode = 0x100 + ( ( spr[i].spr_data & 0x2000 ) ? 4 : 0 );
+
+ tile_addr = 0x2000 + ( ( spr[i].spr_data & 0x1ff ) * 16 );
+ if ( spr[i].spr_data & 0x4000 )
+ tile_addr += ( 7 - ( ( line - spr[i].y ) & 0x07 ) ) * 2;
+ else
+ tile_addr += ( ( line - spr[i].y ) & 0x07 ) * 2;
+ tile_data = k1ge->vram[ tile_addr ] | ( k1ge->vram[ tile_addr + 1 ] << 8 );
+
+ for ( j = 0; j < 8; j++ )
+ {
+ UINT16 col;
+
+ spr_x = spr[i].x + j;
+
+ if ( spr[i].spr_data & 0x8000 )
+ {
+ col = tile_data & 0x03;
+ tile_data >>= 2;
+ }
+ else
+ {
+ col = tile_data >> 14;
+ tile_data <<= 2;
+ }
+
+ if ( spr_x < 160 && col )
+ {
+ p[ spr_x ] = k1ge->vram[ pcode + col ];
+ }
+ }
+ }
+}
+
+
+static void k1ge_draw( device_t *device, int line )
+{
+ k1ge_t *k1ge = get_safe_token( device );
+ UINT16 *p = &k1ge->bitmap->pix16(line);
+ UINT16 oowcol = k1ge->vram[0x012] & 0x07;
+ int i;
+
+ if ( line < k1ge->wba_v || line >= k1ge->wba_v + k1ge->wsi_v )
+ {
+ for( i = 0; i < 160; i++ )
+ {
+ p[i] = oowcol;
+ }
+ }
+ else
+ {
+ UINT16 col = ( ( k1ge->vram[0x118] & 0xc0 ) == 0x80 ) ? k1ge->vram[0x118] & 0x07 : 0;
+
+ for ( i = 0; i < 160; i++ )
+ p[i] = col;
+
+ if ( k1ge->vram[0x030] & 0x80 )
+ {
+ /* Draw sprites with 01 priority */
+ k1ge_draw_sprite_plane( k1ge, p, 1, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF1 */
+ k1ge_draw_scroll_plane( k1ge, p, 0x1000, line, k1ge->vram[0x032], k1ge->vram[0x033], 0x108 );
+
+ /* Draw sprites with 10 priority */
+ k1ge_draw_sprite_plane( k1ge, p, 2, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF2 */
+ k1ge_draw_scroll_plane( k1ge, p, 0x1800, line, k1ge->vram[0x034], k1ge->vram[0x035], 0x110 );
+
+ /* Draw sprites with 11 priority */
+ k1ge_draw_sprite_plane( k1ge, p, 3, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+ }
+ else
+ {
+ /* Draw sprites with 01 priority */
+ k1ge_draw_sprite_plane( k1ge, p, 1, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF2 */
+ k1ge_draw_scroll_plane( k1ge, p, 0x1800, line, k1ge->vram[0x034], k1ge->vram[0x035], 0x110 );
+
+ /* Draw sprites with 10 priority */
+ k1ge_draw_sprite_plane( k1ge, p, 2, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF1 */
+ k1ge_draw_scroll_plane( k1ge, p, 0x1000, line, k1ge->vram[0x032], k1ge->vram[0x033], 0x108 );
+
+ /* Draw sprites with 11 priority */
+ k1ge_draw_sprite_plane( k1ge, p, 3, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+ }
+
+ for( i = 0; i < k1ge->wba_h; i++ )
+ {
+ p[i] = oowcol;
+ }
+
+ for( i = k1ge->wba_h + k1ge->wsi_h; i < 160; i++ )
+ {
+ p[i] = oowcol;
+ }
+ }
+}
+
+
+INLINE void k2ge_draw_scroll_plane( k1ge_t *k1ge, UINT16 *p, UINT16 base, int line, int scroll_x, int scroll_y, UINT16 pal_base )
+{
+ int i;
+ int offset_x = ( scroll_x >> 3 ) * 2;
+ int px = scroll_x & 0x07;
+ UINT16 map_data;
+ UINT16 hflip;
+ UINT16 pcode;
+ UINT16 tile_addr;
+ UINT16 tile_data;
+
+ base += ( ( ( ( scroll_y + line ) >> 3 ) * 0x0040 ) & 0x7ff );
+
+ /* setup */
+ map_data = k1ge->vram[ base + offset_x ] | ( k1ge->vram[ base + offset_x + 1 ] << 8 );
+ hflip = map_data & 0x8000;
+ pcode = pal_base + ( ( map_data & 0x1e00 ) >> 6 );
+ tile_addr = 0x2000 + ( ( map_data & 0x1ff ) * 16 );
+ if ( map_data & 0x4000 )
+ tile_addr += ( 7 - ( ( scroll_y + line ) & 0x07 ) ) * 2;
+ else
+ tile_addr += ( ( scroll_y + line ) & 0x07 ) * 2;
+ tile_data = k1ge->vram[ tile_addr ] | ( k1ge->vram[ tile_addr + 1 ] << 8 );
+ if ( hflip )
+ tile_data >>= 2 * ( scroll_x & 0x07 );
+ else
+ tile_data <<= 2 * ( scroll_x & 0x07 );
+
+ /* draw pixels */
+ for ( i = 0; i < 160; i++ )
+ {
+ UINT16 col;
+
+ if ( hflip )
+ {
+ col = tile_data & 0x0003;
+ tile_data >>= 2;
+ }
+ else
+ {
+ col = tile_data >> 14;
+ tile_data <<= 2;
+ }
+
+ if ( col )
+ {
+ p[ i ] = k1ge->vram[ pcode + col * 2 ] | ( k1ge->vram[ pcode + col * 2 + 1 ] << 8 );
+ }
+
+ px++;
+ if ( px >= 8 )
+ {
+ offset_x = ( offset_x + 2 ) & 0x3f;
+ map_data = k1ge->vram[ base + offset_x ] | ( k1ge->vram[ base + offset_x + 1 ] << 8 );
+ hflip = map_data & 0x8000;
+ pcode = pal_base + ( ( map_data & 0x1e00 ) >> 6 );
+ tile_addr = 0x2000 + ( ( map_data & 0x1ff ) * 16 );
+ if ( map_data & 0x4000 )
+ tile_addr += ( 7 - ( ( scroll_y + line ) & 0x07 ) ) * 2;
+ else
+ tile_addr += ( ( scroll_y + line ) & 0x07 ) * 2;
+ tile_data = k1ge->vram[ tile_addr ] | ( k1ge->vram[ tile_addr + 1 ] << 8 );
+ px = 0;
+ }
+ }
+}
+
+
+INLINE void k2ge_draw_sprite_plane( k1ge_t *k1ge, UINT16 *p, UINT16 priority, int line, int scroll_x, int scroll_y )
+{
+ struct {
+ UINT16 spr_data;
+ UINT8 x;
+ UINT8 y;
+ UINT8 index;
+ } spr[64];
+ int num_sprites = 0;
+ UINT8 spr_y = 0;
+ UINT8 spr_x = 0;
+ int i;
+
+ priority <<= 11;
+
+ /* Select sprites */
+ for ( i = 0; i < 256; i += 4 )
+ {
+ UINT16 spr_data = k1ge->vram[ 0x800 + i ] | ( k1ge->vram[ 0x801 + i ] << 8 );
+ UINT8 x = k1ge->vram[ 0x802 + i ];
+ UINT8 y = k1ge->vram[ 0x803 + i ];
+
+ spr_x = ( spr_data & 0x0400 ) ? ( spr_x + x ) : ( scroll_x + x );
+ spr_y = ( spr_data & 0x0200 ) ? ( spr_y + y ) : ( scroll_y + y );
+
+ if ( ( spr_data & 0x1800 ) == priority )
+ {
+ if ( ( line >= spr_y || spr_y > 0xf8 ) && line < ( ( spr_y + 8 ) & 0xff ) )
+ {
+ spr[num_sprites].spr_data = spr_data;
+ spr[num_sprites].y = spr_y;
+ spr[num_sprites].x = spr_x;
+ spr[num_sprites].index = i >> 2;
+ num_sprites++;
+ }
+ }
+ }
+
+ /* Draw sprites */
+ for ( i = num_sprites-1; i >= 0; i-- )
+ {
+ int j;
+ UINT16 tile_addr;
+ UINT16 tile_data;
+ UINT16 pcode = 0x0200 + ( ( k1ge->vram[0x0c00 + spr[i].index ] & 0x0f ) << 3 );
+
+ tile_addr = 0x2000 + ( ( spr[i].spr_data & 0x1ff ) * 16 );
+ if ( spr[i].spr_data & 0x4000 )
+ tile_addr += ( 7 - ( ( line - spr[i].y ) & 0x07 ) ) * 2;
+ else
+ tile_addr += ( ( line - spr[i].y ) & 0x07 ) * 2;
+ tile_data = k1ge->vram[ tile_addr ] | ( k1ge->vram[ tile_addr + 1 ] << 8 );
+
+ for ( j = 0; j < 8; j++ )
+ {
+ UINT16 col;
+
+ spr_x = spr[i].x + j;
+
+ if ( spr[i].spr_data & 0x8000 )
+ {
+ col = tile_data & 0x03;
+ tile_data >>= 2;
+ }
+ else
+ {
+ col = tile_data >> 14;
+ tile_data <<= 2;
+ }
+
+ if ( spr_x < 160 && col )
+ {
+ p[ spr_x ] = k1ge->vram[ pcode + col * 2 ] | ( k1ge->vram[ pcode + col * 2 + 1 ] << 8 );
+ }
+ }
+ }
+}
+
+
+INLINE void k2ge_k1ge_draw_scroll_plane( k1ge_t *k1ge, UINT16 *p, UINT16 base, int line, int scroll_x, int scroll_y, UINT16 pal_lut_base, UINT16 k2ge_lut_base )
+{
+ int i;
+ int offset_x = ( scroll_x >> 3 ) * 2;
+ int px = scroll_x & 0x07;
+ UINT16 map_data;
+ UINT16 hflip;
+ UINT16 pcode;
+ UINT16 tile_addr;
+ UINT16 tile_data;
+
+ base += ( ( ( ( scroll_y + line ) >> 3 ) * 0x0040 ) & 0x7ff );
+
+ /* setup */
+ map_data = k1ge->vram[ base + offset_x ] | ( k1ge->vram[ base + offset_x + 1 ] << 8 );
+ hflip = map_data & 0x8000;
+ pcode = ( map_data & 0x2000 ) ? 1 : 0;
+ tile_addr = 0x2000 + ( ( map_data & 0x1ff ) * 16 );
+ if ( map_data & 0x4000 )
+ tile_addr += ( 7 - ( ( scroll_y + line ) & 0x07 ) ) * 2;
+ else
+ tile_addr += ( ( scroll_y + line ) & 0x07 ) * 2;
+ tile_data = k1ge->vram[ tile_addr ] | ( k1ge->vram[ tile_addr + 1 ] << 8 );
+ if ( hflip )
+ tile_data >>= 2 * ( scroll_x & 0x07 );
+ else
+ tile_data <<= 2 * ( scroll_x & 0x07 );
+
+ /* draw pixels */
+ for ( i = 0; i < 160; i++ )
+ {
+ UINT16 col;
+
+ if ( hflip )
+ {
+ col = tile_data & 0x0003;
+ tile_data >>= 2;
+ }
+ else
+ {
+ col = tile_data >> 14;
+ tile_data <<= 2;
+ }
+
+ if ( col )
+ {
+ UINT16 col2 = 16 * pcode + ( k1ge->vram[ pal_lut_base + 4 * pcode + col ] * 2 );
+ p[ i ] = k1ge->vram[ k2ge_lut_base + col2 ] | ( k1ge->vram[ k2ge_lut_base + col2 + 1 ] << 8 );
+ }
+
+ px++;
+ if ( px >= 8 )
+ {
+ offset_x = ( offset_x + 2 ) & 0x3f;
+ map_data = k1ge->vram[ base + offset_x ] | ( k1ge->vram[ base + offset_x + 1 ] << 8 );
+ hflip = map_data & 0x8000;
+ pcode = ( map_data & 0x2000 ) ? 1 : 0;
+ tile_addr = 0x2000 + ( ( map_data & 0x1ff ) * 16 );
+ if ( map_data & 0x4000 )
+ tile_addr += ( 7 - ( ( scroll_y + line ) & 0x07 ) ) * 2;
+ else
+ tile_addr += ( ( scroll_y + line ) & 0x07 ) * 2;
+ tile_data = k1ge->vram[ tile_addr ] | ( k1ge->vram[ tile_addr + 1 ] << 8 );
+ px = 0;
+ }
+ }
+}
+
+
+INLINE void k2ge_k1ge_draw_sprite_plane( k1ge_t *k1ge, UINT16 *p, UINT16 priority, int line, int scroll_x, int scroll_y )
+{
+ struct {
+ UINT16 spr_data;
+ UINT8 x;
+ UINT8 y;
+ } spr[64];
+ int num_sprites = 0;
+ UINT8 spr_y = 0;
+ UINT8 spr_x = 0;
+ int i;
+
+ priority <<= 11;
+
+ /* Select sprites */
+ for ( i = 0; i < 256; i += 4 )
+ {
+ UINT16 spr_data = k1ge->vram[ 0x800 + i ] | ( k1ge->vram[ 0x801 + i ] << 8 );
+ UINT8 x = k1ge->vram[ 0x802 + i ];
+ UINT8 y = k1ge->vram[ 0x803 + i ];
+
+ spr_x = ( spr_data & 0x0400 ) ? ( spr_x + x ) : ( scroll_x + x );
+ spr_y = ( spr_data & 0x0200 ) ? ( spr_y + y ) : ( scroll_y + y );
+
+ if ( ( spr_data & 0x1800 ) == priority )
+ {
+ if ( ( line >= spr_y || spr_y > 0xf8 ) && line < ( ( spr_y + 8 ) & 0xff ) )
+ {
+ spr[num_sprites].spr_data = spr_data;
+ spr[num_sprites].y = spr_y;
+ spr[num_sprites].x = spr_x;
+ num_sprites++;
+ }
+ }
+ }
+
+ /* Draw sprites */
+ for ( i = num_sprites-1; i >= 0; i-- )
+ {
+ int j;
+ UINT16 tile_addr;
+ UINT16 tile_data;
+ UINT16 pcode = ( spr[i].spr_data & 0x2000 ) ? 1 : 0;
+
+ tile_addr = 0x2000 + ( ( spr[i].spr_data & 0x1ff ) * 16 );
+ if ( spr[i].spr_data & 0x4000 )
+ tile_addr += ( 7 - ( ( line - spr[i].y ) & 0x07 ) ) * 2;
+ else
+ tile_addr += ( ( line - spr[i].y ) & 0x07 ) * 2;
+ tile_data = k1ge->vram[ tile_addr ] | ( k1ge->vram[ tile_addr + 1 ] << 8 );
+
+ for ( j = 0; j < 8; j++ )
+ {
+ UINT16 col;
+
+ spr_x = spr[i].x + j;
+
+ if ( spr[i].spr_data & 0x8000 )
+ {
+ col = tile_data & 0x03;
+ tile_data >>= 2;
+ }
+ else
+ {
+ col = tile_data >> 14;
+ tile_data <<= 2;
+ }
+
+ if ( spr_x < 160 && col )
+ {
+ UINT16 col2 = 16 * pcode + k1ge->vram[ 0x100 + 4 * pcode + col ] * 2;
+ p[ spr_x ] = k1ge->vram[ 0x380 + col2 ] | ( k1ge->vram[ 0x381 + col2 ] << 8 );
+ }
+ }
+ }
+}
+
+
+static void k2ge_draw( device_t *device, int line )
+{
+ k1ge_t *k1ge = get_safe_token( device );
+ UINT16 *p = &k1ge->bitmap->pix16(line);
+ UINT16 col = 0;
+ UINT16 oowcol;
+ int i;
+
+ oowcol = ( k1ge->vram[0x012] & 0x07 ) * 2;
+ oowcol = k1ge->vram[0x3f0 + oowcol ] | ( k1ge->vram[0x3f1 + oowcol ] << 8 );
+
+ if ( line < k1ge->wba_v || line >= k1ge->wba_v + k1ge->wsi_v )
+ {
+ for( i = 0; i < 160; i++ )
+ {
+ p[i] = oowcol;
+ }
+ }
+ else
+ {
+ /* Determine the background color */
+ if ( ( k1ge->vram[0x118] & 0xc0 ) == 0x80 )
+ {
+ col = ( k1ge->vram[0x118] & 0x07 ) * 2;
+ }
+ col = k1ge->vram[0x3e0 + col ] | ( k1ge->vram[0x3e1 + col ] << 8 );
+
+ /* Set the bacground color */
+ for ( i = 0; i < 160; i++ )
+ {
+ p[i] = col;
+ }
+
+ if ( k1ge->vram[0x7e2] & 0x80 )
+ {
+ /* K1GE compatibility mode */
+ if ( k1ge->vram[0x030] & 0x80 )
+ {
+ /* Draw sprites with 01 priority */
+ k2ge_k1ge_draw_sprite_plane( k1ge, p, 1, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF1 */
+ k2ge_k1ge_draw_scroll_plane( k1ge, p, 0x1000, line, k1ge->vram[0x032], k1ge->vram[0x033], 0x108, 0x3a0 );
+
+ /* Draw sprites with 10 priority */
+ k2ge_k1ge_draw_sprite_plane( k1ge, p, 2, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF2 */
+ k2ge_k1ge_draw_scroll_plane( k1ge, p, 0x1800, line, k1ge->vram[0x034], k1ge->vram[0x035], 0x110, 0x3c0 );
+
+ /* Draw sprites with 11 priority */
+ k2ge_k1ge_draw_sprite_plane( k1ge, p, 3, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+ }
+ else
+ {
+ /* Draw sprites with 01 priority */
+ k2ge_k1ge_draw_sprite_plane( k1ge, p, 1, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF2 */
+ k2ge_k1ge_draw_scroll_plane( k1ge, p, 0x1800, line, k1ge->vram[0x034], k1ge->vram[0x035], 0x110, 0x3c0 );
+
+ /* Draw sprites with 10 priority */
+ k2ge_k1ge_draw_sprite_plane( k1ge, p, 2, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF1 */
+ k2ge_k1ge_draw_scroll_plane( k1ge, p, 0x1000, line, k1ge->vram[0x032], k1ge->vram[0x033], 0x108, 0x3a0 );
+
+ /* Draw sprites with 11 priority */
+ k2ge_k1ge_draw_sprite_plane( k1ge, p, 3, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+ }
+ }
+ else
+ {
+ /* K2GE mode */
+ if ( k1ge->vram[0x030] & 0x80 )
+ {
+ /* Draw sprites with 01 priority */
+ k2ge_draw_sprite_plane( k1ge, p, 1, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF1 */
+ k2ge_draw_scroll_plane( k1ge, p, 0x1000, line, k1ge->vram[0x032], k1ge->vram[0x033], 0x280 );
+
+ /* Draw sprites with 10 priority */
+ k2ge_draw_sprite_plane( k1ge, p, 2, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF2 */
+ k2ge_draw_scroll_plane( k1ge, p, 0x1800, line, k1ge->vram[0x034], k1ge->vram[0x035], 0x300 );
+
+ /* Draw sprites with 11 priority */
+ k2ge_draw_sprite_plane( k1ge, p, 3, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+ }
+ else
+ {
+ /* Draw sprites with 01 priority */
+ k2ge_draw_sprite_plane( k1ge, p, 1, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF2 */
+ k2ge_draw_scroll_plane( k1ge, p, 0x1800, line, k1ge->vram[0x034], k1ge->vram[0x035], 0x300 );
+
+ /* Draw sprites with 10 priority */
+ k2ge_draw_sprite_plane( k1ge, p, 2, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+
+ /* Draw PF1 */
+ k2ge_draw_scroll_plane( k1ge, p, 0x1000, line, k1ge->vram[0x032], k1ge->vram[0x033], 0x280 );
+
+ /* Draw sprites with 11 priority */
+ k2ge_draw_sprite_plane( k1ge, p, 3, line, k1ge->vram[0x020], k1ge->vram[0x021] );
+ }
+ }
+
+ for ( i = 0; i < k1ge->wba_h; i++ )
+ {
+ p[i] = oowcol;
+ }
+
+ for ( i = k1ge->wba_h + k1ge->wsi_h; i < 160; i++ )
+ {
+ p[i] = oowcol;
+ }
+ }
+}
+
+
+static TIMER_CALLBACK( k1ge_hblank_on_timer_callback )
+{
+ device_t *device = (device_t *)ptr;
+ k1ge_t *k1ge = get_safe_token( device );
+
+ if (!k1ge->hblank_pin_w.isnull())
+ k1ge->hblank_pin_w(0, 0);
+}
+
+
+static TIMER_CALLBACK( k1ge_timer_callback )
+{
+ device_t *device = (device_t *)ptr;
+ k1ge_t *k1ge = get_safe_token( device );
+ int y = k1ge->screen->vpos();
+
+ /* Check for start of VBlank */
+ if ( y >= 152 )
+ {
+ k1ge->vram[0x010] |= 0x40;
+ if ((k1ge->vram[0x000] & 0x80 ) && !k1ge->vblank_pin_w.isnull())
+ k1ge->vblank_pin_w(0, 1);
+ }
+
+ /* Check for end of VBlank */
+ if ( y == 0 )
+ {
+ k1ge->wba_h = k1ge->vram[0x002];
+ k1ge->wba_v = k1ge->vram[0x003];
+ k1ge->wsi_h = k1ge->vram[0x004];
+ k1ge->wsi_v = k1ge->vram[0x005];
+ k1ge->vram[0x010] &= ~ 0x40;
+ if ((k1ge->vram[0x000] & 0x80 ) && !k1ge->vblank_pin_w.isnull())
+ k1ge->vblank_pin_w(0, 0);
+ }
+
+ /* Check if Hint should be triggered */
+ if ( y == K1GE_SCREEN_HEIGHT - 1 || y < 151 )
+ {
+ if (!k1ge->hblank_pin_w.isnull())
+ {
+ if ( k1ge->vram[0x000] & 0x40 )
+ k1ge->hblank_pin_w(0, 1);
+ k1ge->hblank_on_timer->adjust( k1ge->screen->time_until_pos(y, 480 ) );
+ }
+ }
+
+ /* Draw a line when inside visible area */
+ if ( y && y < 153 )
+ {
+ k1ge->draw( device, y - 1 );
+ }
+
+ k1ge->timer->adjust( k1ge->screen->time_until_pos(( y + 1 ) % K1GE_SCREEN_HEIGHT, 0 ) );
+}
+
+
+void k1ge_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect )
+{
+ k1ge_t *k1ge = get_safe_token( device );
+
+ copybitmap( bitmap, *k1ge->bitmap, 0, 0, 0, 0, cliprect );
+}
+
+
+static DEVICE_START( k1ge )
+{
+ k1ge_t *k1ge = get_safe_token( device );
+
+ k1ge->intf = (const k1ge_interface*)device->static_config();
+
+ k1ge->vblank_pin_w.resolve(k1ge->intf->vblank_pin_w, *device);
+ k1ge->hblank_pin_w.resolve(k1ge->intf->hblank_pin_w, *device);
+
+ k1ge->timer = device->machine().scheduler().timer_alloc(FUNC(k1ge_timer_callback), (void *) device );
+ k1ge->hblank_on_timer = device->machine().scheduler().timer_alloc(FUNC(k1ge_hblank_on_timer_callback), (void *) device );
+ k1ge->screen = device->machine().device<screen_device>(k1ge->intf->screen_tag);
+ k1ge->vram = device->machine().root_device().memregion( k1ge->intf->vram_tag )->base();
+ k1ge->bitmap = auto_bitmap_ind16_alloc( device->machine(), k1ge->screen->width(), k1ge->screen->height() );
+ k1ge->draw = k1ge_draw;
+}
+
+
+static DEVICE_START( k2ge )
+{
+ k1ge_t *k1ge = get_safe_token( device );
+
+ DEVICE_START_CALL( k1ge );
+ k1ge->draw = k2ge_draw;
+}
+
+
+static DEVICE_RESET( k1ge )
+{
+ k1ge_t *k1ge = get_safe_token( device );
+
+ k1ge->vram[0x000] = 0x00; /* Interrupt enable */
+ k1ge->vram[0x002] = 0x00; /* WBA.H */
+ k1ge->vram[0x003] = 0x00; /* WVA.V */
+ k1ge->vram[0x004] = 0xFF; /* WSI.H */
+ k1ge->vram[0x005] = 0xFF; /* WSI.V */
+ k1ge->vram[0x007] = 0xc6; /* REF */
+ k1ge->vram[0x012] = 0x00; /* 2D control */
+ k1ge->vram[0x020] = 0x00; /* PO.H */
+ k1ge->vram[0x021] = 0x00; /* PO.V */
+ k1ge->vram[0x030] = 0x00; /* PF */
+ k1ge->vram[0x032] = 0x00; /* S1SO.H */
+ k1ge->vram[0x033] = 0x00; /* S1SO.V */
+ k1ge->vram[0x034] = 0x00; /* S2SO.H */
+ k1ge->vram[0x035] = 0x00; /* S2SO.V */
+ k1ge->vram[0x101] = 0x07; /* SPPLT01 */
+ k1ge->vram[0x102] = 0x07; /* SPPLT02 */
+ k1ge->vram[0x103] = 0x07; /* SPPLT03 */
+ k1ge->vram[0x105] = 0x07; /* SPPLT11 */
+ k1ge->vram[0x106] = 0x07; /* SPPLT12 */
+ k1ge->vram[0x107] = 0x07; /* SPPLT13 */
+ k1ge->vram[0x109] = 0x07; /* SC1PLT01 */
+ k1ge->vram[0x10a] = 0x07; /* SC1PLT02 */
+ k1ge->vram[0x10b] = 0x07; /* SC1PLT03 */
+ k1ge->vram[0x10d] = 0x07; /* SC1PLT11 */
+ k1ge->vram[0x10e] = 0x07; /* SC1PLT12 */
+ k1ge->vram[0x10f] = 0x07; /* SC1PLT13 */
+ k1ge->vram[0x111] = 0x07; /* SC2PLT01 */
+ k1ge->vram[0x112] = 0x07; /* SC2PLT02 */
+ k1ge->vram[0x113] = 0x07; /* SC2PLT03 */
+ k1ge->vram[0x115] = 0x07; /* SC2PLT11 */
+ k1ge->vram[0x116] = 0x07; /* SC2PLT12 */
+ k1ge->vram[0x117] = 0x07; /* SC2PLT13 */
+ k1ge->vram[0x118] = 0x07; /* BG */
+ k1ge->vram[0x400] = 0xFF; /* LED control */
+ k1ge->vram[0x402] = 0x80; /* LEDFREG */
+ k1ge->vram[0x7e0] = 0x52; /* RESET */
+ k1ge->vram[0x7e2] = 0x00; /* MODE */
+
+ k1ge->timer->adjust( k1ge->screen->time_until_pos(( k1ge->screen->vpos() + 1 ) % K1GE_SCREEN_HEIGHT, 0 ) );
+}
+
+
+DEVICE_GET_INFO( k1ge )
+{
+ switch ( state )
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof( k1ge_t ); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( k1ge ); break;
+ case DEVINFO_FCT_STOP: break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( k1ge ); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy( info->s, "SNK K1GE" ); break;
+ case DEVINFO_STR_FAMILY: strcpy( info->s, "KxGE" ); break;
+ case DEVINFO_STR_VERSION: strcpy( info->s, "1.0" ); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy( info->s, __FILE__ );
+ case DEVINFO_STR_CREDITS: strcpy( info->s, "Copyright the MESS team" ); break;
+ }
+}
+
+
+DEVICE_GET_INFO( k2ge )
+{
+ switch ( state )
+ {
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( k2ge ); break;
+ default: DEVICE_GET_INFO_CALL( k1ge ); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(K1GE, k1ge);
+DEFINE_LEGACY_DEVICE(K2GE, k2ge);
diff --git a/src/mess/video/k1ge.h b/src/mess/video/k1ge.h
new file mode 100644
index 00000000000..26446f6f0cf
--- /dev/null
+++ b/src/mess/video/k1ge.h
@@ -0,0 +1,44 @@
+
+#ifndef __K2GE_H_
+#define __K2GE_H_
+
+#include "devcb.h"
+
+
+#define K1GE_SCREEN_HEIGHT 199
+
+
+DECLARE_LEGACY_DEVICE(K1GE, k1ge);
+DECLARE_LEGACY_DEVICE(K2GE, k2ge);
+
+
+#define MCFG_K1GE_ADD(_tag, _clock, _config ) \
+ MCFG_DEVICE_ADD( _tag, K1GE, _clock ) \
+ MCFG_DEVICE_CONFIG( _config )
+
+
+#define MCFG_K2GE_ADD(_tag, _clock, _config ) \
+ MCFG_DEVICE_ADD( _tag, K2GE, _clock ) \
+ MCFG_DEVICE_CONFIG( _config )
+
+
+typedef struct _k1ge_interface k1ge_interface;
+struct _k1ge_interface
+{
+ const char *screen_tag; /* screen we are drawing on */
+ const char *vram_tag; /* memory region we will use for video ram */
+ devcb_write8 vblank_pin_w; /* called back when VBlank pin may have changed */
+ devcb_write8 hblank_pin_w; /* called back when HBlank pin may have changed */
+};
+
+
+PALETTE_INIT( k1ge );
+PALETTE_INIT( k2ge );
+
+WRITE8_DEVICE_HANDLER( k1ge_w );
+READ8_DEVICE_HANDLER( k1ge_r );
+
+void k1ge_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect );
+
+#endif
+
diff --git a/src/mess/video/kaypro.c b/src/mess/video/kaypro.c
new file mode 100644
index 00000000000..39fd7e866eb
--- /dev/null
+++ b/src/mess/video/kaypro.c
@@ -0,0 +1,320 @@
+
+#include "includes/kaypro.h"
+
+
+
+/***********************************************************
+
+ Video
+
+************************************************************/
+
+PALETTE_INIT( kaypro )
+{
+ palette_set_color(machine, 0, RGB_BLACK); /* black */
+ palette_set_color(machine, 1, MAKE_RGB(0, 220, 0)); /* green */
+ palette_set_color(machine, 2, MAKE_RGB(0, 110, 0)); /* low intensity green */
+}
+
+SCREEN_UPDATE_IND16( kayproii )
+{
+ kaypro_state *state = screen.machine().driver_data<kaypro_state>();
+/* The display consists of 80 columns and 24 rows. Each row is allocated 128 bytes of ram,
+ but only the first 80 are used. The total video ram therefore is 0x0c00 bytes.
+ There is one video attribute: bit 7 causes blinking. The first half of the
+ character generator is blank, with the visible characters in the 2nd half.
+ During the "off" period of blanking, the first half is used. Only 5 pixels are
+ connected from the rom to the shift register, the remaining pixels are held high. */
+
+ UINT8 y,ra,chr,gfx;
+ UINT16 sy=0,ma=0,x;
+
+ state->m_framecnt++;
+
+ for (y = 0; y < 24; y++)
+ {
+ for (ra = 0; ra < 10; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 80; x++)
+ {
+ gfx = 0;
+
+ if (ra < 8)
+ {
+ chr = state->m_p_videoram[x]^0x80;
+
+ /* Take care of flashing characters */
+ if ((chr < 0x80) && (state->m_framecnt & 0x08))
+ chr |= 0x80;
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[(chr<<3) | ra ];
+ }
+
+ /* Display a scanline of a character (7 pixels) */
+ *p++ = 0;
+ *p++ = BIT( gfx, 4 );
+ *p++ = BIT( gfx, 3 );
+ *p++ = BIT( gfx, 2 );
+ *p++ = BIT( gfx, 1 );
+ *p++ = BIT( gfx, 0 );
+ *p++ = 0;
+ }
+ }
+ ma+=128;
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( omni2 )
+{
+ kaypro_state *state = screen.machine().driver_data<kaypro_state>();
+ UINT8 y,ra,chr,gfx;
+ UINT16 sy=0,ma=0,x;
+
+ state->m_framecnt++;
+
+ for (y = 0; y < 24; y++)
+ {
+ for (ra = 0; ra < 10; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 80; x++)
+ {
+ gfx = 0;
+
+ if (ra < 8)
+ {
+ chr = state->m_p_videoram[x];
+
+ /* Take care of flashing characters */
+ if ((chr > 0x7f) && (state->m_framecnt & 0x08))
+ chr |= 0x80;
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[(chr<<3) | ra ];
+ }
+
+ /* Display a scanline of a character (7 pixels) */
+ *p++ = BIT( gfx, 6 );
+ *p++ = BIT( gfx, 5 );
+ *p++ = BIT( gfx, 4 );
+ *p++ = BIT( gfx, 3 );
+ *p++ = BIT( gfx, 2 );
+ *p++ = BIT( gfx, 1 );
+ *p++ = BIT( gfx, 0 );
+ }
+ }
+ ma+=128;
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_RGB32( kaypro2x )
+{
+ kaypro_state *state = screen.machine().driver_data<kaypro_state>();
+ state->m_framecnt++;
+ state->m_speed = state->m_mc6845_reg[10]&0x20;
+ state->m_flash = state->m_mc6845_reg[10]&0x40; // cursor modes
+ state->m_cursor = (state->m_mc6845_reg[14]<<8) | state->m_mc6845_reg[15]; // get cursor position
+ state->m_crtc->screen_update(screen, bitmap, cliprect);
+ return 0;
+}
+
+/* bit 6 of kaypro2x_system_port selects alternate characters (A12 on character generator rom).
+ The diagram specifies a 2732 with 28 pins, and more address pins. Possibly a 2764 or 27128.
+ Since our dump only goes up to A11, the alternate character set doesn't exist.
+
+ 0000-07FF of videoram is memory-mapped characters; 0800-0FFF is equivalent attribute bytes.
+ d3 Underline
+ d2 blinking (at unknown rate)
+ d1 low intensity
+ d0 reverse video
+
+ Not sure how the attributes interact, for example does an underline blink? */
+
+
+MC6845_UPDATE_ROW( kaypro2x_update_row )
+{
+ kaypro_state *state = device->machine().driver_data<kaypro_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT16 x;
+ UINT8 gfx,fg,bg;
+
+ for (x = 0; x < x_count; x++) // for each character
+ {
+ UINT8 inv=0;
+ // if (x == cursor_x) inv=0xff; /* uncomment when mame fixed */
+ UINT16 mem = (ma + x) & 0x7ff;
+ UINT8 chr = state->m_p_videoram[mem];
+ UINT8 attr = state->m_p_videoram[mem | 0x800];
+
+ if ((attr & 3) == 3)
+ {
+ fg = 0;
+ bg = 2;
+ }
+ else
+ if ((attr & 3) == 2)
+ {
+ fg = 2;
+ bg = 0;
+ }
+ else
+ if ((attr & 3) == 1)
+ {
+ fg = 0;
+ bg = 1;
+ }
+ else
+ {
+ fg = 1;
+ bg = 0;
+ }
+
+ /* Take care of flashing characters */
+ if ( (BIT(attr, 2)) & (BIT(state->m_framecnt, 3)) )
+ fg = bg;
+
+ /* process cursor - remove when mame fixed */
+ if ((((!state->m_flash) && (!state->m_speed)) ||
+ ((state->m_flash) && (state->m_speed) && (state->m_framecnt & 0x10)) ||
+ ((state->m_flash) && (!state->m_speed) && (state->m_framecnt & 8))) &&
+ (mem == state->m_cursor))
+ inv ^= state->m_mc6845_cursor[ra];
+
+ /* get pattern of pixels for that character scanline */
+ if ( (ra == 15) & (BIT(attr, 3)) ) /* underline */
+ gfx = 0xff;
+ else
+ gfx = state->m_p_chargen[(chr<<4) | ra ] ^ inv;
+
+ /* Display a scanline of a character (8 pixels) */
+ *p++ = palette[BIT( gfx, 7 ) ? fg : bg];
+ *p++ = palette[BIT( gfx, 6 ) ? fg : bg];
+ *p++ = palette[BIT( gfx, 5 ) ? fg : bg];
+ *p++ = palette[BIT( gfx, 4 ) ? fg : bg];
+ *p++ = palette[BIT( gfx, 3 ) ? fg : bg];
+ *p++ = palette[BIT( gfx, 2 ) ? fg : bg];
+ *p++ = palette[BIT( gfx, 1 ) ? fg : bg];
+ *p++ = palette[BIT( gfx, 0 ) ? fg : bg];
+ }
+}
+
+/************************************* MC6845 SUPPORT ROUTINES ***************************************/
+
+/* The 6845 can produce a variety of cursor shapes - all are emulated here - remove when mame fixed */
+void kaypro_state::mc6845_cursor_configure()
+{
+ UINT8 i,curs_type=0,r9,r10,r11;
+
+ /* curs_type holds the general cursor shape to be created
+ 0 = no cursor
+ 1 = partial cursor (only shows on a block of scan lines)
+ 2 = full cursor
+ 3 = two-part cursor (has a part at the top and bottom with the middle blank) */
+
+ for ( i = 0; i < ARRAY_LENGTH(m_mc6845_cursor); i++) m_mc6845_cursor[i] = 0; // prepare cursor by erasing old one
+
+ r9 = m_mc6845_reg[9]; // number of scan lines - 1
+ r10 = m_mc6845_reg[10] & 0x1f; // cursor start line = last 5 bits
+ r11 = m_mc6845_reg[11]+1; // cursor end line incremented to suit for-loops below
+
+ /* decide the curs_type by examining the registers */
+ if (r10 < r11) curs_type=1; // start less than end, show start to end
+ else
+ if (r10 == r11) curs_type=2; // if equal, show full cursor
+ else curs_type=3; // if start greater than end, it's a two-part cursor
+
+ if ((r11 - 1) > r9) curs_type=2; // if end greater than scan-lines, show full cursor
+ if (r10 > r9) curs_type=0; // if start greater than scan-lines, then no cursor
+ if (r11 > 16) r11=16; // truncate 5-bit register to fit our 4-bit hardware
+
+ /* create the new cursor */
+ if (curs_type > 1) for (i = 0;i < ARRAY_LENGTH(m_mc6845_cursor);i++) m_mc6845_cursor[i]=0xff; // turn on full cursor
+
+ if (curs_type == 1) for (i = r10;i < r11;i++) m_mc6845_cursor[i]=0xff; // for each line that should show, turn on that scan line
+
+ if (curs_type == 3) for (i = r11; i < r10;i++) m_mc6845_cursor[i]=0; // now take a bite out of the middle
+}
+
+/* Resize the screen within the limits of the hardware. Expand the image to fill the screen area.
+ Standard screen is 640 x 400 = 0x7d0 bytes. */
+
+void kaypro_state::mc6845_screen_configure()
+{
+ UINT16 width = m_mc6845_reg[1]*8-1; // width in pixels
+ UINT16 height = m_mc6845_reg[6]*(m_mc6845_reg[9]+1)-1; // height in pixels
+ UINT16 bytes = m_mc6845_reg[1]*m_mc6845_reg[6]-1; // video ram needed -1
+
+ /* Resize the screen */
+ if ((width < 640) && (height < 400) && (bytes < 0x800)) /* bounds checking to prevent an assert or violation */
+ machine().primary_screen->set_visible_area(0, width, 0, height);
+}
+
+
+/**************************** I/O PORTS *****************************************************************/
+
+READ8_MEMBER( kaypro_state::kaypro2x_status_r )
+{
+/* Need bit 7 high or computer hangs */
+
+ return 0x80 | m_crtc->register_r(space, 0);
+}
+
+WRITE8_MEMBER( kaypro_state::kaypro2x_index_w )
+{
+ m_mc6845_ind = data & 0x1f;
+ m_crtc->address_w( space, 0, data );
+}
+
+WRITE8_MEMBER( kaypro_state::kaypro2x_register_w )
+{
+ static const UINT8 mcmask[32]={0xff,0xff,0xff,0x0f,0x7f,0x1f,0x7f,0x7f,3,0x1f,0x7f,0x1f,0x3f,0xff,0x3f,0xff,0,0};
+
+ if (m_mc6845_ind < 16)
+ m_mc6845_reg[m_mc6845_ind] = data & mcmask[m_mc6845_ind]; /* save data in register */
+ else
+ m_mc6845_reg[m_mc6845_ind] = data;
+
+ m_crtc->register_w( space, 0, data );
+
+ if ((m_mc6845_ind == 1) || (m_mc6845_ind == 6) || (m_mc6845_ind == 9))
+ mc6845_screen_configure(); /* adjust screen size */
+
+ if ((m_mc6845_ind > 8) && (m_mc6845_ind < 12))
+ mc6845_cursor_configure(); /* adjust cursor shape - remove when mame fixed */
+
+ if ((m_mc6845_ind > 17) && (m_mc6845_ind < 20))
+ m_mc6845_video_address = m_mc6845_reg[19] | ((m_mc6845_reg[18] & 0x3f) << 8); /* internal ULA address */
+}
+
+READ8_MEMBER( kaypro_state::kaypro_videoram_r )
+{
+ return m_p_videoram[offset];
+}
+
+WRITE8_MEMBER( kaypro_state::kaypro_videoram_w )
+{
+ m_p_videoram[offset] = data;
+}
+
+READ8_MEMBER( kaypro_state::kaypro2x_videoram_r )
+{
+ return m_p_videoram[m_mc6845_video_address];
+}
+
+WRITE8_MEMBER( kaypro_state::kaypro2x_videoram_w )
+{
+ m_p_videoram[m_mc6845_video_address] = data;
+}
+
+VIDEO_START( kaypro )
+{
+ kaypro_state *state = machine.driver_data<kaypro_state>();
+ state->m_p_chargen = state->memregion("chargen")->base();
+}
diff --git a/src/mess/video/kc.c b/src/mess/video/kc.c
new file mode 100644
index 00000000000..1802f123920
--- /dev/null
+++ b/src/mess/video/kc.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+
+ kc.c
+
+ Functions to emulate the video hardware of the kc85/4,kc85/3
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/kc.h"
+
+// 3 bit colour value. bit 2->green, bit 1->red, bit 0->blue
+static const UINT8 kc85_palette[KC85_PALETTE_SIZE * 3] =
+{
+ // foreground colours, "full" of each component
+ 0x00, 0x00, 0x00, // black
+ 0x00, 0x00, 0xd0, // blue
+ 0xd0, 0x00, 0x00, // red
+ 0xd0, 0x00, 0xd0, // magenta
+ 0x00, 0xd0, 0x00, // green
+ 0x00, 0xd0, 0xd0, // cyan
+ 0xd0, 0xd0, 0x00, // yellow
+ 0xd0, 0xd0, 0xd0, // white
+
+ // full of each component + half of another component
+ 0x00, 0x00, 0x00, // black
+ 0x60, 0x00, 0xa0, // violet
+ 0xa0, 0x60, 0x00, // brown
+ 0xa0, 0x00, 0x60, // red/purple
+ 0x00, 0xa0, 0x60, // pastel green
+ 0x00, 0x60, 0xa0, // sky blue
+ 0xa0, 0xa0, 0x60, // yellow/green
+ 0xd0, 0xd0, 0xd0, // white
+
+ // background colours are slightly darker than foreground colours
+ 0x00, 0x00, 0x00, // black
+ 0x00, 0x00, 0xa0, // dark blue
+ 0xa0, 0x00, 0x00, // dark red
+ 0xa0, 0x00, 0xa0, // dark magenta
+ 0x00, 0xa0, 0x00, // dark green
+ 0x00, 0xa0, 0xa0, // dark cyan
+ 0xa0, 0xa0, 0x00, // dark yellow
+ 0xa0, 0xa0, 0xa0 // dark white (grey)
+};
+
+
+/* Initialise the palette */
+PALETTE_INIT( kc85 )
+{
+ for (int i = 0; i < sizeof(kc85_palette) / 3; i++ )
+ palette_set_color_rgb(machine, i, kc85_palette[i*3], kc85_palette[i*3+1], kc85_palette[i*3+2]);
+}
+
+/* set new blink state */
+WRITE_LINE_MEMBER( kc_state::video_toggle_blink_state )
+{
+ if (state)
+ {
+ machine().primary_screen->update_partial(machine().primary_screen->vpos());
+
+ m_kc85_blink_state = !m_kc85_blink_state;
+ }
+}
+
+
+/* draw 8 pixels */
+void kc_state::video_draw_8_pixels(bitmap_ind16 &bitmap, int x, int y, UINT8 colour_byte, UINT8 gfx_byte)
+{
+ int pens[4];
+ int px;
+
+ if (m_high_resolution)
+ {
+ /* High resolution: 4 colors for block */
+
+ pens[0] = 0; // black
+ pens[1] = 2; // red
+ pens[2] = 5; // cyan
+ pens[3] = 7; // white
+
+ px = x;
+
+ for (int a=0; a<8; a++)
+ {
+ int pen = pens[((gfx_byte>>7) & 0x07) | ((colour_byte>>6) & 0x02)];
+
+ if ((px >= 0) && (px < bitmap.width()) && (y >= 0) && (y < bitmap.height()))
+ {
+ bitmap.pix16(y, px) = pen;
+ }
+
+ px++;
+ colour_byte <<= 1;
+ gfx_byte <<= 1;
+ }
+ }
+ else
+ {
+ /* Low resolution: 2 colors for block */
+ /* 16 foreground colours, 8 background colours */
+
+ /* bit 7 = 1: flash between foreground and background colour 0: no flash */
+ /* bit 6: adjusts foreground colours by adding half of another component */
+ /* bit 5,4,3 = foreground colour */
+ /* bit 5: background colour -> Green */
+ /* bit 4: background colour -> Red */
+ /* bit 3: background colour -> Blue */
+ /* bit 2,1,0 = background colour */
+ /* bit 2: background colour -> Green */
+ /* bit 1: background colour -> Red */
+ /* bit 0: background colour -> Blue */
+
+ int background_pen = (colour_byte&7) + 16;
+ int foreground_pen = ((colour_byte>>3) & 0x0f);
+
+ if ((colour_byte & 0x80) && m_kc85_blink_state && (m_pio_data[1] & 0x80))
+ {
+ foreground_pen = background_pen;
+ }
+
+ pens[0] = background_pen;
+ pens[1] = foreground_pen;
+
+ px = x;
+
+ for (int a=0; a<8; a++)
+ {
+ int pen = pens[(gfx_byte>>7) & 0x01];
+
+ if ((px >= 0) && (px < bitmap.width()) && (y >= 0) && (y < bitmap.height()))
+ {
+ bitmap.pix16(y, px) = pen;
+ }
+ px++;
+ gfx_byte = gfx_byte<<1;
+ }
+ }
+}
+
+
+/***************************************************************************
+ KC85/4 video hardware
+***************************************************************************/
+
+void kc85_4_state::video_start()
+{
+ m_video_ram = machine().memory().region_alloc("videoram", (KC85_4_SCREEN_COLOUR_RAM_SIZE*2) + (KC85_4_SCREEN_PIXEL_RAM_SIZE*2), 1, ENDIANNESS_LITTLE)->base();
+ m_display_video_ram = m_video_ram;
+
+ m_kc85_blink_state = 0;
+}
+
+void kc85_4_state::video_control_w(int data)
+{
+ /* calculate address of video ram to display */
+ if (data & 1)
+ m_display_video_ram = m_video_ram + (KC85_4_SCREEN_PIXEL_RAM_SIZE + KC85_4_SCREEN_COLOUR_RAM_SIZE);
+ else
+ m_display_video_ram = m_video_ram;
+
+ m_high_resolution = (data & 0x08) ? 0 : 1;
+}
+
+
+UINT32 kc85_4_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT8 *pixel_ram = m_display_video_ram;
+ UINT8 *colour_ram = pixel_ram + 0x04000;
+
+ for (int y=cliprect.min_y; y<=cliprect.max_y; y++)
+ {
+ for (int x=0; x<(KC85_SCREEN_WIDTH>>3); x++)
+ {
+ UINT16 offset = y | (x<<8);
+
+ UINT8 colour_byte = colour_ram[offset];
+ UINT8 gfx_byte = pixel_ram[offset];
+
+ video_draw_8_pixels(bitmap, (x<<3), y, colour_byte, gfx_byte);
+ }
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ KC85/3 video
+***************************************************************************/
+
+void kc_state::video_start()
+{
+ m_video_ram = machine().memory().region_alloc("videoram", 0x4000, 1, ENDIANNESS_LITTLE)->base();
+
+ m_kc85_blink_state = 0;
+}
+
+UINT32 kc_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ /* colour ram takes up 0x02800 bytes */
+ UINT8 *pixel_ram = m_video_ram;
+ UINT8 *colour_ram = m_video_ram + 0x02800;
+
+ for (int y=cliprect.min_y; y<=cliprect.max_y; y++)
+ {
+ for (int x=0; x<(KC85_SCREEN_WIDTH>>3); x++)
+ {
+ int pixel_offset,colour_offset;
+
+ if ((x & 0x020)==0)
+ {
+ pixel_offset = (x & 0x01f) | (((y>>2) & 0x03)<<5) |
+ ((y & 0x03)<<7) | (((y>>4) & 0x0f)<<9);
+
+ colour_offset = (x & 0x01f) | (((y>>2) & 0x03f)<<5);
+ }
+ else
+ {
+ /* 1 0 1 0 0 V7 V6 V1 V0 V3 V2 V5 V4 H2 H1 H0 */
+ /* 1 0 1 1 0 0 0 V7 V6 V3 V2 V5 V4 H2 H1 H0 */
+
+ pixel_offset = 0x02000+((x & 0x07) | (((y>>4) & 0x03)<<3) |
+ (((y>>2) & 0x03)<<5) | ((y & 0x03)<<7) | ((y>>6) & 0x03)<<9);
+
+ colour_offset = 0x0800+((x & 0x07) | (((y>>4) & 0x03)<<3) |
+ (((y>>2) & 0x03)<<5) | ((y>>6) & 0x03)<<7);
+ }
+
+ UINT8 colour_byte = colour_ram[colour_offset];
+ UINT8 gfx_byte = pixel_ram[pixel_offset];
+
+ video_draw_8_pixels(bitmap,(x<<3),y, colour_byte, gfx_byte);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mess/video/kramermc.c b/src/mess/video/kramermc.c
new file mode 100644
index 00000000000..13a1b52a0e8
--- /dev/null
+++ b/src/mess/video/kramermc.c
@@ -0,0 +1,45 @@
+/***************************************************************************
+
+ Kramer MC video driver by Miodrag Milanovic
+
+ 13/09/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/kramermc.h"
+
+#define KRAMERMC_VIDEO_MEMORY 0xFC00
+
+const gfx_layout kramermc_charlayout =
+{
+ 8, 8, /* 8x8 characters */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ {0}, /* no bitplanes; 1 bit per pixel */
+ {0, 1, 2, 3, 4, 5, 6, 7},
+ {0 * 8, 1 * 8, 2 * 8, 3 * 8, 4 * 8, 5 * 8, 6 * 8, 7 * 8},
+ 8*8 /* size of one char */
+};
+
+VIDEO_START( kramermc )
+{
+}
+
+SCREEN_UPDATE_IND16( kramermc )
+{
+ int x,y;
+ address_space *space = screen.machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ for(y = 0; y < 16; y++ )
+ {
+ for(x = 0; x < 64; x++ )
+ {
+ int code = space->read_byte(KRAMERMC_VIDEO_MEMORY + x + y*64);
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], code , 0, 0,0, x*8,y*8);
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/kyocera.c b/src/mess/video/kyocera.c
new file mode 100644
index 00000000000..1ffb9b43ab6
--- /dev/null
+++ b/src/mess/video/kyocera.c
@@ -0,0 +1,84 @@
+#include "includes/kyocera.h"
+
+static PALETTE_INIT( kc85 )
+{
+ palette_set_color(machine, 0, MAKE_RGB(138, 146, 148));
+ palette_set_color(machine, 1, MAKE_RGB(92, 83, 88));
+}
+
+UINT32 kc85_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ m_lcdc0->screen_update(screen, bitmap, cliprect);
+ m_lcdc1->screen_update(screen, bitmap, cliprect);
+ m_lcdc2->screen_update(screen, bitmap, cliprect);
+ m_lcdc3->screen_update(screen, bitmap, cliprect);
+ m_lcdc4->screen_update(screen, bitmap, cliprect);
+ m_lcdc5->screen_update(screen, bitmap, cliprect);
+ m_lcdc6->screen_update(screen, bitmap, cliprect);
+ m_lcdc7->screen_update(screen, bitmap, cliprect);
+ m_lcdc8->screen_update(screen, bitmap, cliprect);
+ m_lcdc9->screen_update(screen, bitmap, cliprect);
+
+ return 0;
+}
+
+UINT32 tandy200_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ m_lcdc->screen_update(screen, bitmap, cliprect);
+
+ return 0;
+}
+
+static HD61830_INTERFACE( lcdc_intf )
+{
+ SCREEN_TAG,
+ DEVCB_NULL
+};
+
+static ADDRESS_MAP_START( tandy200_lcdc, AS_0, 8, tandy200_state )
+ ADDRESS_MAP_GLOBAL_MASK(0x1fff)
+ AM_RANGE(0x0000, 0x1fff) AM_RAM
+ADDRESS_MAP_END
+
+MACHINE_CONFIG_FRAGMENT( kc85_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, LCD)
+ MCFG_SCREEN_REFRESH_RATE(44)
+ MCFG_SCREEN_UPDATE_DRIVER(kc85_state, screen_update)
+ MCFG_SCREEN_SIZE(240, 64)
+ MCFG_SCREEN_VISIBLE_AREA(0, 240-1, 0, 64-1)
+
+ MCFG_DEFAULT_LAYOUT(layout_lcd)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(kc85)
+
+ MCFG_HD44102_ADD(HD44102_0_TAG, SCREEN_TAG, 0, 0)
+ MCFG_HD44102_ADD(HD44102_1_TAG, SCREEN_TAG, 50, 0)
+ MCFG_HD44102_ADD(HD44102_2_TAG, SCREEN_TAG, 100, 0)
+ MCFG_HD44102_ADD(HD44102_3_TAG, SCREEN_TAG, 150, 0)
+ MCFG_HD44102_ADD(HD44102_4_TAG, SCREEN_TAG, 200, 0)
+ MCFG_HD44102_ADD(HD44102_5_TAG, SCREEN_TAG, 0, 32)
+ MCFG_HD44102_ADD(HD44102_6_TAG, SCREEN_TAG, 50, 32)
+ MCFG_HD44102_ADD(HD44102_7_TAG, SCREEN_TAG, 100, 32)
+ MCFG_HD44102_ADD(HD44102_8_TAG, SCREEN_TAG, 150, 32)
+ MCFG_HD44102_ADD(HD44102_9_TAG, SCREEN_TAG, 200, 32)
+
+// MCFG_HD44103_MASTER_ADD("m11", SCREEN_TAG, CAP_P(18), RES_K(100), HD44103_FS_HIGH, HD44103_DUTY_1_32)
+// MCFG_HD44103_SLAVE_ADD( "m12", "m11", SCREEN_TAG, HD44103_FS_HIGH, HD44103_DUTY_1_32)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( tandy200_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, LCD)
+ MCFG_SCREEN_REFRESH_RATE(80)
+ MCFG_SCREEN_UPDATE_DRIVER(tandy200_state, screen_update)
+ MCFG_SCREEN_SIZE(240, 128)
+ MCFG_SCREEN_VISIBLE_AREA(0, 240-1, 0, 128-1)
+
+ MCFG_DEFAULT_LAYOUT(layout_lcd)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(kc85)
+
+ MCFG_HD61830_ADD(HD61830_TAG, XTAL_4_9152MHz/2/2, lcdc_intf)
+ MCFG_DEVICE_ADDRESS_MAP(AS_0, tandy200_lcdc)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/llc.c b/src/mess/video/llc.c
new file mode 100644
index 00000000000..952bb4e39e1
--- /dev/null
+++ b/src/mess/video/llc.c
@@ -0,0 +1,97 @@
+/***************************************************************************
+
+ LLC driver by Miodrag Milanovic
+
+ 17/04/2009 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "includes/llc.h"
+
+
+VIDEO_START( llc )
+{
+ llc_state *state = machine.driver_data<llc_state>();
+ state->m_p_chargen = state->memregion("chargen")->base();
+}
+
+SCREEN_UPDATE_IND16( llc1 )
+{
+ llc_state *state = screen.machine().driver_data<llc_state>();
+ UINT8 y,ra,chr,gfx,inv;
+ UINT16 sy=0,ma=0,x;
+
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 8; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 64; x++)
+ {
+ inv = (state->m_p_videoram[x] & 0x80) ? 0xff : 0;
+ chr = state->m_p_videoram[x] & 0x7f;
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[ chr | (ra << 7) ] ^ inv;
+
+ /* Display a scanline of a character (8 pixels) */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=64;
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( llc2 )
+{
+ llc_state *state = screen.machine().driver_data<llc_state>();
+ UINT8 y,ra,chr,gfx,inv, inv1=state->m_rv ? 0xff : 0;
+ UINT16 sy=0,ma=0,x;
+
+ for (y = 0; y < 32; y++)
+ {
+ for (ra = 0; ra < 8; ra++)
+ {
+ inv = 0;
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 64; x++)
+ {
+ chr = state->m_p_videoram[x];
+ if (chr==0x11) // inverse on
+ {
+ inv=0xff;
+ chr=0x0f; // must not show
+ }
+ else
+ if (chr==0x10) // inverse off
+ inv=0;
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[ (chr << 3) | ra ] ^ inv ^ inv1;
+
+ /* Display a scanline of a character (8 pixels) */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=64;
+ }
+ return 0;
+}
diff --git a/src/mess/video/lviv.c b/src/mess/video/lviv.c
new file mode 100644
index 00000000000..87956253f6f
--- /dev/null
+++ b/src/mess/video/lviv.c
@@ -0,0 +1,91 @@
+/***************************************************************************
+
+ lviv.c
+
+ Functions to emulate the video hardware of PK-01 Lviv.
+
+ Krzysztof Strzecha
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/lviv.h"
+
+const unsigned char lviv_palette[8*3] =
+{
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xa4,
+ 0x00, 0xa4, 0x00,
+ 0x00, 0xa4, 0xa4,
+ 0xa4, 0x00, 0x00,
+ 0xa4, 0x00, 0xa4,
+ 0xa4, 0xa4, 0x00,
+ 0xa4, 0xa4, 0xa4
+};
+
+
+PALETTE_INIT( lviv )
+{
+ int i;
+
+ for ( i = 0; i < sizeof(lviv_palette) / 3; i++ ) {
+ palette_set_color_rgb(machine, i, lviv_palette[i*3], lviv_palette[i*3+1], lviv_palette[i*3+2]);
+ }
+}
+
+
+void lviv_update_palette(running_machine &machine, UINT8 pal)
+{
+ lviv_state *state = machine.driver_data<lviv_state>();
+ state->m_colortable[0][0] = 0;
+ state->m_colortable[0][1] = 0;
+ state->m_colortable[0][2] = 0;
+ state->m_colortable[0][3] = 0;
+
+ state->m_colortable[0][0] |= (((pal>>3)&0x01) == ((pal>>4)&0x01)) ? 0x04 : 0x00;
+ state->m_colortable[0][0] |= ((pal>>5)&0x01) ? 0x02 : 0x00;
+ state->m_colortable[0][0] |= (((pal>>2)&0x01) == ((pal>>6)&0x01)) ? 0x01 : 0x00;
+
+ state->m_colortable[0][1] |= ((pal&0x01) == ((pal>>4)&0x01)) ? 0x04 : 0x00;
+ state->m_colortable[0][1] |= ((pal>>5)&0x01) ? 0x02 : 0x00;
+ state->m_colortable[0][1] |= ((pal>>6)&0x01) ? 0x00 : 0x01;
+
+ state->m_colortable[0][2] |= ((pal>>4)&0x01) ? 0x04 : 0x00;
+ state->m_colortable[0][2] |= ((pal>>5)&0x01) ? 0x00 : 0x02;
+ state->m_colortable[0][2] |= ((pal>>6)&0x01) ? 0x01 : 0x00;
+
+ state->m_colortable[0][3] |= ((pal>>4)&0x01) ? 0x00 : 0x04;
+ state->m_colortable[0][3] |= (((pal>>1)&0x01) == ((pal>>5)&0x01)) ? 0x02 : 0x00;
+ state->m_colortable[0][3] |= ((pal>>6)&0x01) ? 0x01 : 0x00;
+}
+
+VIDEO_START( lviv )
+{
+}
+
+SCREEN_UPDATE_IND16( lviv )
+{
+ lviv_state *state = screen.machine().driver_data<lviv_state>();
+ int x,y;
+ int pen;
+ UINT8 data;
+
+ for (y=0; y<256; y++)
+ for (x=0; x<256; x+=4)
+ {
+ data = state->m_video_ram[y*64+x/4];
+
+ pen = state->m_colortable[0][((data & 0x08) >> 3) | ((data & 0x80) >> (3+3))];
+ bitmap.pix16(y, x + 0) = pen;
+
+ pen = state->m_colortable[0][((data & 0x04) >> 2) | ((data & 0x40) >> (2+3))];
+ bitmap.pix16(y, x + 1) = pen;
+
+ pen = state->m_colortable[0][((data & 0x02) >> 1) | ((data & 0x20) >> (1+3))];
+ bitmap.pix16(y, x + 2) = pen;
+
+ pen = state->m_colortable[0][((data & 0x01) >> 0) | ((data & 0x10) >> (0+3))];
+ bitmap.pix16(y, x + 3) = pen;
+ }
+ return 0;
+}
diff --git a/src/mess/video/mac.c b/src/mess/video/mac.c
new file mode 100644
index 00000000000..f21cabd0513
--- /dev/null
+++ b/src/mess/video/mac.c
@@ -0,0 +1,1063 @@
+/***************************************************************************
+
+ video/mac.c
+
+ Macintosh video hardware
+
+ Emulates the video hardware for compact Macintosh series (original
+ Macintosh (128k, 512k, 512ke), Macintosh Plus, Macintosh SE, Macintosh
+ Classic)
+
+ Also emulates on-board video for systems with the
+ RBV, V8, Sonora, and DAFB chips.
+
+ ----------------------------------------------------------------------
+ Monitor sense codes
+
+ Apple assigns 3 pins for monitor IDs. These allow 8 possible codes:
+
+ 000 - color 2-Page Display (21")
+ 001 - monochrome Full Page display (15")
+ 010 - color 512x384 (12")
+ 011 - monochrome 2 Page display (21")
+ 100 - NTSC
+ 101 - color Full Page display (15")
+ 110 - High-Resolution Color (13" 640x480) or use "type 6" extended codes
+ 111 - No monitor connected or use "type 7" extended codes
+
+ For extended codes, you drive one of the 3 pins at a time and read the 2
+ undriven pins. See http://support.apple.com/kb/TA21618?viewlocale=en_US
+ for details.
+
+Extended codes:
+
+ Sense 2 Low Sense 1 Low Sense 0 Low
+ 1 & 0 2 & 0 2 & 1
+
+Multiple Scan 14" 00 00 11
+Multiple Scan 16" 00 10 11
+Multiple Scan 21" 10 00 11
+PAL Encoder 00 00 00
+NTSC Encoder 01 01 00
+VGA/Super VGA 01 01 11
+RGB 16" 10 11 01
+PAL Monitor 11 00 00
+RGB 19" 11 10 10
+Radius color TPD 11 00 01 (TPD = Two Page Display)
+Radius mono TPD 11 01 00
+Apple TPD 11 01 01
+Apple color FPD 01 11 10 (FPD = Full Page Display)
+
+***************************************************************************/
+
+
+#include "emu.h"
+#include "sound/asc.h"
+#include "includes/mac.h"
+#include "machine/ram.h"
+
+PALETTE_INIT( mac )
+{
+ palette_set_color_rgb(machine, 0, 0xff, 0xff, 0xff);
+ palette_set_color_rgb(machine, 1, 0x00, 0x00, 0x00);
+}
+
+// 4-level grayscale
+PALETTE_INIT( macgsc )
+{
+ palette_set_color_rgb(machine, 0, 0xff, 0xff, 0xff);
+ palette_set_color_rgb(machine, 1, 0x7f, 0x7f, 0x7f);
+ palette_set_color_rgb(machine, 2, 0x3f, 0x3f, 0x3f);
+ palette_set_color_rgb(machine, 3, 0x00, 0x00, 0x00);
+}
+
+VIDEO_START( mac )
+{
+}
+
+#define MAC_MAIN_SCREEN_BUF_OFFSET 0x5900
+#define MAC_ALT_SCREEN_BUF_OFFSET 0xD900
+
+SCREEN_UPDATE_IND16( mac )
+{
+ UINT32 video_base;
+ const UINT16 *video_ram;
+ UINT16 word;
+ UINT16 *line;
+ int y, x, b;
+ mac_state *state = screen.machine().driver_data<mac_state>();
+
+ video_base = screen.machine().device<ram_device>(RAM_TAG)->size() - (state->m_screen_buffer ? MAC_MAIN_SCREEN_BUF_OFFSET : MAC_ALT_SCREEN_BUF_OFFSET);
+ video_ram = (const UINT16 *) (screen.machine().device<ram_device>(RAM_TAG)->pointer() + video_base);
+
+ for (y = 0; y < MAC_V_VIS; y++)
+ {
+ line = &bitmap.pix16(y);
+
+ for (x = 0; x < MAC_H_VIS; x += 16)
+ {
+ word = *(video_ram++);
+ for (b = 0; b < 16; b++)
+ {
+ line[x + b] = (word >> (15 - b)) & 0x0001;
+ }
+ }
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( macse30 )
+{
+ UINT32 video_base;
+ const UINT16 *video_ram;
+ UINT16 word;
+ UINT16 *line;
+ int y, x, b;
+ mac_state *state = screen.machine().driver_data<mac_state>();
+
+ video_base = state->m_screen_buffer ? 0x8000 : 0;
+ video_ram = (const UINT16 *) &state->m_vram[video_base/4];
+
+ for (y = 0; y < MAC_V_VIS; y++)
+ {
+ line = &bitmap.pix16(y);
+
+ for (x = 0; x < MAC_H_VIS; x += 16)
+ {
+ word = video_ram[((y * MAC_H_VIS)/16) + ((x/16)^1)];
+ for (b = 0; b < 16; b++)
+ {
+ line[x + b] = (word >> (15 - b)) & 0x0001;
+ }
+ }
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( macprtb )
+{
+ const UINT16 *video_ram;
+ UINT16 word;
+ UINT16 *line;
+ int y, x, b;
+ mac_state *state = screen.machine().driver_data<mac_state>();
+
+ video_ram = (const UINT16 *) state->m_vram16.target();
+
+ for (y = 0; y < 400; y++)
+ {
+ line = &bitmap.pix16(y);
+
+ for (x = 0; x < 640; x += 16)
+ {
+ word = video_ram[((y * 640)/16) + ((x/16))];
+ for (b = 0; b < 16; b++)
+ {
+ line[x + b] = (word >> (15 - b)) & 0x0001;
+ }
+ }
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( macpb140 )
+{
+ const UINT16 *video_ram;
+ UINT16 word;
+ UINT16 *line;
+ int y, x, b;
+ mac_state *state = screen.machine().driver_data<mac_state>();
+
+ video_ram = (const UINT16 *) state->m_vram.target();
+
+ for (y = 0; y < 400; y++)
+ {
+ line = &bitmap.pix16(y);
+
+ for (x = 0; x < 640; x += 16)
+ {
+ word = video_ram[((y * 640)/16) + ((x/16)^1)];
+ for (b = 0; b < 16; b++)
+ {
+ line[x + b] = (word >> (15 - b)) & 0x0001;
+ }
+ }
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( macpb160 )
+{
+ UINT16 *line;
+ int y, x;
+ UINT8 pixels;
+ mac_state *state = screen.machine().driver_data<mac_state>();
+ UINT8 *vram8 = (UINT8 *)state->m_vram.target();
+
+ for (y = 0; y < 400; y++)
+ {
+ line = &bitmap.pix16(y);
+
+ for (x = 0; x < 640/4; x++)
+ {
+ pixels = vram8[(y * 160) + (BYTE4_XOR_BE(x))];
+
+// *line++ = (pixels>>4)&0xf;
+// *line++ = pixels&0xf;
+ *line++ = ((pixels>>6)&3);
+ *line++ = ((pixels>>4)&3);
+ *line++ = ((pixels>>2)&3);
+ *line++ = (pixels&3);
+
+ }
+ }
+ return 0;
+}
+
+// IIci/IIsi RAM-Based Video (RBV) and children: V8, Eagle, Spice, VASP, Sonora
+
+VIDEO_START( macrbv )
+{
+}
+
+VIDEO_RESET(maceagle)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ mac->m_rbv_montype = 32;
+ mac->m_rbv_palette[0xfe] = 0xffffff;
+ mac->m_rbv_palette[0xff] = 0;
+}
+
+VIDEO_RESET(macrbv)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+ rectangle visarea;
+ int htotal, vtotal;
+ double framerate;
+ int view;
+
+ memset(mac->m_rbv_regs, 0, sizeof(mac->m_rbv_regs));
+
+ mac->m_rbv_count = 0;
+ mac->m_rbv_clutoffs = 0;
+ mac->m_rbv_immed10wr = 0;
+
+ mac->m_rbv_regs[2] = 0x7f;
+ mac->m_rbv_regs[3] = 0;
+
+ mac->m_rbv_type = RBV_TYPE_RBV;
+
+ visarea.min_x = 0;
+ visarea.min_y = 0;
+ view = 0;
+ mac->m_rbv_montype = machine.root_device().ioport("MONTYPE")->read_safe(2);
+ switch (mac->m_rbv_montype)
+ {
+ case 1: // 15" portrait display
+ visarea.max_x = 640-1;
+ visarea.max_y = 870-1;
+ htotal = 832;
+ vtotal = 918;
+ framerate = 75.0;
+ view = 1;
+ break;
+
+ case 2: // 12" RGB
+ visarea.max_x = 512-1;
+ visarea.max_y = 384-1;
+ htotal = 640;
+ vtotal = 407;
+ framerate = 60.15;
+ break;
+
+ case 6: // 13" RGB
+ default:
+ visarea.max_x = 640-1;
+ visarea.max_y = 480-1;
+ htotal = 800;
+ vtotal = 525;
+ framerate = 59.94;
+ break;
+ }
+
+// printf("RBV reset: monitor is %dx%d @ %f Hz\n", visarea.max_x+1, visarea.max_y+1, framerate);
+ machine.primary_screen->configure(htotal, vtotal, visarea, HZ_TO_ATTOSECONDS(framerate));
+ render_target *target = machine.render().first_target();
+ target->set_view(view);
+}
+
+VIDEO_RESET(macsonora)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+ rectangle visarea;
+ int htotal, vtotal;
+ double framerate;
+
+ memset(mac->m_rbv_regs, 0, sizeof(mac->m_rbv_regs));
+
+ mac->m_rbv_count = 0;
+ mac->m_rbv_clutoffs = 0;
+ mac->m_rbv_immed10wr = 0;
+
+ mac->m_rbv_regs[2] = 0x7f;
+ mac->m_rbv_regs[3] = 0;
+
+ mac->m_rbv_type = RBV_TYPE_SONORA;
+
+ visarea.min_x = 0;
+ visarea.min_y = 0;
+
+ mac->m_rbv_montype = machine.root_device().ioport("MONTYPE")->read_safe(2);
+ switch (mac->m_rbv_montype)
+ {
+ case 1: // 15" portrait display
+ visarea.max_x = 640-1;
+ visarea.max_y = 870-1;
+ htotal = 832;
+ vtotal = 918;
+ framerate = 75.0;
+ break;
+
+ case 2: // 12" RGB
+ visarea.max_x = 512-1;
+ visarea.max_y = 384-1;
+ htotal = 640;
+ vtotal = 407;
+ framerate = 60.15;
+ break;
+
+ case 6: // 13" RGB
+ default:
+ visarea.max_x = 640-1;
+ visarea.max_y = 480-1;
+ htotal = 800;
+ vtotal = 525;
+ framerate = 59.94;
+ break;
+ }
+
+// printf("RBV reset: monitor is %dx%d @ %f Hz\n", visarea.max_x+1, visarea.max_y+1, framerate);
+ machine.primary_screen->configure(htotal, vtotal, visarea, HZ_TO_ATTOSECONDS(framerate));
+}
+
+VIDEO_START( macsonora )
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ memset(mac->m_rbv_regs, 0, sizeof(mac->m_rbv_regs));
+
+ mac->m_rbv_count = 0;
+ mac->m_rbv_clutoffs = 0;
+ mac->m_rbv_immed10wr = 0;
+
+ mac->m_rbv_regs[2] = 0x7f;
+ mac->m_rbv_regs[3] = 0;
+ mac->m_rbv_regs[4] = 0x6;
+ mac->m_rbv_regs[5] = 0x3;
+
+ mac->m_sonora_vctl[0] = 0x9f;
+ mac->m_sonora_vctl[1] = 0;
+ mac->m_sonora_vctl[2] = 0;
+
+ mac->m_rbv_type = RBV_TYPE_SONORA;
+}
+
+VIDEO_START( macv8 )
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ memset(mac->m_rbv_regs, 0, sizeof(mac->m_rbv_regs));
+
+ mac->m_rbv_count = 0;
+ mac->m_rbv_clutoffs = 0;
+ mac->m_rbv_immed10wr = 0;
+
+ mac->m_rbv_regs[0] = 0x4f;
+ mac->m_rbv_regs[1] = 0x06;
+ mac->m_rbv_regs[2] = 0x7f;
+
+ mac->m_rbv_type = RBV_TYPE_V8;
+}
+
+SCREEN_UPDATE_RGB32( macrbv )
+{
+ UINT32 *scanline;
+ int x, y, hres, vres;
+ mac_state *mac = screen.machine().driver_data<mac_state>();
+ UINT8 *vram8 = (UINT8 *)screen.machine().device<ram_device>(RAM_TAG)->pointer();
+
+ switch (mac->m_rbv_montype)
+ {
+ case 32: // classic II built-in display
+ hres = MAC_H_VIS;
+ vres = MAC_V_VIS;
+ vram8 += 0x1f9a80; // Classic II apparently doesn't use VRAM?
+ break;
+
+ case 1: // 15" portrait display
+ hres = 640;
+ vres = 870;
+ break;
+
+ case 2: // 12" RGB
+ hres = 512;
+ vres = 384;
+ break;
+
+ case 6: // 13" RGB
+ default:
+ hres = 640;
+ vres = 480;
+ break;
+ }
+
+ switch (mac->m_rbv_regs[0x10] & 7)
+ {
+ case 0: // 1bpp
+ {
+ UINT8 pixels;
+
+ for (y = 0; y < vres; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < hres; x+=8)
+ {
+ pixels = vram8[(y * (hres/8)) + ((x/8)^3)];
+
+ *scanline++ = mac->m_rbv_palette[0xfe|(pixels>>7)];
+ *scanline++ = mac->m_rbv_palette[0xfe|((pixels>>6)&1)];
+ *scanline++ = mac->m_rbv_palette[0xfe|((pixels>>5)&1)];
+ *scanline++ = mac->m_rbv_palette[0xfe|((pixels>>4)&1)];
+ *scanline++ = mac->m_rbv_palette[0xfe|((pixels>>3)&1)];
+ *scanline++ = mac->m_rbv_palette[0xfe|((pixels>>2)&1)];
+ *scanline++ = mac->m_rbv_palette[0xfe|((pixels>>1)&1)];
+ *scanline++ = mac->m_rbv_palette[0xfe|(pixels&1)];
+ }
+ }
+ }
+ break;
+
+ case 1: // 2bpp
+ {
+ UINT8 pixels;
+
+ for (y = 0; y < vres; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < hres/4; x++)
+ {
+ pixels = vram8[(y * (hres/4)) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = mac->m_rbv_palette[0xfc|((pixels>>6)&3)];
+ *scanline++ = mac->m_rbv_palette[0xfc|((pixels>>4)&3)];
+ *scanline++ = mac->m_rbv_palette[0xfc|((pixels>>2)&3)];
+ *scanline++ = mac->m_rbv_palette[0xfc|(pixels&3)];
+ }
+ }
+ }
+ break;
+
+ case 2: // 4bpp
+ {
+ UINT8 pixels;
+
+ for (y = 0; y < vres; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < hres/2; x++)
+ {
+ pixels = vram8[(y * (hres/2)) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = mac->m_rbv_palette[0xf0|(pixels>>4)];
+ *scanline++ = mac->m_rbv_palette[0xf0|(pixels&0xf)];
+ }
+ }
+ }
+ break;
+
+ case 3: // 8bpp
+ {
+ UINT8 pixels;
+
+ for (y = 0; y < vres; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < hres; x++)
+ {
+ pixels = vram8[(y * hres) + (BYTE4_XOR_BE(x))];
+ *scanline++ = mac->m_rbv_palette[pixels];
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+SCREEN_UPDATE_RGB32( macrbvvram )
+{
+ UINT32 *scanline;
+ int x, y;
+ mac_state *mac = screen.machine().driver_data<mac_state>();
+ UINT8 mode = 0;
+
+ switch (mac->m_rbv_type)
+ {
+ case RBV_TYPE_RBV:
+ case RBV_TYPE_V8:
+ mode = mac->m_rbv_regs[0x10] & 7;
+ break;
+
+ case RBV_TYPE_SONORA:
+ mode = mac->m_sonora_vctl[1] & 7;
+
+ // forced blank?
+ if (mac->m_sonora_vctl[0] & 0x80)
+ {
+ return 0;
+ }
+ break;
+ }
+
+ switch (mode)
+ {
+ case 0: // 1bpp
+ {
+ UINT8 *vram8 = (UINT8 *)mac->m_vram.target();
+ UINT8 pixels;
+
+ if (mac->m_rbv_type == RBV_TYPE_SONORA)
+ {
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640; x+=8)
+ {
+ pixels = vram8[(y * 80) + ((x/8)^3)];
+
+ *scanline++ = mac->m_rbv_palette[0x7f|(pixels&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<1)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<2)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<3)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<4)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<5)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<6)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<7)&0x80)];
+ }
+ }
+ }
+ else
+ {
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640; x+=8)
+ {
+ pixels = vram8[(y * 0x400) + ((x/8)^3)];
+
+ *scanline++ = mac->m_rbv_palette[0x7f|(pixels&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<1)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<2)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<3)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<4)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<5)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<6)&0x80)];
+ *scanline++ = mac->m_rbv_palette[0x7f|((pixels<<7)&0x80)];
+ }
+ }
+ }
+ }
+ break;
+
+ case 1: // 2bpp
+ {
+ UINT8 *vram8 = (UINT8 *)mac->m_vram.target();
+ UINT8 pixels;
+
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640/4; x++)
+ {
+ pixels = vram8[(y * 160) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = mac->m_rbv_palette[0xfc|((pixels>>6)&3)];
+ *scanline++ = mac->m_rbv_palette[0xfc|((pixels>>4)&3)];
+ *scanline++ = mac->m_rbv_palette[0xfc|((pixels>>2)&3)];
+ *scanline++ = mac->m_rbv_palette[0xfc|(pixels&3)];
+ }
+ }
+ }
+ break;
+
+ case 2: // 4bpp
+ {
+ UINT8 *vram8 = (UINT8 *)mac->m_vram.target();
+ UINT8 pixels;
+
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 640/2; x++)
+ {
+ pixels = vram8[(y * 320) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = mac->m_rbv_palette[0xf0|(pixels>>4)];
+ *scanline++ = mac->m_rbv_palette[0xf0|(pixels&0xf)];
+ }
+ }
+ }
+ break;
+
+ case 3: // 8bpp
+ {
+ UINT8 *vram8 = (UINT8 *)mac->m_vram.target();
+ UINT8 pixels;
+
+ if (mac->m_rbv_type == RBV_TYPE_SONORA)
+ {
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 640; x++)
+ {
+ pixels = vram8[(y * 0x280) + (BYTE4_XOR_BE(x))];
+ *scanline++ = mac->m_rbv_palette[pixels];
+ }
+ }
+ }
+ else
+ {
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 640; x++)
+ {
+ pixels = vram8[(y * 2048) + (BYTE4_XOR_BE(x))];
+ *scanline++ = mac->m_rbv_palette[pixels];
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+// DAFB: video for Quadra 700/900
+
+static void dafb_recalc_ints(mac_state *mac)
+{
+ if (mac->m_dafb_int_status != 0)
+ {
+ mac->nubus_slot_interrupt(0xf, ASSERT_LINE);
+ }
+ else
+ {
+ mac->nubus_slot_interrupt(0xf, CLEAR_LINE);
+ }
+}
+
+static TIMER_CALLBACK(dafb_vbl_tick)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ mac->m_dafb_int_status |= 1;
+ dafb_recalc_ints(mac);
+
+ mac->m_vbl_timer->adjust(mac->m_screen->time_until_pos(480, 0), 0);
+}
+
+static TIMER_CALLBACK(dafb_cursor_tick)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ mac->m_dafb_int_status |= 4;
+ dafb_recalc_ints(mac);
+
+ mac->m_cursor_timer->adjust(mac->m_screen->time_until_pos(mac->m_cursor_line, 0), 0);
+}
+
+VIDEO_START( macdafb )
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ mac->m_vbl_timer = machine.scheduler().timer_alloc(FUNC(dafb_vbl_tick));
+ mac->m_cursor_timer = machine.scheduler().timer_alloc(FUNC(dafb_cursor_tick));
+
+ mac->m_vbl_timer->adjust(attotime::never);
+ mac->m_cursor_timer->adjust(attotime::never);
+}
+
+VIDEO_RESET(macdafb)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ mac->m_rbv_count = 0;
+ mac->m_rbv_clutoffs = 0;
+ mac->m_rbv_montype = 6;
+ mac->m_rbv_vbltime = 0;
+ mac->m_dafb_int_status = 0;
+ mac->m_rbv_type = RBV_TYPE_DAFB;
+ mac->m_dafb_mode = 0;
+ mac->m_dafb_base = 0x1000;
+ mac->m_dafb_stride = 256*4;
+
+ memset(mac->m_rbv_palette, 0, sizeof(mac->m_rbv_palette));
+}
+
+READ32_MEMBER(mac_state::dafb_r)
+{
+// if (offset != 0x108/4) printf("DAFB: Read @ %x (mask %x PC=%x)\n", offset*4, mem_mask, cpu_get_pc(m_maincpu));
+
+ switch (offset<<2)
+ {
+ case 0x1c: // inverse of monitor sense
+ return 7; // 21" color 2-page
+ break;
+
+ case 0x24: // SCSI 539x #1 status
+ return m_dafb_scsi1_drq<<9;
+ break;
+
+ case 0x28: // SCSI 539x #2 status
+ return m_dafb_scsi2_drq<<9;
+ break;
+
+ case 0x108: // IRQ/VBL status
+ return m_dafb_int_status;
+ break;
+
+ case 0x10c: // clear cursor scanline int
+ m_dafb_int_status &= ~4;
+ dafb_recalc_ints(this);
+ break;
+
+ case 0x114: // clear VBL int
+ m_dafb_int_status &= ~1;
+ dafb_recalc_ints(this);
+ break;
+ }
+ return 0;
+}
+
+WRITE32_MEMBER(mac_state::dafb_w)
+{
+// if (offset != 0x10c/4) printf("DAFB: Write %08x @ %x (mask %x PC=%x)\n", data, offset*4, mem_mask, cpu_get_pc(m_maincpu));
+
+ switch (offset<<2)
+ {
+ case 0: // bits 20-9 of base
+ m_dafb_base &= 0x1ff;
+ m_dafb_base |= (data & 0xffff) << 9;
+// printf("DAFB baseH: %x\n", m_dafb_base);
+ break;
+
+ case 4: // bits 8-5 of base
+ m_dafb_base &= ~0x1ff;
+ m_dafb_base |= (data & 0xf) << 5;
+// printf("DAFB baseL: %x\n", m_dafb_base);
+ break;
+
+ case 8:
+ m_dafb_stride = data<<2; // stride in DWORDs
+// printf("DAFB stride: %x %x\n", m_dafb_stride, data);
+ break;
+
+ case 0x104:
+ if (data & 1) // VBL enable
+ {
+ m_vbl_timer->adjust(m_screen->time_until_pos(480, 0), 0);
+ }
+ else
+ {
+ m_vbl_timer->adjust(attotime::never);
+ m_dafb_int_status &= ~1;
+ dafb_recalc_ints(this);
+ }
+
+ if (data & 2) // aux scanline interrupt enable
+ {
+ fatalerror("DAFB: Aux scanline interrupt enable not supported!\n");
+ }
+
+ if (data & 4) // cursor scanline interrupt enable
+ {
+ m_cursor_timer->adjust(m_screen->time_until_pos(m_cursor_line, 0), 0);
+ }
+ else
+ {
+ m_cursor_timer->adjust(attotime::never);
+ m_dafb_int_status &= ~4;
+ dafb_recalc_ints(this);
+ }
+ break;
+
+ case 0x10c: // clear cursor scanline int
+ m_dafb_int_status &= ~4;
+ dafb_recalc_ints(this);
+ break;
+
+ case 0x114: // clear VBL int
+ m_dafb_int_status &= ~1;
+ dafb_recalc_ints(this);
+ break;
+ }
+}
+
+READ32_MEMBER(mac_state::dafb_dac_r)
+{
+// printf("DAFB: Read DAC @ %x (mask %x PC=%x)\n", offset*4, mem_mask, cpu_get_pc(m_maincpu));
+
+ return 0;
+}
+
+WRITE32_MEMBER(mac_state::dafb_dac_w)
+{
+// if ((offset > 0) && (offset != 0x10/4)) printf("DAFB: Write %08x to DAC @ %x (mask %x PC=%x)\n", data, offset*4, mem_mask, cpu_get_pc(m_maincpu));
+
+ switch (offset<<2)
+ {
+ case 0:
+ m_rbv_clutoffs = data & 0xff;
+ m_rbv_count = 0;
+ break;
+
+ case 0x10:
+ m_rbv_colors[m_rbv_count++] = data&0xff;
+
+ if (m_rbv_count == 3)
+ {
+ palette_set_color(space.machine(), m_rbv_clutoffs, MAKE_RGB(m_rbv_colors[0], m_rbv_colors[1], m_rbv_colors[2]));
+ m_rbv_palette[m_rbv_clutoffs] = MAKE_RGB(m_rbv_colors[0], m_rbv_colors[1], m_rbv_colors[2]);
+ m_rbv_clutoffs++;
+ m_rbv_count = 0;
+ }
+ break;
+
+ case 0x20:
+ printf("%x to DAFB mode\n", data);
+ switch (data & 0x9f)
+ {
+ case 0x80:
+ m_dafb_mode = 0; // 1bpp
+ break;
+
+ case 0x88:
+ m_dafb_mode = 1; // 2bpp
+ break;
+
+ case 0x90:
+ m_dafb_mode = 2; // 4bpp
+ break;
+
+ case 0x98:
+ m_dafb_mode = 3; // 8bpp
+ break;
+
+ case 0x9c:
+ m_dafb_mode = 4; // 24bpp
+ break;
+ }
+ break;
+ }
+}
+
+SCREEN_UPDATE_RGB32( macdafb )
+{
+ UINT32 *scanline;
+ int x, y;
+ mac_state *mac = screen.machine().driver_data<mac_state>();
+
+ switch (mac->m_dafb_mode)
+ {
+ case 0: // 1bpp
+ {
+ UINT8 *vram8 = (UINT8 *)mac->m_vram.target();
+ UINT8 pixels;
+ vram8 += mac->m_dafb_base;
+
+ for (y = 0; y < 870; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 1152; x+=8)
+ {
+ pixels = vram8[(y * mac->m_dafb_stride) + ((x/8)^3)];
+
+ *scanline++ = mac->m_rbv_palette[(pixels>>7)&1];
+ *scanline++ = mac->m_rbv_palette[(pixels>>6)&1];
+ *scanline++ = mac->m_rbv_palette[(pixels>>5)&1];
+ *scanline++ = mac->m_rbv_palette[(pixels>>4)&1];
+ *scanline++ = mac->m_rbv_palette[(pixels>>3)&1];
+ *scanline++ = mac->m_rbv_palette[(pixels>>2)&1];
+ *scanline++ = mac->m_rbv_palette[(pixels>>1)&1];
+ *scanline++ = mac->m_rbv_palette[(pixels&1)];
+ }
+ }
+ }
+ break;
+
+ case 1: // 2bpp
+ {
+ UINT8 *vram8 = (UINT8 *)mac->m_vram.target();
+ UINT8 pixels;
+ vram8 += mac->m_dafb_base;
+
+ for (y = 0; y < 870; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 1152/4; x++)
+ {
+ pixels = vram8[(y * mac->m_dafb_stride) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = mac->m_rbv_palette[((pixels>>6)&3)];
+ *scanline++ = mac->m_rbv_palette[((pixels>>4)&3)];
+ *scanline++ = mac->m_rbv_palette[((pixels>>2)&3)];
+ *scanline++ = mac->m_rbv_palette[(pixels&3)];
+ }
+ }
+ }
+ break;
+
+ case 2: // 4bpp
+ {
+ UINT8 *vram8 = (UINT8 *)mac->m_vram.target();
+ UINT8 pixels;
+ vram8 += mac->m_dafb_base;
+
+ for (y = 0; y < 870; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 1152/2; x++)
+ {
+ pixels = vram8[(y * mac->m_dafb_stride) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = mac->m_rbv_palette[(pixels>>4)];
+ *scanline++ = mac->m_rbv_palette[(pixels&0xf)];
+ }
+ }
+ }
+ break;
+
+ case 3: // 8bpp
+ {
+ UINT8 *vram8 = (UINT8 *)mac->m_vram.target();
+ UINT8 pixels;
+ vram8 += mac->m_dafb_base;
+
+ for (y = 0; y < 870; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 1152; x++)
+ {
+ pixels = vram8[(y * mac->m_dafb_stride) + (BYTE4_XOR_BE(x))];
+ *scanline++ = mac->m_rbv_palette[pixels];
+ }
+ }
+ }
+ break;
+
+ case 4: // 24 bpp
+ for (y = 0; y < 480; y++)
+ {
+ UINT32 *base;
+
+ scanline = &bitmap.pix32(y);
+ base = (UINT32 *)&mac->m_vram[(y * (mac->m_dafb_stride/4)) + (mac->m_dafb_base/4)];
+ for (x = 0; x < 640; x++)
+ {
+ *scanline++ = *base++;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+SCREEN_UPDATE_RGB32( macpbwd ) /* Color PowerBooks using an off-the-shelf WD video chipset */
+{
+ UINT32 *scanline;
+ int x, y;
+ mac_state *mac = screen.machine().driver_data<mac_state>();
+ UINT8 *vram8 = (UINT8 *)mac->m_vram.target();
+ UINT8 pixels;
+
+// vram8 += 0x40000;
+
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640; x++)
+ {
+ pixels = vram8[(y * 640) + (BYTE4_XOR_BE(x))];
+ *scanline++ = mac->m_rbv_palette[pixels];
+ }
+ }
+
+ return 0;
+}
+
+READ32_MEMBER(mac_state::macwd_r)
+{
+ switch (offset)
+ {
+ case 0xf6:
+ if (m_screen->vblank())
+ {
+ return 0xffffffff;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+
+ default:
+// printf("macwd_r: @ %x, mask %08x (PC=%x)\n", offset, mem_mask, cpu_get_pc(m_maincpu));
+ break;
+ }
+ return 0;
+}
+
+WRITE32_MEMBER(mac_state::macwd_w)
+{
+ switch (offset)
+ {
+ case 0xf2:
+ if (mem_mask == 0xff000000) // DAC control
+ {
+ m_rbv_clutoffs = data>>24;
+ m_rbv_count = 0;
+ }
+ else if (mem_mask == 0x00ff0000) // DAC data
+ {
+ m_rbv_colors[m_rbv_count++] = (data>>16)&0xff;
+ if (m_rbv_count == 3)
+ {
+// printf("RAMDAC: color %d = %02x %02x %02x\n", m_rbv_clutoffs, m_rbv_colors[0], m_rbv_colors[1], m_rbv_colors[2]);
+ m_rbv_palette[m_rbv_clutoffs] = MAKE_RGB(m_rbv_colors[0], m_rbv_colors[1], m_rbv_colors[2]);
+ m_rbv_clutoffs++;
+ m_rbv_count = 0;
+ }
+ }
+ else
+ {
+ printf("macwd: Unknown DAC write, data %08x, mask %08x\n", data, mem_mask);
+ }
+ break;
+
+ default:
+// printf("macwd_w: %x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, cpu_get_pc(m_maincpu));
+ break;
+ }
+}
+
diff --git a/src/mess/video/mbc55x.c b/src/mess/video/mbc55x.c
new file mode 100644
index 00000000000..3757db084b7
--- /dev/null
+++ b/src/mess/video/mbc55x.c
@@ -0,0 +1,201 @@
+/*
+ video/mbc55x.c
+
+ Machine driver for the Sanyo MBC-550 and MBC-555.
+
+ Phill Harvey-Smith
+ 2011-01-29.
+
+Taken from : http://www.seasip.info/VintagePC/sanyo.html
+
+Video Controller
+
+To a programmer, the MBC's video hardware appears as a 6845 chip and three bitmapped graphics planes.
+The 6845 appears at I/O ports 30h (register select) and 32h (data). At system boot, it is programmed
+for 25 lines x 72 columns. The RAM BIOS then reprograms it for 25 x 80. The ROM also provides timings
+for what appears to be a different 80-column mode; it decides which to use by reading port 1Ch.
+If bit 7 of the result is 1, the 72-column mode is used; otherwise, the 80-column mode is.
+
+Here are the values written to the 6845 in each case, plus (for comparison) the values used by a real CGA:
+
+ 6845 Register | IO.SYS | ROM 80 | ROM 72 | Real CGA
+=============================+========+========+========+==========
+ Horizontal total | 112 | 101 | 112 | 83
+ Horizontal display end | 80 | 80 | 72 | 80
+ Horizontal sync pos | 89 | 83 | 85 | 81
+ Horizontal sync width | 72 | 72 | 74 | 1
+ Vertical total | 65 | 105 | 65 | 26
+ Vertical total adjust | 0 | 2 | 0 | 0
+ Vertical displayed | 50 | 100 | 50 | 26
+ Vertical sync position | 56 | 100 | 56 | 25
+ Interlace | 0 | 0 | 0 | 2
+ Max scan address | 3 | 3 | 3 | 7
+ Cursor start | 0 | 0 | 0 | 6
+ Cursor end | 0 | 0 | 0 | 7
+=============================+========+========+========+==========
+
+The important thing to note here is that from the 6845's point of view, a character is 4 lines high.
+This explains why the framebuffer memory is mapped as it is.
+
+The framebuffers
+
+The MBC video RAM is composed of three planes - green, red and blue. The green plane occupies main memory,
+and its position varies; writes to port 10h set its address:
+
+Value | Address
+======+========
+ 4 | 0C000h
+ 5 | 1C000h (other values have not been tested)
+ 6 | 2C000h
+ 7 | 3C000h
+======+========
+
+The red and blue planes appear to have fixed locations of F0000h and F4000h respectively.
+
+When output goes to a composite monitor, the green plane is usually used by itself.
+The red plane becomes "blink", causing pixels in it to blink; and the blue plane becomes "bright".
+
+Within each plane, memory is organised as 50 rows of 320 bytes (288 bytes in 72-column mode).
+This corresponds to a rectangle, 640 (576) pixels wide and four pixels high. The first four bytes
+give the leftmost column of the rectangle, the next four give the next column, and so on:
+
+[--byte 0--] [--byte 4--] [--byte 8--] [--byte 12--] ...
+[--byte 1--] [--byte 5--] [--byte 9--] [--byte 13--] ...
+[--byte 2--] [--byte 6--] [--byte 10--] [--byte 14--] ...
+[--byte 3--] [--byte 7--] [--byte 11--] [--byte 15--] ...
+
+*************************************************************************************************************/
+
+#include "includes/mbc55x.h"
+
+#define DEBUG_LINES 1
+#define DEBUG_VSYNC 2
+
+#define DEBUG_SET(flags) ((mstate->m_debug_video & (flags))==(flags))
+
+static void video_debug(running_machine &machine, int ref, int params, const char *param[])
+{
+ mbc55x_state *mstate = machine.driver_data<mbc55x_state>();
+ if(params>0)
+ {
+ sscanf(param[0],"%d",&mstate->m_debug_video);
+ }
+ else
+ {
+ debug_console_printf(machine,"Error usage : mbc55x_vid_debug <debuglevel>\n");
+ debug_console_printf(machine,"Current debuglevel=%02X\n",mstate->m_debug_video);
+ }
+}
+
+static MC6845_UPDATE_ROW( vid_update_row )
+{
+ mbc55x_state *mstate = device->machine().driver_data<mbc55x_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ UINT8 *ram = &mstate->m_ram->pointer()[0];
+ UINT8 *red = &mstate->m_video_mem[RED_PLANE_OFFSET];
+ UINT8 *blue = &mstate->m_video_mem[BLUE_PLANE_OFFSET];
+ UINT8 *green;
+ int offset;
+ UINT8 rpx,gpx,bpx;
+ UINT8 rb,gb,bb;
+
+ int x_pos;
+ int pixelno;
+ UINT8 bitno;
+ UINT8 shifts;
+ UINT8 colour;
+
+ switch(mstate->m_vram_page)
+ {
+ case 4 : green=&ram[0x08000]; break;
+ case 5 : green=&ram[0x1C000]; break;
+ case 6 : green=&ram[0x2C000]; break;
+ case 7 : green=&ram[0x3C000]; break;
+ default :
+ green=&ram[0x0C000];
+ }
+
+ if(DEBUG_SET(DEBUG_LINES))
+ logerror("MC6845_UPDATE_ROW: ma=%d, ra=%d, y=%d, x_count=%d\n",ma,ra,y,x_count);
+
+ offset=((ma*4) + ra) % COLOUR_PLANE_SIZE;
+
+ if(DEBUG_SET(DEBUG_LINES))
+ logerror("offset=%05X\n",offset);
+
+ for(x_pos=0; x_pos<x_count; x_pos++)
+ {
+ UINT16 mem = (offset+(x_pos*4)) % COLOUR_PLANE_SIZE;
+ rpx=red[mem];
+ gpx=green[mem];
+ bpx=blue[mem];
+
+ bitno=0x80;
+ shifts=7;
+
+ for(pixelno=0; pixelno<8; pixelno++)
+ {
+
+ rb=(rpx & bitno) >> shifts;
+ gb=(gpx & bitno) >> shifts;
+ bb=(bpx & bitno) >> shifts;
+
+ colour=(rb<<2) | (gb<<1) | (bb<<0);
+
+ bitmap.pix32(y, (x_pos*8)+pixelno)=palette[colour];
+ //logerror("set pixel (%d,%d)=%d\n",y, ((x_pos*8)+pixelno),colour);
+ bitno=bitno>>1;
+ shifts--;
+ }
+ }
+}
+
+WRITE_LINE_MEMBER( mbc55x_state::vid_hsync_changed )
+{
+}
+
+WRITE_LINE_MEMBER( mbc55x_state::vid_vsync_changed )
+{
+}
+
+const mc6845_interface mb55x_mc6845_intf =
+{
+ SCREEN_TAG, /* screen number */
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ vid_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_DRIVER_LINE_MEMBER(mbc55x_state, vid_hsync_changed), /* on_hsync_changed */
+ DEVCB_DRIVER_LINE_MEMBER(mbc55x_state, vid_vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+VIDEO_START( mbc55x )
+{
+ mbc55x_state *mstate = machine.driver_data<mbc55x_state>();
+ mstate->m_debug_video=0;
+
+ logerror("VIDEO_START\n");
+
+ if (machine.debug_flags & DEBUG_FLAG_ENABLED)
+ {
+ debug_console_register_command(machine, "mbc55x_vid_debug", CMDFLAG_NONE, 0, 0, 1, video_debug);
+ }
+}
+
+VIDEO_RESET( mbc55x )
+{
+ mbc55x_state *mstate = machine.driver_data<mbc55x_state>();
+ // When we reset clear the video registers and video memory.
+ memset(&mstate->m_video_mem,0,sizeof(mstate->m_video_mem));
+
+ logerror("Video reset\n");
+}
+
+SCREEN_VBLANK( mbc55x )
+{
+// logerror("SCREEN_VBLANK( mbc55x )\n");
+}
diff --git a/src/mess/video/mbee.c b/src/mess/video/mbee.c
new file mode 100644
index 00000000000..be5e08c94db
--- /dev/null
+++ b/src/mess/video/mbee.c
@@ -0,0 +1,638 @@
+/***************************************************************************
+ microbee.c
+
+ video hardware
+ Juergen Buchmueller <pullmoll@t-online.de>, Dec 1999
+
+ Tests of keyboard. Start mbeeic.
+
+ 1. Load ASTEROIDS PLUS, stay in attract mode, hold down spacebar,
+ it should only fire bullets. If it sometimes starts turning,
+ thrusting or using the shield, then there is a problem.
+
+ 2. Load SCAVENGER and make sure it doesn't go to the next level
+ until you find the Exit.
+
+ 3. At the Basic prompt, type in EDASM press enter. At the memory size
+ prompt press enter. Now, make sure the keyboard works properly.
+
+
+
+ TODO:
+
+ 1. mbeeppc keyboard response is quite slow. You need to hold each
+ key until it responds. It works much better if you overclock the cpu.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "includes/mbee.h"
+
+
+/***********************************************************
+
+ The 6845 can produce a variety of cursor shapes - all
+ are emulated here.
+
+ Need to find out if the 6545 works the same way.
+
+************************************************************/
+
+void mbee_state::sy6545_cursor_configure()
+{
+ UINT8 i,curs_type=0,r9,r10,r11;
+
+ /* curs_type holds the general cursor shape to be created
+ 0 = no cursor
+ 1 = partial cursor (only shows on a block of scan lines)
+ 2 = full cursor
+ 3 = two-part cursor (has a part at the top and bottom with the middle blank) */
+
+ for ( i = 0; i < ARRAY_LENGTH(m_sy6545_cursor); i++) m_sy6545_cursor[i] = 0; // prepare cursor by erasing old one
+
+ r9 = m_sy6545_reg[9]; // number of scan lines - 1
+ r10 = m_sy6545_reg[10] & 0x1f; // cursor start line = last 5 bits
+ r11 = m_sy6545_reg[11]+1; // cursor end line incremented to suit for-loops below
+
+ /* decide the curs_type by examining the registers */
+ if (r10 < r11) curs_type=1; // start less than end, show start to end
+ else
+ if (r10 == r11) curs_type=2; // if equal, show full cursor
+ else curs_type=3; // if start greater than end, it's a two-part cursor
+
+ if ((r11 - 1) > r9) curs_type=2; // if end greater than scan-lines, show full cursor
+ if (r10 > r9) curs_type=0; // if start greater than scan-lines, then no cursor
+ if (r11 > 16) r11=16; // truncate 5-bit register to fit our 4-bit hardware
+
+ /* create the new cursor */
+ if (curs_type > 1) for (i = 0;i < ARRAY_LENGTH(m_sy6545_cursor);i++) m_sy6545_cursor[i]=0xff; // turn on full cursor
+
+ if (curs_type == 1) for (i = r10;i < r11;i++) m_sy6545_cursor[i]=0xff; // for each line that should show, turn on that scan line
+
+ if (curs_type == 3) for (i = r11; i < r10;i++) m_sy6545_cursor[i]=0; // now take a bite out of the middle
+}
+
+
+/***********************************************************
+
+ Handlers of video, colour, and attribute RAM
+
+************************************************************/
+
+
+READ8_MEMBER( mbee_state::mbee_low_r )
+{
+ if (m_0b & 1)
+ return m_p_gfxram[offset];
+ else
+ return m_p_videoram[offset];
+}
+
+WRITE8_MEMBER( mbee_state::mbee_low_w )
+{
+ m_p_videoram[offset] = data;
+}
+
+READ8_MEMBER( mbee_state::mbee_high_r )
+{
+ return m_p_gfxram[0x800 | offset];
+}
+
+WRITE8_MEMBER( mbee_state::mbee_high_w )
+{
+ m_p_gfxram[0x800 | offset] = data;
+}
+
+READ8_MEMBER( mbee_state::mbee_0b_r )
+{
+ return m_0b;
+}
+
+WRITE8_MEMBER( mbee_state::mbee_0b_w )
+{
+ m_0b = data;
+}
+
+READ8_MEMBER( mbee_state::mbeeic_08_r )
+{
+ return m_08;
+}
+
+WRITE8_MEMBER( mbee_state::mbeeic_08_w )
+{
+ m_08 = data;
+}
+
+READ8_MEMBER( mbee_state::mbeeic_high_r )
+{
+ if (m_08 & 0x40)
+ return m_p_colorram[offset];
+ else
+ return m_p_gfxram[0x800 | offset];
+}
+
+WRITE8_MEMBER( mbee_state::mbeeic_high_w )
+{
+ if ((m_08 & 0x40) && (~m_0b & 1))
+ m_p_colorram[offset] = data;
+ else
+ m_p_gfxram[0x0800 | offset] = data;
+}
+
+READ8_MEMBER( mbee_state::mbeeppc_1c_r )
+{
+ return m_1c;
+}
+
+WRITE8_MEMBER( mbee_state::mbeeppc_1c_w )
+{
+/* d7 extended graphics (1=allow attributes and pcg banks)
+ d5 bankswitch basic rom
+ d4 select attribute ram
+ d3..d0 select state->m_videoram bank */
+
+ m_1c = data;
+ membank("basic")->set_entry(BIT(data, 5));
+}
+
+WRITE8_MEMBER( mbee_state::mbee256_1c_w )
+{
+/* d7 extended graphics (1=allow attributes and pcg banks)
+ d5 bankswitch basic rom
+ d4 select attribute ram
+ d3..d0 select state->m_videoram bank */
+
+ m_1c = data;
+}
+
+READ8_MEMBER( mbee_state::mbeeppc_low_r )
+{
+ if ((m_1c & 0x1f) == 0x10)
+ return m_p_attribram[offset];
+ else
+ if (m_0b & 1)
+ return m_p_gfxram[offset];
+ else
+ return m_p_videoram[offset];
+}
+
+WRITE8_MEMBER( mbee_state::mbeeppc_low_w )
+{
+ if (m_1c & 16)
+ m_p_attribram[offset] = data;
+ else
+ m_p_videoram[offset] = data;
+}
+
+READ8_MEMBER( mbee_state::mbeeppc_high_r )
+{
+ if (m_08 & 0x40)
+ return m_p_colorram[offset];
+ else
+ return m_p_gfxram[(((m_1c & 15) + 1) << 11) | offset];
+}
+
+WRITE8_MEMBER ( mbee_state::mbeeppc_high_w )
+{
+ if ((m_08 & 0x40) && (~m_0b & 1))
+ m_p_colorram[offset] = data;
+ else
+ m_p_gfxram[(((m_1c & 15) + 1) << 11) | offset] = data;
+}
+
+
+/***********************************************************
+
+ CRTC-driven keyboard
+
+************************************************************/
+
+
+/* The direction keys are used by the pc85 menu. Do not know what uses the "insert" key. */
+void mbee_state::keyboard_matrix_r(int offs)
+{
+ char kbdrow[6];
+ UINT8 port = (offs >> 7) & 7;
+ UINT8 bit = (offs >> 4) & 7;
+ sprintf(kbdrow,"X%d",port);
+ UINT8 data = (ioport(kbdrow)->read() >> bit) & 1;
+
+ if ((data | m_is_premium) == 0)
+ {
+ UINT8 extra = ioport("EXTRA")->read();
+
+ if( extra & 0x01 ) /* extra: cursor up */
+ {
+ if( port == 7 && bit == 1 ) data = 1; /* Control */
+ if( port == 0 && bit == 5 ) data = 1; /* E */
+ }
+ else
+ if( extra & 0x02 ) /* extra: cursor down */
+ {
+ if( port == 7 && bit == 1 ) data = 1; /* Control */
+ if( port == 3 && bit == 0 ) data = 1; /* X */
+ }
+ else
+ if( extra & 0x04 ) /* extra: cursor left */
+ {
+ if( port == 7 && bit == 1 ) data = 1; /* Control */
+ if( port == 2 && bit == 3 ) data = 1; /* S */
+ }
+ else
+ if( extra & 0x08 ) /* extra: cursor right */
+ {
+ if( port == 7 && bit == 1 ) data = 1; /* Control */
+ if( port == 0 && bit == 4 ) data = 1; /* D */
+ }
+#if 0
+ // this key doesn't appear on any keyboard afaik
+ else
+ if( extra & 0x10 ) /* extra: insert */
+ {
+ if( port == 7 && bit == 1 ) data = 1; /* Control */
+ if( port == 2 && bit == 6 ) data = 1; /* V */
+ }
+#endif
+ }
+
+ if( data )
+ {
+ m_sy6545_reg[17] = offs;
+ m_sy6545_reg[16] = (offs >> 8) & 0x3f;
+ m_sy6545_status |= 0x40; //lpen_strobe
+ }
+}
+
+
+void mbee_state::mbee_video_kbd_scan( int param )
+{
+ if (m_0b) return;
+
+ keyboard_matrix_r(param);
+}
+
+
+/***********************************************************
+
+ CRTC registers
+
+************************************************************/
+
+READ8_MEMBER( mbee_state::m6545_status_r )
+{
+ screen_device *screen = machine().first_screen();
+ const rectangle &visarea = screen->visible_area();
+
+ UINT8 data = m_sy6545_status; // bit 6 = lpen strobe, bit 7 = update strobe
+ int y = machine().primary_screen->vpos();
+
+ if( y < visarea.min_y || y > visarea.max_y )
+ data |= 0x20; /* vertical blanking */
+
+ return data;
+}
+
+READ8_MEMBER( mbee_state::m6545_data_r )
+{
+ UINT16 addr;
+ UINT8 data = m_crtc->register_r( space, 0 );
+
+ switch( m_sy6545_ind )
+ {
+ case 16:
+ case 17:
+ m_sy6545_status &= 0x80; // turn off lpen_strobe
+ break;
+ case 31:
+ /* This firstly pushes the contents of the transparent registers onto the MA lines,
+ then increments the address, then sets update strobe on. */
+ addr = (m_sy6545_reg[18] << 8) | m_sy6545_reg[19];
+ keyboard_matrix_r(addr);
+ m_sy6545_reg[19]++;
+ if (!m_sy6545_reg[19]) m_sy6545_reg[18]++;
+ m_sy6545_status |= 0x80; // update_strobe
+ break;
+ }
+ return data;
+}
+
+WRITE8_MEMBER ( mbee_state::m6545_index_w )
+{
+ data &= 0x1f;
+ m_sy6545_ind = data;
+ m_crtc->address_w( space, 0, data );
+}
+
+WRITE8_MEMBER ( mbee_state::m6545_data_w )
+{
+ static const UINT8 sy6545_mask[32]={0xff,0xff,0xff,0x0f,0x7f,0x1f,0x7f,0x7f,3,0x1f,0x7f,0x1f,0x3f,0xff,0x3f,0xff,0,0,0x3f,0xff};
+ int addr = 0;
+
+ switch( m_sy6545_ind )
+ {
+ case 12:
+ data &= 0x3f; // select alternate character set
+ if( m_sy6545_reg[12] != data )
+ memcpy(m_p_gfxram, memregion("gfx")->base() + (((data & 0x30) == 0x20) << 11), 0x800);
+ break;
+ case 31:
+ /* This firstly pushes the contents of the transparent registers onto the MA lines,
+ then increments the address, then sets update strobe on. */
+ addr = (m_sy6545_reg[18] << 8) | m_sy6545_reg[19];
+ keyboard_matrix_r(addr);
+ m_sy6545_reg[19]++;
+ if (!m_sy6545_reg[19]) m_sy6545_reg[18]++;
+ m_sy6545_status |= 0x80; // update_strobe
+ break;
+ }
+ m_sy6545_reg[m_sy6545_ind] = data & sy6545_mask[m_sy6545_ind]; /* save data in register */
+ m_crtc->register_w( space, 0, data );
+ if ((m_sy6545_ind > 8) && (m_sy6545_ind < 12)) sy6545_cursor_configure(); /* adjust cursor shape - remove when mame fixed */
+}
+
+
+
+
+/***********************************************************
+
+ Video
+
+************************************************************/
+
+VIDEO_START( mbee )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ state->m_p_videoram = machine.root_device().memregion("videoram")->base();
+ state->m_p_gfxram = state->memregion("gfx")->base()+0x1000;
+ state->m_is_premium = 0;
+}
+
+VIDEO_START( mbeeic )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ state->m_p_videoram = machine.root_device().memregion("videoram")->base();
+ state->m_p_colorram = machine.root_device().memregion("colorram")->base();
+ state->m_p_gfxram = state->memregion("gfx")->base()+0x1000;
+ state->m_is_premium = 0;
+}
+
+VIDEO_START( mbeeppc )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ state->m_p_videoram = machine.root_device().memregion("videoram")->base();
+ state->m_p_colorram = machine.root_device().memregion("colorram")->base();
+ state->m_p_gfxram = machine.root_device().memregion("gfx")->base()+0x1000;
+ state->m_p_attribram = state->memregion("attrib")->base();
+ state->m_is_premium = 1;
+}
+
+SCREEN_UPDATE_RGB32( mbee )
+{
+ mbee_state *state = screen.machine().driver_data<mbee_state>();
+ state->m_framecnt++;
+ state->m_speed = state->m_sy6545_reg[10]&0x20, state->m_flash = state->m_sy6545_reg[10]&0x40; // cursor modes
+ state->m_cursor = (state->m_sy6545_reg[14]<<8) | state->m_sy6545_reg[15]; // get cursor position
+ state->m_crtc->screen_update(screen, bitmap, cliprect);
+ return 0;
+}
+
+
+MC6845_ON_UPDATE_ADDR_CHANGED( mbee_update_addr )
+{
+/* not sure what goes in here - parameters passed are device, address, strobe */
+}
+
+MC6845_ON_UPDATE_ADDR_CHANGED( mbee256_update_addr )
+{
+/* not used on 256TC */
+}
+
+
+/* monochrome bee */
+MC6845_UPDATE_ROW( mbee_update_row )
+{
+ mbee_state *state = device->machine().driver_data<mbee_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 chr,gfx;
+ UINT16 mem,x;
+ UINT32 *p = &bitmap.pix32(y);
+
+ for (x = 0; x < x_count; x++) // for each character
+ {
+ UINT8 inv=0;
+ mem = (ma + x) & 0x7ff;
+ chr = state->m_p_videoram[mem];
+
+ state->mbee_video_kbd_scan(x+ma);
+
+ /* process cursor */
+ if ((((!state->m_flash) && (!state->m_speed)) || // (5,6)=(0,0) = cursor on always
+ ((state->m_flash) && (state->m_speed) && (state->m_framecnt & 0x10)) || // (5,6)=(1,1) = cycle per 32 frames
+ ((state->m_flash) && (!state->m_speed) && (state->m_framecnt & 8))) && // (5,6)=(0,1) = cycle per 16 frames
+ (mem == state->m_cursor)) // displaying at cursor position?
+ inv ^= state->m_sy6545_cursor[ra]; // cursor scan row
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_gfxram[(chr<<4) | ra] ^ inv;
+
+ /* Display a scanline of a character (8 pixels) */
+ *p++ = palette[BIT(gfx, 7)];
+ *p++ = palette[BIT(gfx, 6)];
+ *p++ = palette[BIT(gfx, 5)];
+ *p++ = palette[BIT(gfx, 4)];
+ *p++ = palette[BIT(gfx, 3)];
+ *p++ = palette[BIT(gfx, 2)];
+ *p++ = palette[BIT(gfx, 1)];
+ *p++ = palette[BIT(gfx, 0)];
+ }
+}
+
+/* prom-based colours */
+MC6845_UPDATE_ROW( mbeeic_update_row )
+{
+ mbee_state *state = device->machine().driver_data<mbee_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 chr,gfx,fg,bg;
+ UINT16 mem,x,col;
+ UINT16 colourm = (state->m_08 & 0x0e) << 7;
+ UINT32 *p = &bitmap.pix32(y);
+
+ for (x = 0; x < x_count; x++) // for each character
+ {
+ UINT8 inv=0;
+ mem = (ma + x) & 0x7ff;
+ chr = state->m_p_videoram[mem];
+ col = state->m_p_colorram[mem] | colourm; // read a byte of colour
+
+ state->mbee_video_kbd_scan(x+ma);
+
+ /* process cursor */
+ if ((((!state->m_flash) && (!state->m_speed)) || // (5,6)=(0,0) = cursor on always
+ ((state->m_flash) && (state->m_speed) && (state->m_framecnt & 0x10)) || // (5,6)=(1,1) = cycle per 32 frames
+ ((state->m_flash) && (!state->m_speed) && (state->m_framecnt & 8))) && // (5,6)=(0,1) = cycle per 16 frames
+ (mem == state->m_cursor)) // displaying at cursor position?
+ inv ^= state->m_sy6545_cursor[ra]; // cursor scan row
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_gfxram[(chr<<4) | ra] ^ inv;
+ fg = (col & 0x001f) | 64; // map to foreground palette
+ bg = (col & 0x07e0) >> 5; // and background palette
+
+ /* Display a scanline of a character (8 pixels) */
+ *p++ = palette[BIT(gfx, 7) ? fg : bg];
+ *p++ = palette[BIT(gfx, 6) ? fg : bg];
+ *p++ = palette[BIT(gfx, 5) ? fg : bg];
+ *p++ = palette[BIT(gfx, 4) ? fg : bg];
+ *p++ = palette[BIT(gfx, 3) ? fg : bg];
+ *p++ = palette[BIT(gfx, 2) ? fg : bg];
+ *p++ = palette[BIT(gfx, 1) ? fg : bg];
+ *p++ = palette[BIT(gfx, 0) ? fg : bg];
+ }
+}
+
+
+/* new colours & hires2 */
+MC6845_UPDATE_ROW( mbeeppc_update_row )
+{
+ mbee_state *state = device->machine().driver_data<mbee_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 gfx,fg,bg;
+ UINT16 mem,x,col,chr;
+ UINT32 *p = &bitmap.pix32(y);
+
+ for (x = 0; x < x_count; x++) // for each character
+ {
+ UINT8 inv=0;
+ mem = (ma + x) & 0x7ff;
+ chr = state->m_p_videoram[mem];
+ col = state->m_p_colorram[mem]; // read a byte of colour
+
+ if (state->m_1c & 0x80) // are extended features enabled?
+ {
+ UINT8 attr = state->m_p_attribram[mem];
+
+ if (chr & 0x80)
+ chr += ((attr & 15) << 7); // bump chr to its particular pcg definition
+
+ if (attr & 0x40)
+ inv ^= 0xff; // inverse attribute
+
+ if ((attr & 0x80) && (state->m_framecnt & 0x10)) // flashing attribute
+ chr = 0x20;
+ }
+
+ state->mbee_video_kbd_scan(x+ma);
+
+ /* process cursor */
+ if ((((!state->m_flash) && (!state->m_speed)) || // (5,6)=(0,0) = cursor on always
+ ((state->m_flash) && (state->m_speed) && (state->m_framecnt & 0x10)) || // (5,6)=(1,1) = cycle per 32 frames
+ ((state->m_flash) && (!state->m_speed) && (state->m_framecnt & 8))) && // (5,6)=(0,1) = cycle per 16 frames
+ (mem == state->m_cursor)) // displaying at cursor position?
+ inv ^= state->m_sy6545_cursor[ra]; // cursor scan row
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_gfxram[(chr<<4) | ra] ^ inv;
+ fg = col & 15; // map to foreground palette
+ bg = (col & 0xf0) >> 4; // and background palette
+
+ /* Display a scanline of a character (8 pixels) */
+ *p++ = palette[BIT(gfx, 7) ? fg : bg];
+ *p++ = palette[BIT(gfx, 6) ? fg : bg];
+ *p++ = palette[BIT(gfx, 5) ? fg : bg];
+ *p++ = palette[BIT(gfx, 4) ? fg : bg];
+ *p++ = palette[BIT(gfx, 3) ? fg : bg];
+ *p++ = palette[BIT(gfx, 2) ? fg : bg];
+ *p++ = palette[BIT(gfx, 1) ? fg : bg];
+ *p++ = palette[BIT(gfx, 0) ? fg : bg];
+ }
+}
+
+
+/***********************************************************
+
+ Palette
+
+************************************************************/
+
+PALETTE_INIT( mbeeic )
+{
+ const UINT8 *color_prom = machine.root_device().memregion("proms")->base();
+ UINT16 i;
+ UINT8 r, b, g, k;
+ UINT8 level[] = { 0, 0x80, 0xff, 0xff }; /* off, half, full intensity */
+
+ /* set up background palette (00-63) */
+ for (i = 0; i < 64; i++)
+ {
+ r = level[((i>>0)&1)|((i>>2)&2)];
+ g = level[((i>>1)&1)|((i>>3)&2)];
+ b = level[((i>>2)&1)|((i>>4)&2)];
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+
+ /* set up foreground palette (64-95) by reading the prom */
+ for (i = 0; i < 32; i++)
+ {
+ k = color_prom[i];
+ r = level[((k>>2)&1)|((k>>4)&2)];
+ g = level[((k>>1)&1)|((k>>3)&2)];
+ b = level[((k>>0)&1)|((k>>2)&2)];
+ palette_set_color(machine, i|64, MAKE_RGB(r, g, b));
+ }
+}
+
+
+PALETTE_INIT( mbeepc85b )
+{
+ const UINT8 *color_prom = machine.root_device().memregion("proms")->base();
+ UINT16 i;
+ UINT8 r, b, g, k;
+ UINT8 level[] = { 0, 0x80, 0x80, 0xff }; /* off, half, full intensity */
+
+ /* set up background palette (00-63) */
+ for (i = 0; i < 64; i++)
+ {
+ r = level[((i>>0)&1)|((i>>2)&2)];
+ g = level[((i>>1)&1)|((i>>3)&2)];
+ b = level[((i>>2)&1)|((i>>4)&2)];
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+
+ level[2] = 0xff;
+
+ /* set up foreground palette (64-95) by reading the prom */
+ for (i = 0; i < 32; i++)
+ {
+ k = color_prom[i];
+ r = level[((k>>2)&1)|((k>>4)&2)];
+ g = level[((k>>1)&1)|((k>>3)&2)];
+ b = level[((k>>0)&1)|((k>>2)&2)];
+ palette_set_color(machine, i|64, MAKE_RGB(r, g, b));
+ }
+}
+
+
+PALETTE_INIT( mbeeppc )
+{
+ UINT16 i;
+ UINT8 r, b, g;
+
+ /* set up 8 low intensity colours */
+ for (i = 0; i < 8; i++)
+ {
+ r = (i & 1) ? 0xc0 : 0;
+ g = (i & 2) ? 0xc0 : 0;
+ b = (i & 4) ? 0xc0 : 0;
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+
+ /* set up 8 high intensity colours */
+ for (i = 9; i < 16; i++)
+ {
+ r = (i & 1) ? 0xff : 0;
+ g = (i & 2) ? 0xff : 0;
+ b = (i & 4) ? 0xff : 0;
+ palette_set_color(machine, i, MAKE_RGB(r, g, b));
+ }
+}
+
diff --git a/src/mess/video/mc68328.c b/src/mess/video/mc68328.c
new file mode 100644
index 00000000000..28fed90fbd6
--- /dev/null
+++ b/src/mess/video/mc68328.c
@@ -0,0 +1,66 @@
+/**********************************************************************
+
+ Motorola 68328 ("DragonBall") System-on-a-Chip LCD implementation
+
+ By MooglyGuy
+ contact mooglyguy@gmail.com with licensing and usage questions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "includes/mc68328.h"
+#include "machine/mc68328.h"
+#include "machine/ram.h"
+
+/* THIS IS PRETTY MUCH TOTALLY WRONG AND DOESN'T REFLECT THE MC68328'S INTERNAL FUNCTIONALITY AT ALL! */
+PALETTE_INIT( mc68328 )
+{
+ palette_set_color_rgb(machine, 0, 0x7b, 0x8c, 0x5a);
+ palette_set_color_rgb(machine, 1, 0x00, 0x00, 0x00);
+}
+
+VIDEO_START( mc68328 )
+{
+}
+
+/* THIS IS PRETTY MUCH TOTALLY WRONG AND DOESN'T REFLECT THE MC68328'S INTERNAL FUNCTIONALITY AT ALL! */
+SCREEN_UPDATE_IND16( mc68328 )
+{
+ device_t *mc68328_device = screen.machine().device(MC68328_TAG);
+ mc68328_t* mc68328 = mc68328_get_safe_token( mc68328_device );
+
+ const UINT16 *video_ram = (const UINT16 *)(screen.machine().device<ram_device>(RAM_TAG)->pointer() + (mc68328->regs.lssa & 0x00ffffff));
+ UINT16 word;
+ UINT16 *line;
+ int y, x, b;
+
+ if(mc68328->regs.lckcon & LCKCON_LCDC_EN)
+ {
+ for (y = 0; y < 160; y++)
+ {
+ line = &bitmap.pix16(y);
+
+ for (x = 0; x < 160; x += 16)
+ {
+ word = *(video_ram++);
+ for (b = 0; b < 16; b++)
+ {
+ line[x + b] = (word >> (15 - b)) & 0x0001;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (y = 0; y < 160; y++)
+ {
+ line = &bitmap.pix16(y);
+
+ for (x = 0; x < 160; x++)
+ {
+ line[x] = 0;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mess/video/mc6847.c b/src/mess/video/mc6847.c
new file mode 100644
index 00000000000..aa11a9a86a5
--- /dev/null
+++ b/src/mess/video/mc6847.c
@@ -0,0 +1,1627 @@
+/*********************************************************************
+
+ mc6847.c
+
+ Implementation of Motorola 6847 video hardware chip
+
+ Sources:
+ M6847 data sheet
+ M6847T1 info from Rainbow magazine (10/1986-12/1986)
+
+
+ AG AS INTEXT INV GM2 GM1 GM0
+ -- -- ------ --- --- --- ---
+ 0 0 0 0 X X X Internal Alphanumerics
+ 0 0 0 1 X X X Internal Alphanumerics Inverted
+ 0 0 1 0 X X X External Alphanumerics
+ 0 0 1 1 X X X External Alphanumerics Inverted
+ 0 1 0 X X X X Semigraphics 4
+ 0 1 1 X X X X Semigraphics 6
+ 1 X X X 0 0 0 Graphics CG1 (64x64x4) (16 bpr)
+ 1 X X X 0 0 1 Graphics RG1 (128x64x2) (16 bpr)
+ 1 X X X 0 1 0 Graphics CG2 (128x64x4) (32 bpr)
+ 1 X X X 0 1 1 Graphics RG2 (128x96x2) (16 bpr)
+ 1 X X X 1 0 0 Graphics CG3 (128x96x4) (32 bpr)
+ 1 X X X 1 0 1 Graphics RG3 (128x192x2) (16 bpr)
+ 1 X X X 1 1 0 Graphics CG6 (128x192x4) (32 bpr)
+ 1 X X X 1 1 1 Graphics RG6 (256x192x2) (32 bpr)
+
+ Note: The M6847 relies on an external source (typically a 6883 SAM chip)
+ to feed it bytes; so the BPR (bytes per row) figures are effectively
+ suggestions. Mismatching modes is responsible for the semigraphic modes
+ on the CoCo.
+
+ Timing:
+ (source Motorola M6847 Manual)
+
+ Horizontal Sync: Total Period: 227.5 clock cycles
+ @ CLK(0) + DHS_F - falling edge (high to low)
+ @ CLK(16.5) + DHS_R - rising edge (low to high)
+ @ CLK(42) - left border start
+ @ CLK(71.5) - body start
+ @ CLK(199.5) - right border start
+ @ CLK(227.5) + DHS_F - falling edge (high to low)
+ ...
+
+ Field Sync: Total Period 262*227.5 clock cycles
+ @ CLK(0) + DFS_F - falling edge (high to low)
+ @ CLK(32*227.5) + DFS_R - rising edge (low to high)
+ @ CLK(262*227.5) + DFS_F - falling edge (high to low) (262.5 for the M6847Y)
+
+ DHS_F: 550ns
+ DHS_R: 740ns
+ DFS_F: 520ns
+ DFS_R: 500ns
+
+ The M6847T1 is a later variant of the M6847 chip that implements lower
+ case support and some other nifty features. This chip is in the CoCo 2B.
+ I have not been able to find a pinout diagram for this chip so I am
+ assuming that the extra text modes on the CoCo 2B are activated by the
+ GM2-0 pins. This needs to be confirmed.
+
+**********************************************************************/
+
+
+#include "emu.h"
+#include "video/mc6847.h"
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define TOP_BORDER 25
+#define USE_HORIZONTAL_CLIP false
+
+#define TIMER_HSYNC_PERIOD (227.5)
+#define TIMER_HSYNC_OFF_TIME (10.0)
+#define TIMER_HSYNC_ON_TIME (TIMER_HSYNC_OFF_TIME + 16.5)
+#define TIMER_FSYNC_OFF_TIME (TIMER_HSYNC_PERIOD * TOP_BORDER + TIMER_HSYNC_ON_TIME)
+#define TIMER_FSYNC_ON_TIME (TIMER_HSYNC_PERIOD * (TOP_BORDER + 192) + TIMER_HSYNC_ON_TIME)
+
+#define LOG_SCANLINE 0
+#define LOG_HSYNC 0
+#define LOG_FSYNC 0
+
+
+const UINT32 mc6847_base_device::s_palette[mc6847_base_device::PALETTE_LENGTH] =
+{
+ MAKE_RGB(0x07, 0xff, 0x00), /* GREEN */
+ MAKE_RGB(0xff, 0xff, 0x00), /* YELLOW */
+ MAKE_RGB(0x3b, 0x08, 0xff), /* BLUE */
+ MAKE_RGB(0xcc, 0x00, 0x3b), /* RED */
+ MAKE_RGB(0xff, 0xff, 0xff), /* BUFF */
+ MAKE_RGB(0x07, 0xe3, 0x99), /* CYAN */
+ MAKE_RGB(0xff, 0x1c, 0xff), /* MAGENTA */
+ MAKE_RGB(0xff, 0x81, 0x00), /* ORANGE */
+
+ MAKE_RGB(0x00, 0x00, 0x00), /* BLACK */
+ MAKE_RGB(0x07, 0xff, 0x00), /* GREEN */
+ MAKE_RGB(0x00, 0x00, 0x00), /* BLACK */
+ MAKE_RGB(0xff, 0xff, 0xff), /* BUFF */
+
+ MAKE_RGB(0x00, 0x7c, 0x00), /* ALPHANUMERIC DARK GREEN */
+ MAKE_RGB(0x07, 0xff, 0x00), /* ALPHANUMERIC BRIGHT GREEN */
+ MAKE_RGB(0x91, 0x00, 0x00), /* ALPHANUMERIC DARK ORANGE */
+ MAKE_RGB(0xff, 0x81, 0x00) /* ALPHANUMERIC BRIGHT ORANGE */
+};
+
+
+
+//**************************************************************************
+// FRIEND DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+mc6847_friend_device::mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,
+ const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ m_character_map(fontdata, is_mc6847t1)
+{
+ m_tpfs = tpfs;
+
+ // The MC6847 and the GIME apply field sync on different scanlines
+ m_field_sync_falling_edge_scanline = field_sync_falling_edge_scanline;
+}
+
+
+
+//-------------------------------------------------
+// setup_timer - sets up a single timer relative
+// to the clock
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE emu_timer *mc6847_friend_device::setup_timer(device_timer_id id, double offset, double period)
+{
+ emu_timer *timer = timer_alloc(id);
+ timer->adjust(
+ attotime::from_ticks(offset * 4, m_clock * 4),
+ 0,
+ attotime::from_ticks(period * 4, m_clock * 4));
+ return timer;
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc6847_friend_device::device_start(void)
+{
+ /* create the timers */
+ m_frame_timer = setup_timer( TIMER_FRAME, 0, m_tpfs * TIMER_HSYNC_PERIOD);
+ m_hsync_on_timer = setup_timer( TIMER_HSYNC_ON, TIMER_HSYNC_ON_TIME, TIMER_HSYNC_PERIOD);
+ m_hsync_off_timer = setup_timer(TIMER_HSYNC_OFF, TIMER_HSYNC_OFF_TIME, TIMER_HSYNC_PERIOD);
+ m_fsync_timer = timer_alloc(TIMER_FSYNC);
+
+ m_top_border_scanlines = 0;
+ m_body_scanlines = 0;
+ m_wide = false;
+ set_geometry(25, 192, false);
+
+ /* save states */
+ save_item(NAME(m_physical_scanline));
+ save_item(NAME(m_logical_scanline));
+ save_item(NAME(m_logical_scanline_zone));
+ save_item(NAME(m_horizontal_sync));
+ save_item(NAME(m_field_sync));
+
+ /* artifacting */
+ m_artifacter.setup_config(this);
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific reset
+//-------------------------------------------------
+
+void mc6847_friend_device::device_reset(void)
+{
+ device_t::device_reset();
+ m_video_changed = true;
+}
+
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post load
+//-------------------------------------------------
+
+void mc6847_friend_device::device_post_load(void)
+{
+ device_t::device_post_load();
+ m_video_changed = true;
+}
+
+
+
+//-------------------------------------------------
+// update_field_sync_timer
+//-------------------------------------------------
+
+void mc6847_friend_device::update_field_sync_timer(void)
+{
+ /* are we expecting field sync? */
+ bool expected_field_sync = (m_physical_scanline < m_field_sync_falling_edge_scanline)
+ || (m_logical_scanline_zone == SCANLINE_ZONE_VBLANK);
+
+ /* determine the duration */
+ attotime duration = (expected_field_sync != m_field_sync) ? attotime::from_ticks(160, m_clock) : attotime::never;
+
+ /* and reset the timer */
+ m_fsync_timer->adjust(duration, expected_field_sync ? 1 : 0);
+}
+
+
+
+//-------------------------------------------------
+// device_timer
+//-------------------------------------------------
+
+void mc6847_friend_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_FRAME: new_frame(); break;
+ case TIMER_HSYNC_ON: change_horizontal_sync(true); break;
+ case TIMER_HSYNC_OFF: change_horizontal_sync(false); break;
+ case TIMER_FSYNC: change_field_sync(param != 0); break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// new_frame
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void mc6847_friend_device::new_frame(void)
+{
+ m_physical_scanline = 0;
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_FRAME_END;
+}
+
+
+
+//-------------------------------------------------
+// scanline_zone_string
+//-------------------------------------------------
+
+const char *mc6847_friend_device::scanline_zone_string(scanline_zone zone)
+{
+ const char *result;
+ switch(zone)
+ {
+ case SCANLINE_ZONE_TOP_BORDER: result = "SCANLINE_ZONE_TOP_BORDER"; break;
+ case SCANLINE_ZONE_BODY: result = "SCANLINE_ZONE_BODY"; break;
+ case SCANLINE_ZONE_BOTTOM_BORDER: result = "SCANLINE_ZONE_BOTTOM_BORDER"; break;
+ case SCANLINE_ZONE_RETRACE: result = "SCANLINE_ZONE_RETRACE"; break;
+ case SCANLINE_ZONE_VBLANK: result = "SCANLINE_ZONE_VBLANK"; break;
+ case SCANLINE_ZONE_FRAME_END: result = "SCANLINE_ZONE_FRAME_END"; break;
+ default:
+ fatalerror("Should not get here");
+ break;
+ }
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// change_horizontal_sync
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void mc6847_friend_device::change_horizontal_sync(bool line)
+{
+ g_profiler.start(PROFILER_USER1);
+ if (line && !m_horizontal_sync)
+ {
+ if (LOG_SCANLINE)
+ logerror("%s: change_horizontal_sync(): Recording scanline\n", describe_context());
+
+ /* first store the scanline */
+ g_profiler.start(PROFILER_USER2);
+ switch((scanline_zone) m_logical_scanline_zone)
+ {
+ case SCANLINE_ZONE_TOP_BORDER:
+ case SCANLINE_ZONE_BOTTOM_BORDER:
+ record_border_scanline(m_physical_scanline);
+ break;
+
+ case SCANLINE_ZONE_BODY:
+ record_body_scanline(m_physical_scanline, m_logical_scanline);
+ break;
+
+ case SCANLINE_ZONE_RETRACE:
+ case SCANLINE_ZONE_VBLANK:
+ case SCANLINE_ZONE_FRAME_END:
+ /* do nothing */
+ break;
+ }
+ g_profiler.stop();
+
+ /* advance to next scanline */
+ next_scanline();
+ }
+
+ /* finally output horizontal sync */
+ if (line != m_horizontal_sync)
+ {
+ m_horizontal_sync = line;
+
+ /* log if apprpriate */
+ if (LOG_HSYNC)
+ logerror("%s: change_horizontal_sync(): line=%d\n", describe_context(), line ? 1 : 0);
+
+ /* invoke callback */
+ if (!m_res_out_hsync_func.isnull())
+ m_res_out_hsync_func(line);
+
+ /* call virtual function */
+ horizontal_sync_changed(m_horizontal_sync);
+ }
+
+ /* and update the field sync timer */
+ update_field_sync_timer();
+ g_profiler.stop();
+}
+
+
+
+//-------------------------------------------------
+// change_field_sync
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void mc6847_friend_device::change_field_sync(bool line)
+{
+ /* output field sync */
+ if (line != m_field_sync)
+ {
+ m_field_sync = line;
+
+ /* log if apprpriate */
+ if (LOG_FSYNC)
+ logerror("%s: change_field_sync(): line=%d\n", describe_context(), line ? 1 : 0);
+
+ /* invoke callback */
+ if (!m_res_out_fsync_func.isnull())
+ m_res_out_fsync_func(line);
+
+ /* call virtual function */
+ field_sync_changed(m_field_sync);
+ }
+}
+
+
+
+//-------------------------------------------------
+// next_scanline
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE void mc6847_friend_device::next_scanline(void)
+{
+ /* advance to next scanline */
+ m_physical_scanline++;
+ m_logical_scanline++;
+
+ /* check for movement into the next "zone" */
+ if (m_logical_scanline_zone == SCANLINE_ZONE_FRAME_END)
+ {
+ /* we're now in the top border */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_TOP_BORDER;
+ }
+ else if ((m_logical_scanline_zone < SCANLINE_ZONE_VBLANK) && (m_physical_scanline >= 25+192+26+6))
+ {
+ /* we're now into vblank */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_VBLANK;
+ }
+ else if ((m_logical_scanline_zone < SCANLINE_ZONE_RETRACE) && (m_physical_scanline >= 25+192+26))
+ {
+ /* we're now into retrace */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_RETRACE;
+ }
+ else if ((m_logical_scanline_zone == SCANLINE_ZONE_TOP_BORDER) && (m_logical_scanline >= m_top_border_scanlines))
+ {
+ /* we're now into the body */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_BODY;
+ }
+ else if ((m_logical_scanline_zone == SCANLINE_ZONE_BODY) && (m_logical_scanline >= m_body_scanlines))
+ {
+ /* we're now into the bottom border */
+ m_logical_scanline = 0;
+ m_logical_scanline_zone = SCANLINE_ZONE_BOTTOM_BORDER;
+ enter_bottom_border();
+ }
+}
+
+
+
+//-------------------------------------------------
+// horizontal_sync_changed
+//-------------------------------------------------
+
+void mc6847_friend_device::horizontal_sync_changed(bool line)
+{
+}
+
+
+
+//-------------------------------------------------
+// field_sync_changed
+//-------------------------------------------------
+
+void mc6847_friend_device::field_sync_changed(bool line)
+{
+}
+
+
+
+//-------------------------------------------------
+// enter_bottom_border
+//-------------------------------------------------
+
+void mc6847_friend_device::enter_bottom_border(void)
+{
+}
+
+
+
+//-------------------------------------------------
+// record_border_scanline
+//-------------------------------------------------
+
+void mc6847_friend_device::record_border_scanline(UINT16 physical_scanline)
+{
+}
+
+
+
+//-------------------------------------------------
+// video_flush
+//-------------------------------------------------
+
+void mc6847_friend_device::video_flush(void)
+{
+}
+
+
+
+//-------------------------------------------------
+// describe_context
+//-------------------------------------------------
+
+const char *mc6847_friend_device::describe_context(void)
+{
+ static char buffer[128];
+ snprintf(buffer, ARRAY_LENGTH(buffer), "%s (scanline %s:%d)",
+ machine().describe_context(),
+ scanline_zone_string((scanline_zone) m_logical_scanline_zone),
+ m_logical_scanline);
+ return buffer;
+}
+
+
+
+//**************************************************************************
+// BASE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+mc6847_base_device::mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs)
+ : mc6847_friend_device(mconfig, type, name, tag, owner, clock, fontdata, (type == MC6847T1_NTSC) || (type == MC6847T1_PAL), tpfs, 25+191)
+{
+ m_palette = s_palette;
+
+ for (int i = 0; i < ARRAY_LENGTH(s_palette); i++)
+ {
+ m_bw_palette[i] = black_and_white(s_palette[i]);
+ }
+}
+
+
+
+//-------------------------------------------------
+// setup_fixed_mode - sets up a particular video
+// mode bit with a decb callback
+//-------------------------------------------------
+
+void mc6847_base_device::setup_fixed_mode(struct devcb_read_line callback, UINT8 mode)
+{
+ if (callback.type == DEVCB_TYPE_NULL)
+ {
+ // do nothing
+ }
+ else if (callback.type == DEVCB_TYPE_CONSTANT && (callback.index == 0 || callback.index == 1))
+ {
+ // this mode is fixed
+ m_fixed_mode |= (callback.index ? mode : 0x00);
+ m_fixed_mode_mask |= mode;
+ }
+ else
+ {
+ // for reasons of performance, we currently only support DEVCB_NULL,
+ // DEVCB_LINE_GND and DEVCB_LINE_VCC
+ emu_fatalerror("mc6847 does not support this callback type for mode bits");
+ }
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc6847_base_device::device_start()
+{
+ const mc6847_interface *config = (const mc6847_interface *) static_config();
+ assert(config);
+
+ /* inherited function */
+ mc6847_friend_device::device_start();
+
+ /* setup */
+ memset(m_data, 0, sizeof(m_data));
+
+ /* resolve callbacks */
+ m_res_input_func.resolve(config->m_input_func, *this);
+ m_res_out_hsync_func.resolve(config->m_out_hsync_func, *this);
+ m_res_out_fsync_func.resolve(config->m_out_fsync_func, *this);
+ m_get_char_rom = config->m_get_char_rom;
+
+ /* set up fixed mode */
+ m_fixed_mode = 0x00;
+ m_fixed_mode_mask = 0x00;
+ setup_fixed_mode(config->m_in_gm2_func, MODE_GM2);
+ setup_fixed_mode(config->m_in_gm1_func, MODE_GM1);
+ setup_fixed_mode(config->m_in_gm0_func, MODE_GM0);
+ setup_fixed_mode(config->m_in_intext_func, MODE_INTEXT);
+ setup_fixed_mode(config->m_in_inv_func, MODE_INV);
+ setup_fixed_mode(config->m_in_as_func, MODE_AS);
+ setup_fixed_mode(config->m_in_ag_func, MODE_AG);
+ setup_fixed_mode(config->m_in_css_func, MODE_CSS);
+
+ /* state save */
+ save_item(NAME(m_dirty));
+ save_item(NAME(m_mode));
+
+ /* colors */
+ m_palette = config->m_black_and_white ? m_bw_palette : s_palette;
+}
+
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mc6847_base_device::device_reset()
+{
+ mc6847_friend_device::device_reset();
+ m_mode = m_fixed_mode;
+}
+
+
+
+//-------------------------------------------------
+// record_scanline_res
+//-------------------------------------------------
+
+template<int sample_count, int yres>
+void mc6847_base_device::record_scanline_res(int scanline)
+{
+ int i, column;
+ UINT8 data;
+
+ /* calculate offset */
+ offs_t offset = scanline / (192 / yres) * sample_count;
+
+ /* main loop */
+ for (column = 0; column < sample_count; column++)
+ {
+ /* input data */
+ data = m_res_input_func(offset++);
+
+ /* update values */
+ update_value(&m_data[scanline].m_mode[column], simplify_mode(data, m_mode));
+ update_value(&m_data[scanline].m_data[column], data);
+ }
+
+ /* several more inputs occur after hblank */
+ for (i = 0; i < sample_count * 5 / 16; i++)
+ {
+ data = m_res_input_func(offset++);
+ }
+
+ /* update sample count */
+ update_value(&m_data[scanline].m_sample_count, (UINT8) sample_count);
+}
+
+
+
+//-------------------------------------------------
+// record_body_scanline
+//-------------------------------------------------
+
+void mc6847_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 scanline)
+{
+ // sanity checks
+ assert(scanline < 192);
+
+ if (m_mode & MODE_AG)
+ {
+ switch(m_mode & (MODE_GM2|MODE_GM1|MODE_GM0))
+ {
+ case 0:
+ case MODE_GM0:
+ record_scanline_res<16, 64>(scanline);
+ break;
+
+ case MODE_GM1:
+ record_scanline_res<32, 64>(scanline);
+ break;
+
+ case MODE_GM1|MODE_GM0:
+ record_scanline_res<16, 96>(scanline);
+ break;
+
+ case MODE_GM2:
+ record_scanline_res<32, 96>(scanline);
+ break;
+
+ case MODE_GM2|MODE_GM0:
+ record_scanline_res<16, 192>(scanline);
+ break;
+
+ case MODE_GM2|MODE_GM1:
+ case MODE_GM2|MODE_GM1|MODE_GM0:
+ record_scanline_res<32, 192>(scanline);
+ break;
+
+ default:
+ /* should not get here */
+ fatalerror("should not get here");
+ break;
+ }
+ }
+ else
+ {
+ record_scanline_res<32, 16>(scanline);
+ }
+}
+
+
+
+//-------------------------------------------------
+// field_sync_changed
+//-------------------------------------------------
+
+void mc6847_base_device::field_sync_changed(bool line)
+{
+ /* when field sync is on, the DA* enter the Hi-Z state */
+ if (line && !m_res_input_func.isnull())
+ m_res_input_func(~0);
+}
+
+
+
+//-------------------------------------------------
+// border_value
+//-------------------------------------------------
+
+ATTR_FORCE_INLINE mc6847_base_device::pixel_t mc6847_base_device::border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1)
+{
+ pixel_t result;
+ switch(mc6847_friend_device::border_value(mode, is_mc6847t1))
+ {
+ case BORDER_COLOR_BLACK:
+ result = palette[8];
+ break;
+ case BORDER_COLOR_GREEN:
+ result = palette[0];
+ break;
+ case BORDER_COLOR_WHITE:
+ result = palette[4];
+ break;
+ case BORDER_COLOR_ORANGE:
+ result = palette[7];
+ break;
+ default:
+ fatalerror("Should not get here");
+ break;
+ }
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// update
+//-------------------------------------------------
+
+UINT32 mc6847_base_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ int base_x = 32;
+ int base_y = 25;
+ int x, x2, y;
+ bool is_mc6847t1 = (type() == MC6847T1_NTSC) || (type() == MC6847T1_PAL);
+ int min_x = USE_HORIZONTAL_CLIP ? cliprect.min_x : 0;
+ int max_x = USE_HORIZONTAL_CLIP ? cliprect.max_x : (base_x * 2 + 256 - 1);
+ int min_y = cliprect.min_y;
+ int max_y = cliprect.max_y;
+ const pixel_t *palette = m_palette;
+
+ /* if the video didn't change, indicate as much */
+ if (!has_video_changed())
+ return UPDATE_HAS_NOT_CHANGED;
+
+ /* top border */
+ for (y = min_y; y < base_y; y++)
+ {
+ for (x = min_x; x <= max_x; x++)
+ {
+ *bitmap_addr(bitmap, y, x) = border_value(m_data[0].m_mode[0], palette, is_mc6847t1);
+ }
+ }
+
+ for (y = MAX(0, min_y - base_y); y <= MIN(192, max_y - base_y); y++)
+ {
+ /* left border */
+ for (x = min_x; x < base_x; x++)
+ {
+ *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[0], palette, is_mc6847t1);
+ }
+
+ /* body */
+ x = 0;
+ int width = m_data[y].m_sample_count;
+ pixel_t *RESTRICT pixels = bitmap_addr(bitmap, base_y + y, base_x);
+ while(x < width)
+ {
+ /* determine how many bytes exist for which the mode is identical */
+ for (x2 = x + 1; (x2 < width) && (m_data[y].m_mode[x] == m_data[y].m_mode[x2]); x2++)
+ ;
+
+ /* emit the samples */
+ pixels += emit_mc6847_samples<1>(
+ m_data[y].m_mode[x],
+ &m_data[y].m_data[x],
+ x2 - x,
+ pixels,
+ m_palette,
+ m_get_char_rom,
+ x,
+ y);
+
+ /* update x */
+ x = x2;
+ }
+
+ /* right border */
+ for (x = base_x + 256; x <= max_x; x++)
+ {
+ *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[width - 1], palette, is_mc6847t1);
+ }
+
+ /* artifacting */
+ m_artifacter.process_artifacts<1>(bitmap_addr(bitmap, y + base_y, base_x), m_data[y].m_mode[0], palette);
+ }
+
+ /* bottom border */
+ for (y = base_y + 192; y <= max_y; y++)
+ {
+ for (x = min_x; x <= max_x; x++)
+ {
+ int width = m_data[191].m_sample_count;
+ *bitmap_addr(bitmap, y, x) = border_value(m_data[191].m_mode[width - 1], palette, is_mc6847t1);
+ }
+ }
+ return 0;
+}
+
+
+
+//**************************************************************************
+// CHARACTER MAP
+//**************************************************************************
+
+mc6847_friend_device::character_map::character_map(const UINT8 *text_fontdata, bool is_mc6847t1)
+{
+ int mode, i;
+
+ // set up font data
+ for (i = 0; i < 64*12; i++)
+ {
+ m_text_fontdata_inverse[i] = text_fontdata[i] ^ 0xFF;
+ m_text_fontdata_lower_case[i] = text_fontdata[i + (i < 32*12 ? 64*12 : 0)] ^ (i < 32*12 ? 0xFF : 0x00);
+ m_text_fontdata_lower_case_inverse[i] = m_text_fontdata_lower_case[i] ^ 0xFF;
+ }
+
+ // loop through all modes
+ for (mode = 0; mode < sizeof(m_entries) / sizeof(m_entries[0]); mode++)
+ {
+ const UINT8 *fontdata;
+ UINT8 character_mask;
+ UINT8 color_shift_0 = 0;
+ UINT8 color_shift_1 = 0;
+ UINT8 color_mask_0 = 0x00;
+ UINT8 color_mask_1 = 0x00;
+ UINT16 color_base_0;
+ UINT16 color_base_1;
+
+ if ((mode & MODE_INTEXT) && !is_mc6847t1)
+ {
+ // semigraphics 6
+ fontdata = semigraphics6_fontdata8x12;
+ character_mask = 0x3F;
+ color_base_0 = 8;
+ color_base_1 = mode & MODE_CSS ? 4 : 0;
+ color_shift_1 = 6;
+ color_mask_1 = 0x03;
+ }
+ else if (mode & MODE_AS)
+ {
+ // semigraphics 4
+ fontdata = semigraphics4_fontdata8x12;
+ character_mask = 0x0F;
+ color_base_0 = 8;
+ color_base_1 = 0;
+ color_shift_1 = 4;
+ color_mask_1 = 0x07;
+ }
+ else
+ {
+ // text
+ bool is_lower_case = is_mc6847t1 && ((mode & MODE_INV) == 0) && (mode & MODE_GM0);
+ bool is_inverse1 = (mode & MODE_INV) ? true : false;
+ bool is_inverse2 = is_mc6847t1 && (mode & MODE_GM1);
+ bool is_inverse = (is_inverse1 && !is_inverse2) || (!is_inverse1 && is_inverse2);
+ fontdata = is_inverse
+ ? (is_lower_case ? m_text_fontdata_lower_case_inverse : m_text_fontdata_inverse)
+ : (is_lower_case ? m_text_fontdata_lower_case : text_fontdata);
+ character_mask = 0x3F;
+ color_base_0 = (mode & MODE_CSS ? 14 : 12);
+ color_base_1 = (mode & MODE_CSS ? 15 : 13);
+ }
+
+ // populate the entry
+ memset(&m_entries[mode], 0, sizeof(m_entries[mode]));
+ m_entries[mode].m_fontdata = fontdata;
+ m_entries[mode].m_character_mask = character_mask;
+ m_entries[mode].m_color_shift_0 = color_shift_0;
+ m_entries[mode].m_color_shift_1 = color_shift_1;
+ m_entries[mode].m_color_mask_0 = color_mask_0;
+ m_entries[mode].m_color_mask_1 = color_mask_1;
+ m_entries[mode].m_color_base_0 = color_base_0;
+ m_entries[mode].m_color_base_1 = color_base_1;
+ }
+}
+
+
+
+//-------------------------------------------------
+// pal_round_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::pal_round_fontdata8x12[] =
+{
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+
+ /* Lower case */
+ 0x00, 0x00, 0x18, 0x24, 0x20, 0x70, 0x20, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00
+};
+
+
+
+//-------------------------------------------------
+// pal_square_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::pal_square_fontdata8x12[] =
+{
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00,
+
+ /* Lower case */
+ 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00,
+};
+
+
+
+//-------------------------------------------------
+// ntsc_round_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::ntsc_round_fontdata8x12[] =
+{
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+
+ /* Lower case */
+ 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00,
+};
+
+
+
+//-------------------------------------------------
+// ntsc_square_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::ntsc_square_fontdata8x12[] =
+{
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x04, 0x02, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00,
+
+ /* Lower case */
+ 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18,
+ 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00
+};
+
+
+
+//-------------------------------------------------
+// semigraphics4_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::semigraphics4_fontdata8x12[] =
+{
+ /* Block Graphics (Semigraphics 4 Graphics ) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+
+
+//-------------------------------------------------
+// semigraphics6_fontdata8x12
+//-------------------------------------------------
+
+const UINT8 mc6847_friend_device::semigraphics6_fontdata8x12[] =
+{
+ /* Semigraphics 6 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+
+
+//**************************************************************************
+// ARTIFACTING
+//**************************************************************************
+
+INPUT_PORTS_START(mc6847_artifacting)
+ PORT_START(ARTIFACTING_TAG)
+ PORT_CONFNAME( 0x03, 0x01, "Artifacting" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x01, DEF_STR( Standard ) )
+ PORT_CONFSETTING( 0x02, DEF_STR( Reverse ) )
+INPUT_PORTS_END
+
+ioport_constructor mc6847_base_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(mc6847_artifacting);
+}
+
+
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+mc6847_base_device::artifacter::artifacter()
+{
+ m_config = NULL;
+ m_artifacting = 0;
+ m_saved_artifacting = 0;
+ m_saved_c0 = 0;
+ m_saved_c1 = 0;
+ memset(m_expanded_colors, 0, sizeof(m_expanded_colors));
+}
+
+
+
+//-------------------------------------------------
+// artifacter::setup_config
+//-------------------------------------------------
+
+void mc6847_base_device::artifacter::setup_config(device_t *device)
+{
+ char port_name[32];
+ snprintf(port_name, ARRAY_LENGTH(port_name), "%s:%s", device->tag(), ARTIFACTING_TAG);
+ m_config = device->ioport(port_name);
+}
+
+
+
+//-------------------------------------------------
+// artifacter::update_colors
+//-------------------------------------------------
+
+void mc6847_base_device::artifacter::update_colors(pixel_t c0, pixel_t c1)
+{
+ /* Boy this code sucks; this code was adapted from the old M6847
+ * artifacting implmentation. The only reason that it didn't look as
+ * horrible was because the code around it sucked as well. Now that I
+ * have cleaned everything up, the ugliness is much more prominent.
+ *
+ * Hopefully we will have a generic artifacting algorithm that plugs into
+ * the MESS/MAME core directly so we can chuck this hack */
+ static const double artifact_colors[14*3] =
+ {
+ 0.157, 0.000, 0.157, /* [ 1] - dk purple (reverse 2) */
+ 0.000, 0.157, 0.000, /* [ 2] - dk green (reverse 1) */
+ 1.000, 0.824, 1.000, /* [ 3] - lt purple (reverse 4) */
+ 0.824, 1.000, 0.824, /* [ 4] - lt green (reverse 3) */
+ 0.706, 0.236, 0.118, /* [ 5] - dk blue (reverse 6) */
+ 0.000, 0.197, 0.471, /* [ 6] - dk red (reverse 5) */
+ 1.000, 0.550, 0.393, /* [ 7] - lt blue (reverse 8) */
+ 0.275, 0.785, 1.000, /* [ 8] - lt red (reverse 7) */
+ 0.000, 0.500, 1.000, /* [ 9] - red (reverse 10) */
+ 1.000, 0.500, 0.000, /* [10] - blue (reverse 9) */
+ 1.000, 0.942, 0.785, /* [11] - cyan (reverse 12) */
+ 0.393, 0.942, 1.000, /* [12] - yellow (reverse 11) */
+ 0.236, 0.000, 0.000, /* [13] - black-blue (reverse 14) */
+ 0.000, 0.000, 0.236 /* [14] - black-red (reverse 13) */
+ };
+
+ static const UINT8 artifact_correction[128] =
+ {
+ 0, 0, 0, 0, 0, 6, 0, 2,
+ 5, 7, 5, 7, 1, 3, 1, 11,
+ 8, 6, 8, 14, 8, 9, 8, 9,
+ 4, 4, 4, 15, 12, 12, 12, 15,
+
+ 5, 13, 5, 13, 13, 0, 13, 2,
+ 10, 10, 10, 10, 10, 15, 10, 11,
+ 3, 1, 3, 1, 15, 9, 15, 9,
+ 11, 11, 11, 11, 15, 15, 15, 15,
+
+ 14, 0, 14, 0, 14, 6, 14, 2,
+ 0, 7, 0, 7, 1, 3, 1, 11,
+ 9, 6, 9, 14, 9, 9, 9, 9,
+ 15, 4, 15, 15, 12, 12, 12, 15,
+
+ 2, 13, 2, 13, 2, 0, 2, 2,
+ 10, 10, 10, 10, 10, 15, 10, 11,
+ 12, 1, 12, 1, 12, 9, 12, 9,
+ 15, 11, 15, 11, 15, 15, 15, 15
+ };
+
+ pixel_t colors[16];
+ int i;
+
+ /* do we need to update our artifact colors table? */
+ if ((m_artifacting != m_saved_artifacting) || (c0 != m_saved_c0) || (c1 != m_saved_c1))
+ {
+ m_saved_artifacting = m_artifacting;
+ m_saved_c0 = colors[0] = c0;
+ m_saved_c1 = colors[15] = c1;
+
+ /* mix the other colors */
+ for (i = 1; i <= 14; i++)
+ {
+ const double *factors = &artifact_colors[((i - 1) ^ (m_artifacting & 0x01)) * 3];
+
+ colors[i] = (mix_color(factors[0], c0 >> 16, c1 >> 16) << 16)
+ | (mix_color(factors[1], c0 >> 8, c1 >> 8) << 8)
+ | (mix_color(factors[2], c0 >> 0, c1 >> 0) << 0);
+ }
+ for (i = 0; i < 128; i++)
+ {
+ m_expanded_colors[i] = colors[artifact_correction[i]];
+ }
+ }
+}
+
+
+
+//-------------------------------------------------
+// artifacter::update
+//-------------------------------------------------
+
+mc6847_base_device::pixel_t mc6847_base_device::artifacter::mix_color(double factor, UINT8 c0, UINT8 c1)
+{
+ return (UINT32) (UINT8) ((c0 * (1.0 - factor)) + (c1 * (0.0 + factor)) + 0.5);
+}
+
+
+
+//**************************************************************************
+// VARIATIONS
+//**************************************************************************
+
+const device_type MC6847_NTSC = &device_creator<mc6847_ntsc_device>;
+const device_type MC6847_PAL = &device_creator<mc6847_pal_device>;
+const device_type MC6847Y_NTSC = &device_creator<mc6847y_ntsc_device>;
+const device_type MC6847Y_PAL = &device_creator<mc6847y_pal_device>;
+const device_type MC6847T1_NTSC = &device_creator<mc6847t1_ntsc_device>;
+const device_type MC6847T1_PAL = &device_creator<mc6847t1_pal_device>;
+
+
+
+//-------------------------------------------------
+// mc6847_ntsc_device
+//-------------------------------------------------
+
+mc6847_ntsc_device::mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847_NTSC, "MC6847_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 227.0)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847_pal_device
+//-------------------------------------------------
+
+mc6847_pal_device::mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847_PAL, "MC6847_PAL", tag, owner, clock, pal_square_fontdata8x12, 227.0)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847y_ntsc_device
+//-------------------------------------------------
+
+mc6847y_ntsc_device::mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847Y_NTSC, "MC6847Y_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 227.5)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847y_pal_device
+//-------------------------------------------------
+
+mc6847y_pal_device::mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847Y_PAL, "MC6847Y_PAL", tag, owner, clock, pal_square_fontdata8x12, 227.5)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847t1_ntsc_device
+//-------------------------------------------------
+
+mc6847t1_ntsc_device::mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847T1_NTSC, "MC6847T1_NTSC", tag, owner, clock, ntsc_round_fontdata8x12, 227.0)
+{
+}
+
+
+
+//-------------------------------------------------
+// mc6847t1_pal_device
+//-------------------------------------------------
+
+mc6847t1_pal_device::mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : mc6847_base_device(mconfig, MC6847T1_PAL, "MC6847T1_PAL", tag, owner, clock, pal_round_fontdata8x12, 227.0)
+{
+}
+
+
+
diff --git a/src/mess/video/mc6847.h b/src/mess/video/mc6847.h
new file mode 100644
index 00000000000..71f2d476f15
--- /dev/null
+++ b/src/mess/video/mc6847.h
@@ -0,0 +1,631 @@
+/*********************************************************************
+
+ mc6847.h
+
+ Implementation of Motorola 6847 video hardware chip
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __MC6847__
+#define __MC6847__
+
+
+//**************************************************************************
+// MC6847 CONFIGURATION / INTERFACE
+//**************************************************************************
+
+#define MCFG_MC6847_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_MC6847_ADD(_tag, _variant, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, _variant, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define MCFG_SCREEN_MC6847_NTSC_ADD(_tag, _mctag) \
+ MCFG_SCREEN_ADD(_tag, RASTER) \
+ MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \
+ MCFG_SCREEN_REFRESH_RATE(60) \
+ MCFG_SCREEN_SIZE(320, 243) \
+ MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \
+ MCFG_SCREEN_VBLANK_TIME(0) \
+
+#define MCFG_SCREEN_MC6847_PAL_ADD(_tag, _mctag) \
+ MCFG_SCREEN_ADD(_tag, RASTER) \
+ MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \
+ MCFG_SCREEN_REFRESH_RATE(50) \
+ MCFG_SCREEN_SIZE(320, 243) \
+ MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \
+ MCFG_SCREEN_VBLANK_TIME(0) \
+
+/* interface */
+typedef struct _mc6847_interface mc6847_interface;
+struct _mc6847_interface
+{
+ /* screen we are acting on */
+ const char *m_screen_tag;
+
+ /* if specified, this gets called whenever reading a byte (offs_t ~0 specifies DA* entering the tristate mode) */
+ devcb_read8 m_input_func;
+
+ /* if specified, this gets called for every change of the HS pin (pin 38) */
+ devcb_write_line m_out_hsync_func;
+
+ /* if specified, this gets called for every change of the FS pin (pin 37) */
+ devcb_write_line m_out_fsync_func;
+
+ /* mode control lines input */
+ devcb_read_line m_in_ag_func;
+ devcb_read_line m_in_gm2_func;
+ devcb_read_line m_in_gm1_func;
+ devcb_read_line m_in_gm0_func;
+ devcb_read_line m_in_css_func;
+ devcb_read_line m_in_as_func;
+ devcb_read_line m_in_intext_func;
+ devcb_read_line m_in_inv_func;
+
+ /* if specified, this reads the external char rom off of the driver state */
+ UINT8 (*m_get_char_rom)(running_machine &machine, UINT8 ch, int line);
+
+ /* if true, this is black and white */
+ bool m_black_and_white;
+};
+
+#define ARTIFACTING_TAG "artifacting"
+
+INPUT_PORTS_EXTERN(mc6847_artifacting);
+
+
+//**************************************************************************
+// MC6847 CORE
+//**************************************************************************
+
+PALETTE_INIT( mc6847 );
+PALETTE_INIT( mc6847_bw );
+
+// base class so that the GIME emulation can access mc6847 stuff
+class mc6847_friend_device : public device_t
+{
+public:
+ // inlines
+ bool hs_r(void) { return m_horizontal_sync; }
+ bool fs_r(void) { return m_field_sync; }
+
+protected:
+ mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,
+ const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline);
+
+ // video mode constants
+ static const UINT8 MODE_AG = 0x80;
+ static const UINT8 MODE_GM2 = 0x40;
+ static const UINT8 MODE_GM1 = 0x20;
+ static const UINT8 MODE_GM0 = 0x10;
+ static const UINT8 MODE_CSS = 0x08;
+ static const UINT8 MODE_AS = 0x04;
+ static const UINT8 MODE_INTEXT = 0x02;
+ static const UINT8 MODE_INV = 0x01;
+
+ // timer constants
+ static const device_timer_id TIMER_FRAME = 0;
+ static const device_timer_id TIMER_HSYNC_OFF = 1;
+ static const device_timer_id TIMER_HSYNC_ON = 2;
+ static const device_timer_id TIMER_FSYNC = 3;
+
+ // fonts
+ static const UINT8 pal_round_fontdata8x12[];
+ static const UINT8 pal_square_fontdata8x12[];
+ static const UINT8 ntsc_round_fontdata8x12[];
+ static const UINT8 ntsc_square_fontdata8x12[];
+ static const UINT8 semigraphics4_fontdata8x12[];
+ static const UINT8 semigraphics6_fontdata8x12[];
+
+ // pixel definitions
+ typedef UINT32 pixel_t;
+
+ pixel_t *bitmap_addr(bitmap_rgb32 &bitmap, int y, int x)
+ {
+ return &bitmap.pix32(y, x);
+ }
+
+ static UINT8 simplify_mode(UINT8 data, UINT8 mode)
+ {
+ // simplifies MC6847 modes to drop mode flags that are not significant
+ return mode & ~((mode & MODE_AG) ? (MODE_AS | MODE_INV) : 0);
+ }
+
+ // internal class that represents a MC6847 character map
+ class character_map
+ {
+ public:
+ // constructor that sets up the font data
+ character_map(const UINT8 *fontdata, bool is_mc6847t1);
+
+ // optimized template function that emits a single character
+ template<int xscale>
+ ATTR_FORCE_INLINE void emit_character(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, int y, const pixel_t *palette)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ // get the character
+ UINT8 character = data[i];
+
+ // based on the mode, determine which entry to use
+ const entry *e = &m_entries[mode % (sizeof(m_entries) / sizeof(m_entries[0]))];
+
+ // identify the character in the font data
+ const UINT8 *font_character = e->m_fontdata + (character & e->m_character_mask) * 12;
+
+ // get the particular slice out
+ UINT8 font_character_slice = font_character[y % 12];
+
+ // get the two colors
+ UINT16 color_base_0 = e->m_color_base_0 + ((character >> e->m_color_shift_0) & e->m_color_mask_0);
+ UINT16 color_base_1 = e->m_color_base_1 + ((character >> e->m_color_shift_1) & e->m_color_mask_1);
+ pixel_t color_0 = palette[color_base_0];
+ pixel_t color_1 = palette[color_base_1];
+
+ // emit the bits
+ for (int j = 0; j < 8; j++)
+ {
+ for (int k = 0; k < xscale; k++)
+ {
+ pixels[(i * 8 + j) * xscale + k] = bit_test(font_character_slice, j, color_0, color_1);
+ }
+ }
+ }
+ };
+
+ private:
+ struct entry
+ {
+ const UINT8 *m_fontdata;
+ UINT8 m_character_mask;
+ UINT8 m_color_shift_0;
+ UINT8 m_color_shift_1;
+ UINT8 m_color_mask_0;
+ UINT8 m_color_mask_1;
+ UINT16 m_color_base_0;
+ UINT16 m_color_base_1;
+ };
+
+ // lookup table for MC6847 modes to determine font data and color
+ entry m_entries[128];
+
+ // text font data calculated on startup
+ UINT8 m_text_fontdata_inverse[64*12];
+ UINT8 m_text_fontdata_lower_case[64*12];
+ UINT8 m_text_fontdata_lower_case_inverse[64*12];
+
+ // optimized function that tests a single bit
+ ATTR_FORCE_INLINE pixel_t bit_test(UINT8 data, int shift, pixel_t color_0, pixel_t color_1)
+ {
+ return data & (0x80 >> shift) ? color_1 : color_0;
+ }
+ };
+
+ // artficater internal class
+ class artifacter
+ {
+ public:
+ artifacter();
+
+ // artifacting config
+ void setup_config(device_t *device);
+ void poll_config(void) { m_artifacting = (m_config!=NULL) ? m_config->read() : 0; }
+
+ // artifacting application
+ template<int xscale>
+ ATTR_FORCE_INLINE void process_artifacts(pixel_t *pixels, UINT8 mode, const pixel_t *palette)
+ {
+ if (((mode & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) == (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0))
+ && (m_artifacting != 0))
+ {
+ // identify the new colors and update
+ pixel_t c0 = palette[(mode & MODE_CSS) ? 10 : 8];
+ pixel_t c1 = palette[(mode & MODE_CSS) ? 11 : 9];
+ update_colors(c0, c1);
+
+ // generate the new line
+ pixel_t new_line[256];
+ int x, i;
+ for (x = 0; x < 256; x += 2)
+ {
+ UINT8 val = ((pixels[(x - 2) * xscale] == c1) ? 0x20 : 0x00)
+ | ((pixels[(x - 1) * xscale] == c1) ? 0x10 : 0x00)
+ | ((pixels[(x + 0) * xscale] == c1) ? 0x08 : 0x00)
+ | ((pixels[(x + 1) * xscale] == c1) ? 0x04 : 0x00)
+ | ((pixels[(x + 2) * xscale] == c1) ? 0x02 : 0x00)
+ | ((pixels[(x + 3) * xscale] == c1) ? 0x01 : 0x00);
+
+ new_line[x + 0] = m_expanded_colors[val * 2 + 0];
+ new_line[x + 1] = m_expanded_colors[val * 2 + 1];
+ }
+
+ // and copy it in
+ for (x = 0; x < 256; x++)
+ {
+ for (i = 0; i < xscale; i++)
+ pixels[x * xscale + i] = new_line[x];
+ }
+ }
+ }
+
+ private:
+ ioport_port *m_config;
+ ioport_value m_artifacting;
+ ioport_value m_saved_artifacting;
+ pixel_t m_saved_c0, m_saved_c1;
+ pixel_t m_expanded_colors[128];
+
+ void update_colors(pixel_t c0, pixel_t c1);
+ static pixel_t mix_color(double factor, UINT8 c0, UINT8 c1);
+ };
+
+ typedef enum
+ {
+ BORDER_COLOR_BLACK,
+ BORDER_COLOR_GREEN,
+ BORDER_COLOR_WHITE,
+ BORDER_COLOR_ORANGE
+ } border_color_t;
+
+ // callbacks
+ devcb_resolved_write_line m_res_out_hsync_func;
+ devcb_resolved_write_line m_res_out_fsync_func;
+
+ // incidentals
+ character_map m_character_map;
+ artifacter m_artifacter;
+
+ // device-level overrides
+ virtual void device_start(void);
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_reset(void);
+ virtual void device_post_load(void);
+
+ // other overridables
+ virtual void new_frame(void);
+ virtual void horizontal_sync_changed(bool line);
+ virtual void field_sync_changed(bool line);
+ virtual void enter_bottom_border(void);
+ virtual void record_border_scanline(UINT16 physical_scanline);
+ virtual void record_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline) = 0;
+
+ // miscellaneous
+ void video_flush(void);
+ const char *describe_context(void);
+
+ // setup functions
+ emu_timer *setup_timer(device_timer_id id, double offset, double period);
+
+ // converts to B&W
+ static pixel_t black_and_white(pixel_t color)
+ {
+ UINT8 average_color = (RGB_RED(color) + RGB_GREEN(color) + RGB_BLUE(color)) / 3;
+ return MAKE_RGB(average_color, average_color, average_color);
+ }
+
+ // changes the geometry
+ ATTR_FORCE_INLINE void set_geometry(UINT16 top_border_scanlines, UINT16 body_scanlines, bool wide)
+ {
+ if (UNEXPECTED((m_top_border_scanlines != top_border_scanlines)
+ || (m_body_scanlines != body_scanlines)
+ || (m_wide != wide)))
+ {
+ m_top_border_scanlines = top_border_scanlines;
+ m_body_scanlines = body_scanlines;
+ m_wide = wide;
+ update_field_sync_timer();
+ }
+ }
+
+ // calculates the border color
+ static ATTR_FORCE_INLINE border_color_t border_value(UINT8 mode, bool is_mc6847t1)
+ {
+ border_color_t result;
+
+ if (mode & MODE_AG)
+ {
+ // graphics
+ result = mode & MODE_CSS ? BORDER_COLOR_WHITE : BORDER_COLOR_GREEN;
+ }
+ else if (!is_mc6847t1 || ((mode & MODE_GM2) == 0))
+ {
+ // text, black border
+ result = BORDER_COLOR_BLACK;
+ }
+ else
+ {
+ // text, green or orange border
+ result = mode & MODE_CSS ? BORDER_COLOR_ORANGE : BORDER_COLOR_GREEN;
+ }
+ return result;
+ }
+
+ // checks to see if the video has changed
+ ATTR_FORCE_INLINE bool has_video_changed(void)
+ {
+ /* poll the artifacting config */
+ m_artifacter.poll_config();
+
+ /* if the video didn't change, indicate as much */
+ bool video_changed = m_video_changed;
+ m_video_changed = false;
+ return video_changed;
+ }
+
+ // updates a byte in the video state
+ template<class T>
+ ATTR_FORCE_INLINE bool update_value(T *ptr, T byte)
+ {
+ bool result = false;
+ if (*ptr != byte)
+ {
+ *ptr = byte;
+ m_video_changed = true;
+ result = true;
+ }
+ return result;
+ };
+
+ // template function for emitting graphics bytes
+ template<int bits_per_pixel, int xscale>
+ ATTR_FORCE_INLINE void emit_graphics(const UINT8 *data, int length, pixel_t *RESTRICT pixels, UINT16 color_base, const pixel_t *RESTRICT palette)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ for (int j = 0; j < (8 / bits_per_pixel); j++)
+ {
+ for (int k = 0; k < xscale; k++)
+ {
+ UINT16 color = color_base + ((data[i] >> (8 - (j + 1) * bits_per_pixel)) & ((1 << bits_per_pixel) - 1));
+ pixels[(i * (8 / bits_per_pixel) + j) * xscale + k] = palette[color];
+ }
+ }
+ }
+ }
+
+ // template function for emitting samples
+ template<int xscale>
+ UINT32 emit_mc6847_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, const pixel_t *RESTRICT palette,
+ UINT8 (*get_char_rom)(running_machine &machine, UINT8 ch, int line), int x, int y)
+ {
+ UINT32 result = 0;
+ if (mode & MODE_AG)
+ {
+ /* graphics */
+ switch(mode & (MODE_GM2|MODE_GM1|MODE_GM0))
+ {
+ case 0:
+ emit_graphics<2, xscale * 4>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette);
+ result = length * 8 * xscale * 2;
+ break;
+
+ case MODE_GM0:
+ case MODE_GM1|MODE_GM0:
+ case MODE_GM2|MODE_GM0:
+ emit_graphics<1, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette);
+ result = length * 8 * xscale * 2;
+ break;
+
+ case MODE_GM1:
+ case MODE_GM2:
+ case MODE_GM2|MODE_GM1:
+ emit_graphics<2, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette);
+ result = length * 8 * xscale;
+ break;
+
+ case MODE_GM2|MODE_GM1|MODE_GM0:
+ emit_graphics<1, xscale * 1>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette);
+ result = length * 8 * xscale;
+ break;
+
+ default:
+ /* should not get here */
+ fatalerror("Should not get here");
+ break;
+ }
+ }
+ else if ((get_char_rom != NULL) && ((mode & (MODE_AG|MODE_AS|MODE_INTEXT)) == MODE_INTEXT))
+ {
+ /* external ROM */
+ for (int i = 0; i < length; i++)
+ {
+ UINT8 byte = get_char_rom(machine(), data[i], y % 12) ^ (mode & MODE_INV ? 0xFF : 0x00);
+ emit_graphics<2, xscale * 2>(&byte, 1, &pixels[i * 8], (mode & MODE_CSS) ? 14 : 12, palette);
+ }
+ result = length * 8 * xscale;
+ }
+ else
+ {
+ /* text/semigraphics */
+ m_character_map.emit_character<xscale>(mode, data, length, pixels, y, palette);
+ result = length * 8 * xscale;
+ }
+ return result;
+ }
+
+
+private:
+ enum scanline_zone
+ {
+ SCANLINE_ZONE_TOP_BORDER,
+ SCANLINE_ZONE_BODY,
+ SCANLINE_ZONE_BOTTOM_BORDER,
+ SCANLINE_ZONE_RETRACE,
+ SCANLINE_ZONE_VBLANK,
+ SCANLINE_ZONE_FRAME_END
+ };
+
+ // timers
+ emu_timer *m_frame_timer;
+ emu_timer *m_hsync_on_timer;
+ emu_timer *m_hsync_off_timer;
+ emu_timer *m_fsync_timer;
+
+ // incidentals
+ double m_tpfs;
+ int m_field_sync_falling_edge_scanline;
+ bool m_wide;
+ bool m_video_changed;
+ UINT16 m_top_border_scanlines;
+ UINT16 m_body_scanlines;
+
+ // video state
+ UINT16 m_physical_scanline;
+ UINT16 m_logical_scanline;
+ UINT16 m_logical_scanline_zone;
+ bool m_horizontal_sync;
+ bool m_field_sync;
+
+ // functions
+ void change_horizontal_sync(bool line);
+ void change_field_sync(bool line);
+ void update_field_sync_timer(void);
+ void next_scanline(void);
+
+ // debugging
+ const char *scanline_zone_string(scanline_zone zone);
+};
+
+// actual base class for MC6847 family of devices
+class mc6847_base_device : public mc6847_friend_device
+{
+public:
+ /* updates the screen -- this will call begin_update(),
+ followed by update_row() reapeatedly and after all row
+ updating is complete, end_update() */
+ UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ // mode changing operations
+ DECLARE_WRITE_LINE_MEMBER( ag_w ) { change_mode(MODE_AG, state); }
+ DECLARE_WRITE_LINE_MEMBER( gm2_w ) { change_mode(MODE_GM2, state); }
+ DECLARE_WRITE_LINE_MEMBER( gm1_w ) { change_mode(MODE_GM1, state); }
+ DECLARE_WRITE_LINE_MEMBER( gm0_w ) { change_mode(MODE_GM0, state); }
+ DECLARE_WRITE_LINE_MEMBER( as_w ) { change_mode(MODE_AS, state); }
+ DECLARE_WRITE_LINE_MEMBER( css_w ) { change_mode(MODE_CSS, state); }
+ DECLARE_WRITE_LINE_MEMBER( intext_w ) { change_mode(MODE_INTEXT, state); }
+ DECLARE_WRITE_LINE_MEMBER( inv_w ) { change_mode(MODE_INV, state); }
+
+protected:
+ mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual ioport_constructor device_input_ports() const;
+
+ // other overrides
+ virtual void field_sync_changed(bool line);
+
+private:
+ struct video_scanline
+ {
+ UINT8 m_sample_count;
+ UINT8 m_mode[32];
+ UINT8 m_data[32];
+ };
+
+ // palette
+ static const int PALETTE_LENGTH = 16;
+ static const UINT32 s_palette[PALETTE_LENGTH];
+
+ // callbacks
+ devcb_resolved_read8 m_res_input_func;
+ UINT8 (*m_get_char_rom)(running_machine &machine, UINT8 ch, int line);
+
+ // incidentals
+ UINT8 m_fixed_mode;
+ UINT8 m_fixed_mode_mask;
+ const pixel_t *m_palette;
+ pixel_t m_bw_palette[PALETTE_LENGTH];
+
+ // state
+ UINT8 m_mode;
+ video_scanline m_data[192];
+ bool m_dirty;
+
+ void change_mode(UINT8 mode, int state)
+ {
+ /* sanity check, to ensure that we're not changing fixed modes */
+ assert((mode & m_fixed_mode_mask) == 0);
+
+ if (!m_dirty)
+ {
+ video_flush();
+ m_dirty = true;
+ }
+
+ if (state)
+ m_mode |= mode;
+ else
+ m_mode &= ~mode;
+ }
+
+ // setup functions
+ void setup_fixed_mode(struct devcb_read_line callback, UINT8 mode);
+
+ // runtime functions
+ virtual void record_body_scanline(UINT16 physical_scanline, UINT16 scanline);
+ pixel_t border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1);
+
+ template<int xscale>
+ void emit_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *pixels, int x, int y);
+
+ // template function for doing video update collection
+ template<int sample_count, int yres>
+ void record_scanline_res(int scanline);
+};
+
+
+//**************************************************************************
+// VARIATIONS
+//**************************************************************************
+
+class mc6847_ntsc_device : public mc6847_base_device
+{
+public:
+ mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847_pal_device : public mc6847_base_device
+{
+public:
+ mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847y_ntsc_device : public mc6847_base_device
+{
+public:
+ mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847y_pal_device : public mc6847_base_device
+{
+public:
+ mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847t1_ntsc_device : public mc6847_base_device
+{
+public:
+ mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class mc6847t1_pal_device : public mc6847_base_device
+{
+public:
+ mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+extern const device_type MC6847_NTSC;
+extern const device_type MC6847_PAL;
+extern const device_type MC6847Y_NTSC;
+extern const device_type MC6847Y_PAL;
+extern const device_type MC6847T1_NTSC;
+extern const device_type MC6847T1_PAL;
+
+#endif /* __MC6847__ */
+
diff --git a/src/mess/video/mc80.c b/src/mess/video/mc80.c
new file mode 100644
index 00000000000..c327ef229da
--- /dev/null
+++ b/src/mess/video/mc80.c
@@ -0,0 +1,174 @@
+/***************************************************************************
+
+ MC-80.xx video by Miodrag Milanovic
+
+ 15/05/2009 Initial implementation
+ 12/05/2009 Skeleton driver.
+
+****************************************************************************/
+
+#include "includes/mc80.h"
+
+// This is not a content of U402 510
+// but order is fine
+
+static const UINT8 prom[] = {
+ 0x0c,0x11,0x13,0x15,0x17,0x10,0x0e,0x00, // @
+ 0x04,0x0a,0x11,0x11,0x1f,0x11,0x11,0x00, // A
+ 0x1e,0x11,0x11,0x1e,0x11,0x11,0x1e,0x00, // B
+ 0x0e,0x11,0x10,0x10,0x10,0x11,0x0e,0x00, // C
+ 0x1e,0x09,0x09,0x09,0x09,0x09,0x1e,0x00, // D
+ 0x1f,0x10,0x10,0x1e,0x10,0x10,0x1f,0x00, // E
+ 0x1f,0x10,0x10,0x1e,0x10,0x10,0x10,0x00, // F
+ 0x0e,0x11,0x10,0x10,0x13,0x11,0x0f,0x00, // G
+
+ 0x11,0x11,0x11,0x1f,0x11,0x11,0x11,0x00, // H
+ 0x0e,0x04,0x04,0x04,0x04,0x04,0x0e,0x00, // I
+ 0x01,0x01,0x01,0x01,0x11,0x11,0x0e,0x00, // J
+ 0x11,0x12,0x14,0x18,0x14,0x12,0x11,0x00, // K
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x1f,0x00, // L
+ 0x11,0x1b,0x15,0x15,0x11,0x11,0x11,0x00, // M
+ 0x11,0x11,0x19,0x15,0x13,0x11,0x11,0x00, // N
+ 0x0e,0x11,0x11,0x11,0x11,0x11,0x0e,0x00, // O
+
+ 0x1e,0x11,0x11,0x1e,0x10,0x10,0x10,0x00, // P
+ 0x0e,0x11,0x11,0x11,0x15,0x12,0x0d,0x00, // Q
+ 0x1e,0x11,0x11,0x1e,0x14,0x12,0x11,0x00, // R
+ 0x0e,0x11,0x10,0x0e,0x01,0x11,0x0e,0x00, // S
+ 0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x00, // T
+ 0x11,0x11,0x11,0x11,0x11,0x11,0x0e,0x00, // U
+ 0x11,0x11,0x11,0x0a,0x0a,0x04,0x04,0x00, // V
+ 0x11,0x11,0x11,0x15,0x15,0x15,0x0a,0x00, // W
+
+ 0x11,0x11,0x0a,0x04,0x0a,0x11,0x11,0x00, // X
+ 0x11,0x11,0x0a,0x04,0x04,0x04,0x04,0x00, // Y
+ 0x1f,0x01,0x02,0x04,0x08,0x10,0x1f,0x00, // Z
+ 0x1c,0x10,0x10,0x10,0x10,0x10,0x1c,0x00, // [
+ 0x00,0x10,0x08,0x04,0x02,0x01,0x00,0x00, // backslash
+ 0x07,0x01,0x01,0x01,0x01,0x01,0x07,0x00, // ]
+ 0x0e,0x11,0x00,0x00,0x00,0x00,0x00,0x00, // ^
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00, // _
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
+ 0x04,0x04,0x04,0x04,0x04,0x00,0x04,0x00, // !
+ 0x0a,0x0a,0x0a,0x00,0x00,0x00,0x00,0x00, // "
+ 0x0a,0x0a,0x1f,0x0a,0x1f,0x0a,0x0a,0x00, // #
+ 0x00,0x11,0x0e,0x0a,0x0e,0x11,0x00,0x00, // []
+ 0x18,0x19,0x02,0x04,0x08,0x13,0x03,0x00, // %
+ 0x04,0x0a,0x0a,0x0c,0x15,0x12,0x0d,0x00, // &
+ 0x04,0x04,0x08,0x00,0x00,0x00,0x00,0x00, // '
+
+ 0x02,0x04,0x08,0x08,0x08,0x04,0x02,0x00, // (
+ 0x08,0x04,0x02,0x02,0x02,0x04,0x08,0x00, // )
+ 0x00,0x04,0x15,0x0e,0x15,0x04,0x00,0x00, // *
+ 0x00,0x04,0x04,0x1f,0x04,0x04,0x00,0x00, // +
+ 0x00,0x00,0x00,0x00,0x08,0x08,0x10,0x00, // ,
+ 0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00, // -
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00, // .
+ 0x00,0x01,0x02,0x04,0x08,0x10,0x00,0x00, // /
+
+ 0x0e,0x11,0x13,0x15,0x19,0x11,0x0e,0x00, // 0
+ 0x04,0x0c,0x04,0x04,0x04,0x04,0x0e,0x00, // 1
+ 0x0e,0x11,0x01,0x06,0x08,0x10,0x1f,0x00, // 2
+ 0x1f,0x01,0x02,0x06,0x01,0x11,0x0e,0x00, // 3
+ 0x02,0x06,0x0a,0x12,0x1f,0x02,0x02,0x00, // 4
+ 0x1f,0x10,0x1e,0x01,0x01,0x11,0x0e,0x00, // 5
+ 0x07,0x08,0x10,0x1e,0x11,0x11,0x0e,0x00, // 6
+ 0x1f,0x01,0x02,0x04,0x08,0x08,0x08,0x00, // 7
+
+ 0x0e,0x11,0x11,0x0e,0x11,0x11,0x0e,0x00, // 8
+ 0x0e,0x11,0x11,0x0f,0x01,0x02,0x1c,0x00, // 9
+ 0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00, // :
+ 0x00,0x00,0x04,0x00,0x04,0x04,0x08,0x00, // ;
+ 0x02,0x04,0x08,0x10,0x08,0x04,0x02,0x00, // <
+ 0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00, // =
+ 0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00, // >
+ 0x0e,0x11,0x01,0x02,0x04,0x00,0x04,0x00 // ?
+};
+
+/*****************************************************************************/
+/* Implementation for MC80.2x */
+/*****************************************************************************/
+
+
+
+VIDEO_START( mc8020 )
+{
+}
+
+SCREEN_UPDATE_IND16( mc8020 )
+{
+ mc80_state *state = screen.machine().driver_data<mc80_state>();
+ UINT8 y,ra,chr,gfx;
+ UINT16 sy=0,ma=0,x;
+
+ for(y = 0; y < 8; y++ )
+ {
+ for (ra = 0; ra < 16; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 32; x++)
+ {
+ if (ra > 3 && ra < 12)
+ {
+ chr = state->m_p_videoram[x];
+ gfx = prom[(chr<<3) | (ra-4)];
+ }
+ else
+ gfx = 0;
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=32;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* Implementation for MC80.3x */
+/*****************************************************************************/
+
+
+VIDEO_START( mc8030 )
+{
+ mc80_state *state = machine.driver_data<mc80_state>();
+ state->m_p_videoram.set_target(state->memregion("vram")->base(),state->m_p_videoram.bytes());
+}
+
+SCREEN_UPDATE_IND16( mc8030 )
+{
+ mc80_state *state = screen.machine().driver_data<mc80_state>();
+ UINT8 gfx;
+ UINT16 y=0,ma=0,x;
+
+ for(y = 0; y < 256; y++ )
+ {
+ UINT16 *p = &bitmap.pix16(y);
+ {
+ for (x = ma; x < ma + 64; x++)
+ {
+ gfx = state->m_p_videoram[x^0x3fff];
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=64;
+ }
+ return 0;
+}
diff --git a/src/mess/video/microtan.c b/src/mess/video/microtan.c
new file mode 100644
index 00000000000..7f8a9a429c4
--- /dev/null
+++ b/src/mess/video/microtan.c
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * Microtan 65
+ *
+ * video hardware
+ *
+ * Juergen Buchmueller <pullmoll@t-online.de>, Jul 2000
+ *
+ * Thanks go to Geoff Macdonald <mail@geoff.org.uk>
+ * for his site http:://www.geo255.redhotant.com
+ * and to Fabrice Frances <frances@ensica.fr>
+ * for his site http://www.ifrance.com/oric/microtan.html
+ *
+ ***************************************************************************/
+
+#include "emu.h"
+#include "includes/microtan.h"
+
+
+
+
+WRITE8_MEMBER(microtan_state::microtan_videoram_w)
+{
+ UINT8 *videoram = m_videoram;
+ if ((videoram[offset] != data) || (m_chunky_buffer[offset] != m_chunky_graphics))
+ {
+ videoram[offset] = data;
+ m_bg_tilemap->mark_tile_dirty(offset);
+ m_chunky_buffer[offset] = m_chunky_graphics;
+ }
+}
+
+static TILE_GET_INFO(get_bg_tile_info)
+{
+ microtan_state *state = machine.driver_data<microtan_state>();
+ UINT8 *videoram = state->m_videoram;
+ int gfxn = state->m_chunky_buffer[tile_index];
+ int code = videoram[tile_index];
+
+ SET_TILE_INFO(gfxn, code, 0, 0);
+}
+
+VIDEO_START( microtan )
+{
+ microtan_state *state = machine.driver_data<microtan_state>();
+ state->m_bg_tilemap = tilemap_create(machine, get_bg_tile_info, tilemap_scan_rows,
+ 8, 16, 32, 16);
+
+ state->m_chunky_buffer = auto_alloc_array(machine, UINT8, 0x200);
+ memset(state->m_chunky_buffer, 0, 0x200);
+ state->m_chunky_graphics = 0;
+}
+
+SCREEN_UPDATE_IND16( microtan )
+{
+ microtan_state *state = screen.machine().driver_data<microtan_state>();
+ state->m_bg_tilemap->draw(bitmap, cliprect, 0, 0);
+ return 0;
+}
diff --git a/src/mess/video/mikro80.c b/src/mess/video/mikro80.c
new file mode 100644
index 00000000000..dcd10312f02
--- /dev/null
+++ b/src/mess/video/mikro80.c
@@ -0,0 +1,39 @@
+/***************************************************************************
+
+ Mikro-80 video driver by Miodrag Milanovic
+
+ 10/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/mikro80.h"
+
+
+VIDEO_START( mikro80 )
+{
+}
+
+SCREEN_UPDATE_IND16( mikro80 )
+{
+ mikro80_state *state = screen.machine().driver_data<mikro80_state>();
+ UINT8 *gfx = state->memregion("gfx1")->base();
+ int x,y,b;
+
+ for(y = 0; y < 32*8; y++ )
+ {
+ for(x = 0; x < 64; x++ )
+ {
+ int addr = x + (y / 8)*64;
+ UINT8 code = gfx[state->m_video_ram [addr]*8+ (y % 8)];
+ UINT8 attr = state->m_cursor_ram[addr+1] & 0x80 ? 1 : 0;
+ for (b = 7; b >= 0; b--)
+ {
+ UINT8 col = (code >> b) & 0x01;
+ bitmap.pix16(y, x*8+(7-b)) = attr ? col ^ 1 : col;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mess/video/mikromik.c b/src/mess/video/mikromik.c
new file mode 100644
index 00000000000..a939220e0f3
--- /dev/null
+++ b/src/mess/video/mikromik.c
@@ -0,0 +1,169 @@
+#include "includes/mikromik.h"
+
+
+
+//-------------------------------------------------
+// PALETTE_INIT( mm1 )
+//-------------------------------------------------
+
+static PALETTE_INIT( mm1 )
+{
+ palette_set_color(machine, 0, RGB_BLACK); /* black */
+ palette_set_color_rgb(machine, 1, 0x00, 0xc0, 0x00); /* green */
+ palette_set_color_rgb(machine, 2, 0x00, 0xff, 0x00); /* bright green */
+}
+
+
+//-------------------------------------------------
+// i8275_interface crtc_intf
+//-------------------------------------------------
+
+static I8275_DISPLAY_PIXELS( crtc_display_pixels )
+{
+ mm1_state *state = device->machine().driver_data<mm1_state>();
+
+ UINT8 romdata = state->m_char_rom[(charcode << 4) | linecount];
+
+ int d0 = BIT(romdata, 0);
+ int d7 = BIT(romdata, 7);
+ int gpa0 = BIT(gpa, 0);
+ int llen = state->m_llen;
+ int i;
+
+ UINT8 data = (romdata << 1) | (d7 & d0);
+
+ for (i = 0; i < 8; i++)
+ {
+ int qh = BIT(data, i);
+ int video_in = ((((d7 & llen) | !vsp) & !gpa0) & qh) | lten;
+ int compl_in = rvv;
+ int hlt_in = hlgt;
+
+ int color = hlt_in ? 2 : (video_in ^ compl_in);
+
+ state->m_bitmap.pix16(y, x + i) = color;
+ }
+}
+
+static const i8275_interface crtc_intf =
+{
+ SCREEN_TAG,
+ 8,
+ 0,
+ DEVCB_DEVICE_LINE_MEMBER(I8237_TAG, am9517a_device, dreq0_w),
+ DEVCB_NULL,
+ crtc_display_pixels
+};
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( mm1_upd7220_map )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( mm1_upd7220_map, AS_0, 8, mm1_state )
+ AM_RANGE(0x00000, 0x3ffff) AM_RAM AM_SHARE("video_ram")
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// UPD7220_INTERFACE( hgdc_intf )
+//-------------------------------------------------
+
+static UPD7220_DISPLAY_PIXELS( hgdc_display_pixels )
+{
+ mm1_state *state = device->machine().driver_data<mm1_state>();
+
+ UINT8 data = state->m_video_ram[address * 2];
+
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(data, i)) bitmap.pix16(y, x + i) = 1;
+ }
+}
+
+static UPD7220_INTERFACE( hgdc_intf )
+{
+ SCREEN_TAG,
+ hgdc_display_pixels,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// VIDEO_START( mm1 )
+//-------------------------------------------------
+
+void mm1_state::video_start()
+{
+ // find memory regions
+ m_char_rom = memregion("chargen")->base();
+
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+}
+
+
+//-------------------------------------------------
+// SCREEN_UPDATE_IND16( mm1 )
+//-------------------------------------------------
+
+UINT32 mm1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ /* text */
+ i8275_update(m_crtc, bitmap, cliprect);
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+
+ /* graphics */
+ m_hgdc->screen_update(screen, bitmap, cliprect);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// gfx_layout charlayout
+//-------------------------------------------------
+
+static const gfx_layout charlayout =
+{
+ 8, 16,
+ RGN_FRAC(1,1),
+ 1,
+ { 0 },
+ { 7, 6, 5, 4, 3, 2, 1, 0 },
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8,
+ 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 },
+ 8*16
+};
+
+
+//-------------------------------------------------
+// GFXDECODE( mm1 )
+//-------------------------------------------------
+
+static GFXDECODE_START( mm1 )
+ GFXDECODE_ENTRY( "chargen", 0, charlayout, 0, 0x100 )
+GFXDECODE_END
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( mm1m6_video )
+//-------------------------------------------------
+
+MACHINE_CONFIG_FRAGMENT( mm1m6_video )
+ MCFG_SCREEN_ADD( SCREEN_TAG, RASTER )
+ MCFG_SCREEN_REFRESH_RATE( 50 )
+ MCFG_SCREEN_UPDATE_DRIVER(mm1_state, screen_update)
+ MCFG_SCREEN_SIZE( 800, 400 )
+ MCFG_SCREEN_VISIBLE_AREA( 0, 800-1, 0, 400-1 )
+ //MCFG_SCREEN_RAW_PARAMS(XTAL_18_720MHz, ...)
+
+ MCFG_GFXDECODE(mm1)
+ MCFG_PALETTE_LENGTH(3)
+ MCFG_PALETTE_INIT(mm1)
+
+ MCFG_I8275_ADD(I8275_TAG, crtc_intf)
+ MCFG_UPD7220_ADD(UPD7220_TAG, XTAL_18_720MHz/8, hgdc_intf, mm1_upd7220_map)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/mos6566.c b/src/mess/video/mos6566.c
new file mode 100644
index 00000000000..8da06e7f11e
--- /dev/null
+++ b/src/mess/video/mos6566.c
@@ -0,0 +1,2818 @@
+/***************************************************************************
+
+ MOS 6566/6567/6569 Video Interface Chip (VIC-II) emulation
+
+ A part of the code (cycle routine and drawing routines) is a modified version of the vic ii emulation used in
+ commodore 64 emulator "frodo" by Christian Bauer
+
+ http://frodo.cebix.net/
+ The rights on the source code remain at the author.
+ It may not - not even in parts - used for commercial purposes without explicit written permission by the author.
+ Permission to use it for non-commercial purposes is hereby granted als long as my copyright notice remains in the program.
+ You are not allowed to use the source to create and distribute a modified version of Frodo.
+
+ Copyright the MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+/*
+
+ TODO:
+
+ - cleanup
+ - light pen
+ - 1:1 sync with CPU
+ - remove RDY hack
+ - VIC IIe
+ - http://hitmen.c02.at/temp/palstuff/
+
+*/
+
+#include "mos6566.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+enum
+{
+ REGISTER_M0X = 0,
+ REGISTER_M0Y,
+ REGISTER_M1X,
+ REGISTER_M1Y,
+ REGISTER_M2X,
+ REGISTER_M2Y,
+ REGISTER_M3X,
+ REGISTER_M3Y,
+ REGISTER_M4X,
+ REGISTER_M4Y,
+ REGISTER_M5X,
+ REGISTER_M5Y,
+ REGISTER_M6X,
+ REGISTER_M6Y,
+ REGISTER_M7X,
+ REGISTER_M7Y,
+ REGISTER_MX_MSB,
+ REGISTER_CR1,
+ REGISTER_RASTER,
+ REGISTER_LPX,
+ REGISTER_LPY,
+ REGISTER_ME,
+ REGISTER_CR2,
+ REGISTER_MYE,
+ REGISTER_MP,
+ REGISTER_IRQ,
+ REGISTER_IE,
+ REGISTER_MDP,
+ REGISTER_MMC,
+ REGISTER_MXE,
+ REGISTER_MM,
+ REGISTER_MD,
+ REGISTER_EC,
+ REGISTER_B0C,
+ REGISTER_B1C,
+ REGISTER_B2C,
+ REGISTER_B3C,
+ REGISTER_MM0,
+ REGISTER_MM1,
+ REGISTER_M0C,
+ REGISTER_M1C,
+ REGISTER_M2C,
+ REGISTER_M3C,
+ REGISTER_M4C,
+ REGISTER_M5C,
+ REGISTER_M6C,
+ REGISTER_M7C
+};
+
+
+static const UINT8 PALETTE[] =
+{
+// black, white, red, cyan
+// purple, green, blue, yellow
+// orange, brown, light red, dark gray,
+// medium gray, light green, light blue, light gray
+// taken from the vice emulator
+ 0x00, 0x00, 0x00, 0xfd, 0xfe, 0xfc, 0xbe, 0x1a, 0x24, 0x30, 0xe6, 0xc6,
+ 0xb4, 0x1a, 0xe2, 0x1f, 0xd2, 0x1e, 0x21, 0x1b, 0xae, 0xdf, 0xf6, 0x0a,
+ 0xb8, 0x41, 0x04, 0x6a, 0x33, 0x04, 0xfe, 0x4a, 0x57, 0x42, 0x45, 0x40,
+ 0x70, 0x74, 0x6f, 0x59, 0xfe, 0x59, 0x5f, 0x53, 0xfe, 0xa4, 0xa7, 0xa2
+};
+
+
+#define VERBOSE_LEVEL 0
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_LEVEL >= N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s", machine().time().as_double(), (char*) M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+#define IS_PAL ((m_variant == TYPE_6569) || (m_variant == TYPE_6572) || (m_variant == TYPE_6573) || (m_variant == TYPE_8565) || (m_variant == TYPE_8565) || (m_variant == TYPE_8569))
+#define IS_VICIIE ((m_variant == TYPE_8564) || (m_variant == TYPE_8566) || (m_variant == TYPE_8569))
+
+#define ROW25_YSTART 0x33
+#define ROW25_YSTOP 0xfb
+#define ROW24_YSTART 0x37
+#define ROW24_YSTOP 0xf7
+
+#define RASTERLINE_2_C64(a) (a)
+#define C64_2_RASTERLINE(a) (a)
+#define XPOS (VIC2_STARTVISIBLECOLUMNS + (VIC2_VISIBLECOLUMNS - VIC2_HSIZE) / 2)
+#define YPOS (VIC2_STARTVISIBLELINES /* + (VIC2_VISIBLELINES - VIC2_VSIZE) / 2 */)
+#define FIRSTCOLUMN 50
+
+/* 2008-05 FP: lightpen code needs to read input port from c64.c and cbmb.c */
+
+#define LIGHTPEN_BUTTON (m_in_lightpen_button_func(0))
+#define LIGHTPEN_X_VALUE (m_in_lightpen_x_func(0))
+#define LIGHTPEN_Y_VALUE (m_in_lightpen_y_func(0))
+
+/* lightpen delivers values from internal counters; they do not start with the visual area or frame area */
+#define VIC2_MAME_XPOS 0
+#define VIC2_MAME_YPOS 0
+#define VIC6567_X_BEGIN 38
+#define VIC6567_Y_BEGIN -6 /* first 6 lines after retrace not for lightpen! */
+#define VIC6569_X_BEGIN 38
+#define VIC6569_Y_BEGIN -6
+#define VIC2_X_BEGIN (IS_PAL ? VIC6569_X_BEGIN : VIC6567_X_BEGIN)
+#define VIC2_Y_BEGIN (IS_PAL ? VIC6569_Y_BEGIN : VIC6567_Y_BEGIN)
+#define VIC2_X_VALUE ((LIGHTPEN_X_VALUE / 1.3) + 12)
+#define VIC2_Y_VALUE ((LIGHTPEN_Y_VALUE ) + 10)
+
+#define VIC2E_K0_LEVEL (m_reg[0x2f] & 0x01)
+#define VIC2E_K1_LEVEL (m_reg[0x2f] & 0x02)
+#define VIC2E_K2_LEVEL (m_reg[0x2f] & 0x04)
+
+
+/* sprites 0 .. 7 */
+#define SPRITEON(nr) (m_reg[0x15] & (1 << nr))
+#define SPRITE_Y_EXPAND(nr) (m_reg[0x17] & (1 << nr))
+#define SPRITE_Y_SIZE(nr) (SPRITE_Y_EXPAND(nr) ? 2 * 21 : 21)
+#define SPRITE_X_EXPAND(nr) (m_reg[0x1d] & (1 << nr))
+#define SPRITE_X_SIZE(nr) (SPRITE_X_EXPAND(nr) ? 2 * 24 : 24)
+#define SPRITE_X_POS(nr) (m_reg[(nr) * 2] | (m_reg[0x10] & (1 << (nr)) ? 0x100 : 0))
+#define SPRITE_Y_POS(nr) (m_reg[1 + 2 * (nr)])
+#define SPRITE_MULTICOLOR(nr) (m_reg[0x1c] & (1 << nr))
+#define SPRITE_PRIORITY(nr) (m_reg[0x1b] & (1 << nr))
+#define SPRITE_MULTICOLOR1 (m_reg[0x25] & 0x0f)
+#define SPRITE_MULTICOLOR2 (m_reg[0x26] & 0x0f)
+#define SPRITE_COLOR(nr) (m_reg[0x27+nr] & 0x0f)
+#define SPRITE_ADDR(nr) (m_videoaddr | 0x3f8 | nr)
+#define SPRITE_COLL (m_reg[0x1e])
+#define SPRITE_BG_COLL (m_reg[0x1f])
+
+#define GFXMODE ((m_reg[0x11] & 0x60) | (m_reg[0x16] & 0x10)) >> 4
+#define SCREENON (m_reg[0x11] & 0x10)
+#define VERTICALPOS (m_reg[0x11] & 0x07)
+#define HORIZONTALPOS (m_reg[0x16] & 0x07)
+#define ECMON (m_reg[0x11] & 0x40)
+#define HIRESON (m_reg[0x11] & 0x20)
+#define COLUMNS40 (m_reg[0x16] & 0x08) /* else 38 Columns */
+
+#define VIDEOADDR ((m_reg[0x18] & 0xf0) << (10 - 4))
+#define CHARGENADDR ((m_reg[0x18] & 0x0e) << 10)
+#define BITMAPADDR ((data & 0x08) << 10)
+
+#define RASTERLINE (((m_reg[0x11] & 0x80) << 1) | m_reg[0x12])
+
+#define FRAMECOLOR (m_reg[0x20] & 0x0f)
+#define BACKGROUNDCOLOR (m_reg[0x21] & 0x0f)
+#define MULTICOLOR1 (m_reg[0x22] & 0x0f)
+#define MULTICOLOR2 (m_reg[0x23] & 0x0f)
+#define FOREGROUNDCOLOR (m_reg[0x24] & 0x0f)
+
+#define VIC2_LINES (IS_PAL ? VIC6569_LINES : VIC6567_LINES)
+#define VIC2_FIRST_DMA_LINE (IS_PAL ? VIC6569_FIRST_DMA_LINE : VIC6567_FIRST_DMA_LINE)
+#define VIC2_LAST_DMA_LINE (IS_PAL ? VIC6569_LAST_DMA_LINE : VIC6567_LAST_DMA_LINE)
+#define VIC2_FIRST_DISP_LINE (IS_PAL ? VIC6569_FIRST_DISP_LINE : VIC6567_FIRST_DISP_LINE)
+#define VIC2_LAST_DISP_LINE (IS_PAL ? VIC6569_LAST_DISP_LINE : VIC6567_LAST_DISP_LINE)
+#define VIC2_RASTER_2_EMU(a) (IS_PAL ? VIC6569_RASTER_2_EMU(a) : VIC6567_RASTER_2_EMU(a))
+#define VIC2_FIRSTCOLUMN (IS_PAL ? VIC6569_FIRSTCOLUMN : VIC6567_FIRSTCOLUMN)
+#define VIC2_X_2_EMU(a) (IS_PAL ? VIC6569_X_2_EMU(a) : VIC6567_X_2_EMU(a))
+
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type MOS6566 = &device_creator<mos6566_device>;
+const device_type MOS6567 = &device_creator<mos6567_device>;
+const device_type MOS8562 = &device_creator<mos8562_device>;
+const device_type MOS6569 = &device_creator<mos6569_device>;
+const device_type MOS8565 = &device_creator<mos8565_device>;
+
+
+// default address maps
+static ADDRESS_MAP_START( mos6566_videoram_map, AS_0, 8, mos6566_device )
+ AM_RANGE(0x0000, 0x3fff) AM_RAM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( mos6566_colorram_map, AS_1, 8, mos6566_device )
+ AM_RANGE(0x000, 0x3ff) AM_RAM
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *mos6566_device::memory_space_config(address_spacenum spacenum) const
+{
+ switch (spacenum)
+ {
+ case AS_0: return &m_videoram_space_config;
+ case AS_1: return &m_colorram_space_config;
+ default: return NULL;
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+inline void mos6566_device::vic2_set_interrupt( int mask )
+{
+ if (((m_reg[0x19] ^ mask) & m_reg[0x1a] & 0xf))
+ {
+ if (!(m_reg[0x19] & 0x80))
+ {
+ DBG_LOG(2, "vic2", ("irq start %.2x\n", mask));
+ m_reg[0x19] |= 0x80;
+ m_out_irq_func(1);
+ }
+ }
+ m_reg[0x19] |= mask;
+}
+
+inline void mos6566_device::vic2_clear_interrupt( int mask )
+{
+ m_reg[0x19] &= ~mask;
+ if ((m_reg[0x19] & 0x80) && !(m_reg[0x19] & m_reg[0x1a] & 0xf))
+ {
+ DBG_LOG(2, "vic2", ("irq end %.2x\n", mask));
+ m_reg[0x19] &= ~0x80;
+ m_out_irq_func(0);
+ }
+}
+
+inline UINT8 mos6566_device::read_videoram(offs_t offset)
+{
+ return space(AS_0)->read_byte(offset & 0x3fff);
+}
+
+inline UINT8 mos6566_device::read_colorram(offs_t offset)
+{
+ return space(AS_1)->read_byte(offset & 0x3ff);
+}
+
+// Idle access
+inline void mos6566_device::vic2_idle_access()
+{
+ read_videoram(0x3fff);
+}
+
+// Fetch sprite data pointer
+inline void mos6566_device::vic2_spr_ptr_access( int num )
+{
+ m_spr_ptr[num] = read_videoram(SPRITE_ADDR(num)) << 6;
+}
+
+// Fetch sprite data, increment data counter
+inline void mos6566_device::vic2_spr_data_access( int num, int bytenum )
+{
+ if (m_spr_dma_on & (1 << num))
+ {
+ m_spr_data[num][bytenum] = read_videoram((m_mc[num] & 0x3f) | m_spr_ptr[num]);
+ m_mc[num]++;
+ }
+ else
+ if (bytenum == 1)
+ vic2_idle_access();
+}
+
+// Turn on display if Bad Line
+inline void mos6566_device::vic2_display_if_bad_line()
+{
+ if (m_is_bad_line)
+ m_display_state = 1;
+}
+
+// Suspend CPU
+inline void mos6566_device::vic2_suspend_cpu()
+{
+ if (m_device_suspended == 0)
+ {
+ m_first_ba_cycle = m_cycles_counter;
+ if (m_in_rdy_workaround_func(0) != 7 )
+ {
+// device_suspend(machine.firstcpu, SUSPEND_REASON_SPIN, 0);
+ }
+ m_device_suspended = 1;
+ }
+}
+
+// Resume CPU
+inline void mos6566_device::vic2_resume_cpu()
+{
+ if (m_device_suspended == 1)
+ {
+ // device_resume(machine.firstcpu, SUSPEND_REASON_SPIN);
+ m_device_suspended = 0;
+ }
+}
+
+// Refresh access
+inline void mos6566_device::vic2_refresh_access()
+{
+ read_videoram(0x3f00 | m_ref_cnt--);
+}
+
+
+inline void mos6566_device::vic2_fetch_if_bad_line()
+{
+ if (m_is_bad_line)
+ m_display_state = 1;
+}
+
+
+// Turn on display and matrix access and reset RC if Bad Line
+inline void mos6566_device::vic2_rc_if_bad_line()
+{
+ if (m_is_bad_line)
+ {
+ m_display_state = 1;
+ m_rc = 0;
+ }
+}
+
+// Sample border color and increment m_graphic_x
+inline void mos6566_device::vic2_sample_border()
+{
+ if (m_draw_this_line)
+ {
+ if (m_border_on)
+ m_border_color_sample[m_cycle - 13] = FRAMECOLOR;
+ m_graphic_x += 8;
+ }
+}
+
+
+// Turn on sprite DMA if necessary
+inline void mos6566_device::vic2_check_sprite_dma()
+{
+ int i;
+ UINT8 mask = 1;
+
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if (SPRITEON(i) && ((m_rasterline & 0xff) == SPRITE_Y_POS(i)))
+ {
+ m_spr_dma_on |= mask;
+ m_mc_base[i] = 0;
+ if (SPRITE_Y_EXPAND(i))
+ m_spr_exp_y &= ~mask;
+ }
+}
+
+// Video matrix access
+inline void mos6566_device::vic2_matrix_access()
+{
+// if (m_device_suspended == 1)
+ {
+ if (m_cycles_counter < m_first_ba_cycle)
+ m_matrix_line[m_ml_index] = m_color_line[m_ml_index] = 0xff;
+ else
+ {
+ UINT16 adr = (m_vc & 0x03ff) | VIDEOADDR;
+ m_matrix_line[m_ml_index] = read_videoram(adr);
+ m_color_line[m_ml_index] = read_colorram((adr & 0x03ff));
+ }
+ }
+}
+
+// Graphics data access
+inline void mos6566_device::vic2_graphics_access()
+{
+ if (m_display_state == 1)
+ {
+ UINT16 adr;
+ if (HIRESON)
+ adr = ((m_vc & 0x03ff) << 3) | m_bitmapaddr | m_rc;
+ else
+ adr = (m_matrix_line[m_ml_index] << 3) | m_chargenaddr | m_rc;
+ if (ECMON)
+ adr &= 0xf9ff;
+ m_gfx_data = read_videoram(adr);
+ m_char_data = m_matrix_line[m_ml_index];
+ m_color_data = m_color_line[m_ml_index];
+ m_ml_index++;
+ m_vc++;
+ }
+ else
+ {
+ m_gfx_data = read_videoram((ECMON ? 0x39ff : 0x3fff));
+ m_char_data = 0;
+ }
+}
+
+inline void mos6566_device::vic2_draw_background()
+{
+ if (m_draw_this_line)
+ {
+ UINT8 c;
+
+ switch (GFXMODE)
+ {
+ case 0:
+ case 1:
+ case 3:
+ c = m_colors[0];
+ break;
+ case 2:
+ c = m_last_char_data & 0x0f;
+ break;
+ case 4:
+ if (m_last_char_data & 0x80)
+ if (m_last_char_data & 0x40)
+ c = m_colors[3];
+ else
+ c = m_colors[2];
+ else
+ if (m_last_char_data & 0x40)
+ c = m_colors[1];
+ else
+ c = m_colors[0];
+ break;
+ default:
+ c = 0;
+ break;
+ }
+ m_bitmap->plot_box(m_graphic_x, VIC2_RASTER_2_EMU(m_rasterline), 8, 1, c);
+ }
+}
+
+inline void mos6566_device::vic2_draw_mono( UINT16 p, UINT8 c0, UINT8 c1 )
+{
+ UINT8 c[2];
+ UINT8 data = m_gfx_data;
+
+ c[0] = c0;
+ c[1] = c1;
+
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = c[data & 1];
+ m_fore_coll_buf[p + 7] = data & 1; data >>= 1;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = c[data & 1];
+ m_fore_coll_buf[p + 6] = data & 1; data >>= 1;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = c[data & 1];
+ m_fore_coll_buf[p + 5] = data & 1; data >>= 1;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = c[data & 1];
+ m_fore_coll_buf[p + 4] = data & 1; data >>= 1;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = c[data & 1];
+ m_fore_coll_buf[p + 3] = data & 1; data >>= 1;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = c[data & 1];
+ m_fore_coll_buf[p + 2] = data & 1; data >>= 1;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = c[data & 1];
+ m_fore_coll_buf[p + 1] = data & 1; data >>= 1;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = c[data];
+ m_fore_coll_buf[p + 0] = data & 1;
+}
+
+inline void mos6566_device::vic2_draw_multi( UINT16 p, UINT8 c0, UINT8 c1, UINT8 c2, UINT8 c3 )
+{
+ UINT8 c[4];
+ UINT8 data = m_gfx_data;
+
+ c[0] = c0;
+ c[1] = c1;
+ c[2] = c2;
+ c[3] = c3;
+
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = c[data & 3];
+ m_fore_coll_buf[p + 7] = data & 2;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = c[data & 3];
+ m_fore_coll_buf[p + 6] = data & 2; data >>= 2;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = c[data & 3];
+ m_fore_coll_buf[p + 5] = data & 2;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = c[data & 3];
+ m_fore_coll_buf[p + 4] = data & 2; data >>= 2;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = c[data & 3];
+ m_fore_coll_buf[p + 3] = data & 2;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = c[data & 3];
+ m_fore_coll_buf[p + 2] = data & 2; data >>= 2;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = c[data];
+ m_fore_coll_buf[p + 1] = data & 2;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = c[data];
+ m_fore_coll_buf[p + 0] = data & 2;
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// mos6566_device - constructor
+//-------------------------------------------------
+
+mos6566_device::mos6566_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MOS6566, "MOS6566", tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ device_execute_interface(mconfig, *this),
+ m_icount(0),
+ m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(mos6566_videoram_map)),
+ m_colorram_space_config("colorram", ENDIANNESS_LITTLE, 8, 10, 0, NULL, *ADDRESS_MAP_NAME(mos6566_colorram_map))
+{
+ m_variant = TYPE_6566;
+}
+
+mos6566_device::mos6566_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ device_execute_interface(mconfig, *this),
+ m_icount(0),
+ m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(mos6566_videoram_map)),
+ m_colorram_space_config("colorram", ENDIANNESS_LITTLE, 8, 10, 0, NULL, *ADDRESS_MAP_NAME(mos6566_colorram_map))
+{
+}
+
+mos6567_device::mos6567_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :mos6566_device(mconfig, MOS6567, "MOS6567", tag, owner, clock) { m_variant = TYPE_6567; }
+
+mos6567_device::mos6567_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
+ :mos6566_device(mconfig, type, name, tag, owner, clock) { }
+
+mos8562_device::mos8562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :mos6567_device(mconfig, MOS8562, "MOS8562", tag, owner, clock) { m_variant = TYPE_8562; }
+
+mos6569_device::mos6569_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :mos6566_device(mconfig, MOS6566, "MOS6569", tag, owner, clock) { m_variant = TYPE_6569; }
+
+mos6569_device::mos6569_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
+ :mos6566_device(mconfig, type, name, tag, owner, clock) { }
+
+mos8565_device::mos8565_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :mos6569_device(mconfig, MOS8565, "MOS8565", tag, owner, clock) { m_variant = TYPE_8565; }
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void mos6566_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const mos6566_interface *intf = reinterpret_cast<const mos6566_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<mos6566_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mos6566_device::device_start()
+{
+ // set our instruction counter
+ m_icountptr = &m_icount;
+
+ // resolve callbacks
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_rdy_func.resolve(m_out_rdy_cb, *this);
+ m_in_lightpen_x_func.resolve(m_in_x_cb, *this);
+ m_in_lightpen_y_func.resolve(m_in_y_cb, *this);
+ m_in_lightpen_button_func.resolve(m_in_button_cb, *this);
+ m_in_rdy_workaround_func.resolve(m_in_rdy_cb, *this);
+
+ m_cpu = machine().device<cpu_device>(m_cpu_tag);
+
+ m_screen = machine().device<screen_device>(m_screen_tag);
+ int width = m_screen->width();
+ int height = m_screen->height();
+
+ m_bitmap = auto_bitmap_ind16_alloc(machine(), width, height);
+
+ // initialize palette
+ int i;
+
+ for (i = 0; i < 16; i++)
+ {
+ palette_set_color_rgb(machine(), i, PALETTE[i * 3], PALETTE[i * 3 + 1], PALETTE[i * 3 + 2]);
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ m_expandx[i] = 0;
+ if (i & 1)
+ m_expandx[i] |= 3;
+ if (i & 2)
+ m_expandx[i] |= 0xc;
+ if (i & 4)
+ m_expandx[i] |= 0x30;
+ if (i & 8)
+ m_expandx[i] |= 0xc0;
+ if (i & 0x10)
+ m_expandx[i] |= 0x300;
+ if (i & 0x20)
+ m_expandx[i] |= 0xc00;
+ if (i & 0x40)
+ m_expandx[i] |= 0x3000;
+ if (i & 0x80)
+ m_expandx[i] |= 0xc000;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ m_expandx_multi[i] = 0;
+ if (i & 1)
+ m_expandx_multi[i] |= 5;
+ if (i & 2)
+ m_expandx_multi[i] |= 0xa;
+ if (i & 4)
+ m_expandx_multi[i] |= 0x50;
+ if (i & 8)
+ m_expandx_multi[i] |= 0xa0;
+ if (i & 0x10)
+ m_expandx_multi[i] |= 0x500;
+ if (i & 0x20)
+ m_expandx_multi[i] |= 0xa00;
+ if (i & 0x40)
+ m_expandx_multi[i] |= 0x5000;
+ if (i & 0x80)
+ m_expandx_multi[i] |= 0xa000;
+ }
+
+ // state saving
+ save_item(NAME(m_reg));
+
+ save_item(NAME(m_on));
+
+ //save_item(NAME(m_bitmap));
+
+ save_item(NAME(m_chargenaddr));
+ save_item(NAME(m_videoaddr));
+ save_item(NAME(m_bitmapaddr));
+
+ save_item(NAME(m_colors));
+ save_item(NAME(m_spritemulti));
+
+ save_item(NAME(m_rasterline));
+ save_item(NAME(m_cycles_counter));
+ save_item(NAME(m_cycle));
+ save_item(NAME(m_raster_x));
+ save_item(NAME(m_graphic_x));
+
+ save_item(NAME(m_dy_start));
+ save_item(NAME(m_dy_stop));
+
+ save_item(NAME(m_draw_this_line));
+ save_item(NAME(m_is_bad_line));
+ save_item(NAME(m_bad_lines_enabled));
+ save_item(NAME(m_display_state));
+ save_item(NAME(m_char_data));
+ save_item(NAME(m_gfx_data));
+ save_item(NAME(m_color_data));
+ save_item(NAME(m_last_char_data));
+ save_item(NAME(m_matrix_line));
+ save_item(NAME(m_color_line));
+ save_item(NAME(m_vblanking));
+ save_item(NAME(m_ml_index));
+ save_item(NAME(m_rc));
+ save_item(NAME(m_vc));
+ save_item(NAME(m_vc_base));
+ save_item(NAME(m_ref_cnt));
+
+ save_item(NAME(m_spr_coll_buf));
+ save_item(NAME(m_fore_coll_buf));
+ save_item(NAME(m_spr_exp_y));
+ save_item(NAME(m_spr_dma_on));
+ save_item(NAME(m_spr_draw));
+ save_item(NAME(m_spr_disp_on));
+ save_item(NAME(m_spr_ptr));
+ save_item(NAME(m_mc_base));
+ save_item(NAME(m_mc));
+
+ for (i = 0; i < 8; i++)
+ {
+ save_item(NAME(m_spr_data[i]), i);
+ save_item(NAME(m_spr_draw_data[i]), i);
+ }
+
+ save_item(NAME(m_border_on));
+ save_item(NAME(m_ud_border_on));
+ save_item(NAME(m_border_on_sample));
+ save_item(NAME(m_border_color_sample));
+
+ save_item(NAME(m_first_ba_cycle));
+ save_item(NAME(m_device_suspended));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mos6566_device::device_reset()
+{
+ int i, j;
+
+ memset(m_reg, 0, ARRAY_LENGTH(m_reg));
+
+ for (i = 0; i < ARRAY_LENGTH(m_mc); i++)
+ m_mc[i] = 63;
+
+ // from 0 to 311 (0 first, PAL) or from 0 to 261 (? first, NTSC 6567R56A) or from 0 to 262 (? first, NTSC 6567R8)
+ m_rasterline = 0; // VIC2_LINES - 1;
+
+ m_cycles_counter = -1;
+ m_cycle = 63;
+
+ m_on = 1;
+
+ m_dy_start = ROW24_YSTART;
+ m_dy_stop = ROW24_YSTOP;
+
+ m_draw_this_line = 0;
+ m_is_bad_line = 0;
+ m_bad_lines_enabled = 0;
+ m_display_state = 0;
+ m_char_data = 0;
+ m_gfx_data = 0;
+ m_color_data = 0;
+ m_last_char_data = 0;
+ m_vblanking = 0;
+ m_ml_index = 0;
+ m_rc = 0;
+ m_vc = 0;
+ m_vc_base = 0;
+ m_ref_cnt = 0;
+
+ m_spr_exp_y = 0;
+ m_spr_dma_on = 0;
+ m_spr_draw = 0;
+ m_spr_disp_on = 0;
+
+
+ m_border_on = 0;
+ m_ud_border_on = 0;
+
+ m_first_ba_cycle = 0;
+ m_device_suspended = 0;
+
+ memset(m_matrix_line, 0, ARRAY_LENGTH(m_matrix_line));
+ memset(m_color_line, 0, ARRAY_LENGTH(m_color_line));
+
+ memset(m_spr_coll_buf, 0, ARRAY_LENGTH(m_spr_coll_buf));
+ memset(m_fore_coll_buf, 0, ARRAY_LENGTH(m_fore_coll_buf));
+ memset(m_border_on_sample, 0, ARRAY_LENGTH(m_border_on_sample));
+ memset(m_border_color_sample, 0, ARRAY_LENGTH(m_border_color_sample));
+
+ for (i = 0; i < 8; i++)
+ {
+ m_spr_ptr[i] = 0;
+ m_mc_base[i] = 0;
+ m_mc[i] = 0;
+ for (j = 0; j < 4; j++)
+ {
+ m_spr_draw_data[i][j] = 0;
+ m_spr_data[i][j] = 0;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// execute_run -
+//-------------------------------------------------
+
+void mos6566_device::execute_run()
+{
+ do
+ {
+ int i;
+ UINT8 mask;
+ m_cycles_counter++;
+
+ switch (m_cycle)
+ {
+
+ // Sprite 3, raster counter, raster IRQ, bad line
+ case 1:
+ if (m_rasterline == (VIC2_LINES - 1))
+ {
+ m_vblanking = 1;
+
+ // if (LIGHTPEN_BUTTON)
+ {
+ m_reg[0x13] = VIC2_X_VALUE;
+ m_reg[0x14] = VIC2_Y_VALUE;
+ }
+ vic2_set_interrupt(8);
+ }
+ else
+ {
+ m_rasterline++;
+
+ if (m_rasterline == VIC2_FIRST_DMA_LINE)
+ m_bad_lines_enabled = SCREENON;
+
+ m_is_bad_line = ((m_rasterline >= VIC2_FIRST_DMA_LINE) && (m_rasterline <= VIC2_LAST_DMA_LINE) &&
+ ((m_rasterline & 0x07) == VERTICALPOS) && m_bad_lines_enabled);
+
+ m_draw_this_line = ((VIC2_RASTER_2_EMU(m_rasterline) >= VIC2_RASTER_2_EMU(VIC2_FIRST_DISP_LINE)) &&
+ (VIC2_RASTER_2_EMU(m_rasterline ) <= VIC2_RASTER_2_EMU(VIC2_LAST_DISP_LINE)));
+ }
+
+ m_border_on_sample[0] = m_border_on;
+ vic2_spr_ptr_access(3);
+ vic2_spr_data_access(3, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x08)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Sprite 3
+ case 2:
+ if (m_vblanking)
+ {
+ // Vertical blank, reset counters
+ m_rasterline = m_vc_base = 0;
+ m_ref_cnt = 0xff;
+ m_vblanking = 0;
+
+ // Trigger raster IRQ if IRQ in line 0
+ if (RASTERLINE == 0)
+ {
+ vic2_set_interrupt(1);
+ }
+ }
+
+ if (m_rasterline == RASTERLINE)
+ {
+ vic2_set_interrupt(1);
+ }
+
+ m_graphic_x = VIC2_X_2_EMU(0);
+
+ vic2_spr_data_access(3, 1);
+ vic2_spr_data_access(3, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 4
+ case 3:
+ vic2_spr_ptr_access(4);
+ vic2_spr_data_access(4, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x10)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Sprite 4
+ case 4:
+ vic2_spr_data_access(4, 1);
+ vic2_spr_data_access(4, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 5
+ case 5:
+ vic2_spr_ptr_access(5);
+ vic2_spr_data_access(5, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x20)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Sprite 5
+ case 6:
+ vic2_spr_data_access(5, 1);
+ vic2_spr_data_access(5, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 6
+ case 7:
+ vic2_spr_ptr_access(6);
+ vic2_spr_data_access(6, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x40)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Sprite 6
+ case 8:
+ vic2_spr_data_access(6, 1);
+ vic2_spr_data_access(6, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 7
+ case 9:
+ vic2_spr_ptr_access(7);
+ vic2_spr_data_access(7, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x80)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Sprite 7
+ case 10:
+ vic2_spr_data_access(7, 1);
+ vic2_spr_data_access(7, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Refresh
+ case 11:
+ vic2_refresh_access();
+ vic2_display_if_bad_line();
+
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Refresh, fetch if bad line
+ case 12:
+ vic2_refresh_access();
+ vic2_fetch_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Refresh, fetch if bad line, raster_x
+ case 13:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_refresh_access();
+ vic2_fetch_if_bad_line();
+
+ m_raster_x = 0xfffc;
+
+ m_cycle++;
+ break;
+
+ // Refresh, fetch if bad line, RC, VC
+ case 14:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_refresh_access();
+ vic2_rc_if_bad_line();
+
+ m_vc = m_vc_base;
+
+ m_cycle++;
+ break;
+
+ // Refresh, fetch if bad line, sprite y expansion
+ case 15:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_refresh_access();
+ vic2_fetch_if_bad_line();
+
+ for (i = 0; i < 8; i++)
+ if (m_spr_exp_y & (1 << i))
+ m_mc_base[i] += 2;
+
+ if (m_is_bad_line)
+ vic2_suspend_cpu();
+
+ m_ml_index = 0;
+ vic2_matrix_access();
+
+ m_cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 16:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_graphics_access();
+ vic2_fetch_if_bad_line();
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ if (m_spr_exp_y & mask)
+ m_mc_base[i]++;
+ if ((m_mc_base[i] & 0x3f) == 0x3f)
+ m_spr_dma_on &= ~mask;
+ }
+
+ vic2_matrix_access();
+
+ m_cycle++;
+ break;
+
+ // Graphics, check border
+ case 17:
+ if (COLUMNS40)
+ {
+ if (m_rasterline == m_dy_stop)
+ m_ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (m_rasterline == m_dy_start)
+ m_border_on = m_ud_border_on = 0;
+ else
+ if (m_ud_border_on == 0)
+ m_border_on = 0;
+ }
+ else
+ if (m_ud_border_on == 0)
+ m_border_on = 0;
+ }
+ }
+
+ // Second sample of border state
+ m_border_on_sample[1] = m_border_on;
+
+ vic2_draw_background();
+ vic2_draw_graphics();
+ vic2_sample_border();
+ vic2_graphics_access();
+ vic2_fetch_if_bad_line();
+ vic2_matrix_access();
+
+ m_cycle++;
+ break;
+
+ // Check border
+ case 18:
+ if (!COLUMNS40)
+ {
+ if (m_rasterline == m_dy_stop)
+ m_ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (m_rasterline == m_dy_start)
+ m_border_on = m_ud_border_on = 0;
+ else
+ if (m_ud_border_on == 0)
+ m_border_on = 0;
+ }
+ else
+ if (m_ud_border_on == 0)
+ m_border_on = 0;
+ }
+ }
+
+ // Third sample of border state
+ m_border_on_sample[2] = m_border_on;
+
+ // Graphics
+
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ vic2_draw_graphics();
+ vic2_sample_border();
+ vic2_graphics_access();
+ vic2_fetch_if_bad_line();
+ vic2_matrix_access();
+ m_last_char_data = m_char_data;
+
+ m_cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 55:
+ vic2_draw_graphics();
+ vic2_sample_border();
+ vic2_graphics_access();
+ vic2_display_if_bad_line();
+
+ // sprite y expansion
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if (SPRITE_Y_EXPAND (i))
+ m_spr_exp_y ^= mask;
+
+ vic2_check_sprite_dma();
+
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Check border, sprite DMA
+ case 56:
+ if (!COLUMNS40)
+ m_border_on = 1;
+
+ // Fourth sample of border state
+ m_border_on_sample[3] = m_border_on;
+
+ vic2_draw_graphics();
+ vic2_sample_border();
+ vic2_idle_access();
+ vic2_display_if_bad_line();
+ vic2_check_sprite_dma();
+
+ m_cycle++;
+ break;
+
+ // Check border, sprites
+ case 57:
+ if (COLUMNS40)
+ m_border_on = 1;
+
+ // Fifth sample of border state
+ m_border_on_sample[4] = m_border_on;
+
+ // Sample spr_disp_on and spr_data for sprite drawing
+ m_spr_draw = m_spr_disp_on;
+ if (m_spr_draw)
+ memcpy(m_spr_draw_data, m_spr_data, 8 * 4);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if ((m_spr_disp_on & mask) && !(m_spr_dma_on & mask))
+ m_spr_disp_on &= ~mask;
+
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_idle_access();
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // for NTSC 6567R8
+ case 58:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_idle_access();
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // for NTSC 6567R8
+ case 59:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_idle_access();
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 0, sprite DMA, MC, RC
+ case 60:
+ vic2_draw_background();
+ vic2_sample_border();
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ m_mc[i] = m_mc_base[i];
+ if ((m_spr_dma_on & mask) && ((m_rasterline & 0xff) == SPRITE_Y_POS(i)))
+ m_spr_disp_on |= mask;
+ }
+
+ vic2_spr_ptr_access(0);
+ vic2_spr_data_access(0, 0);
+
+ if (m_rc == 7)
+ {
+ m_vc_base = m_vc;
+ m_display_state = 0;
+ }
+
+ if (m_is_bad_line || m_display_state)
+ {
+ m_display_state = 1;
+ m_rc = (m_rc + 1) & 7;
+ }
+
+ if (m_spr_dma_on & 0x01)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Sprite 0
+ case 61:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_spr_data_access(0, 1);
+ vic2_spr_data_access(0, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 1, draw
+ case 62:
+ vic2_draw_background();
+ vic2_sample_border();
+
+ if (m_draw_this_line)
+ {
+ vic2_draw_sprites();
+
+ if (m_border_on_sample[0])
+ for (i = 0; i < 4; i++)
+ m_bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[i]);
+
+ if (m_border_on_sample[1])
+ m_bitmap->plot_box(VIC2_X_2_EMU(4 * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[4]);
+
+ if (m_border_on_sample[2])
+ for (i = 5; i < 43; i++)
+ m_bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[i]);
+
+ if (m_border_on_sample[3])
+ m_bitmap->plot_box(VIC2_X_2_EMU(43 * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[43]);
+
+ if (m_border_on_sample[4])
+ {
+ for (i = 44; i < 48; i++)
+ m_bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[i]);
+ for (i = 48; i < 53; i++)
+ m_bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[47]);
+ }
+ }
+
+ vic2_spr_ptr_access(1);
+ vic2_spr_data_access(1, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x02)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Sprite 1
+ case 63:
+ vic2_spr_data_access(1, 1);
+ vic2_spr_data_access(1, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 2
+ case 64:
+ vic2_spr_ptr_access(2);
+ vic2_spr_data_access(2, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x04)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Sprite 2
+ case 65:
+ vic2_spr_data_access(2, 1);
+ vic2_spr_data_access(2, 2);
+ vic2_display_if_bad_line();
+
+ if (m_rasterline == m_dy_stop)
+ m_ud_border_on = 1;
+ else
+ if (SCREENON && (m_rasterline == m_dy_start))
+ m_ud_border_on = 0;
+
+ // Last cycle
+ m_cycle = 1;
+ }
+
+ m_raster_x += 8;
+ m_icount--;
+ } while (m_icount > 0);
+}
+
+
+//-------------------------------------------------
+// execute_run -
+//-------------------------------------------------
+
+void mos6569_device::execute_run()
+{
+ do
+ {
+ int i;
+ UINT8 mask;
+ //static int adjust[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ UINT8 cpu_cycles = m_cpu->total_cycles() & 0xff;
+ UINT8 vic_cycles = (m_cycles_counter + 1) & 0xff;
+ m_cycles_counter++;
+
+ // printf("%02x %02x %02x\n",cpu_cycles,vic_cycles,m_rdy_cycles);
+ #if 0
+ if (machine.input().code_pressed(KEYCODE_X))
+ {
+ if (machine.input().code_pressed_once(KEYCODE_Q)) adjust[1]++;
+ if (machine.input().code_pressed_once(KEYCODE_W)) adjust[2]++;
+ if (machine.input().code_pressed_once(KEYCODE_E)) adjust[3]++;
+ if (machine.input().code_pressed_once(KEYCODE_R)) adjust[4]++;
+ if (machine.input().code_pressed_once(KEYCODE_T)) adjust[5]++;
+ if (machine.input().code_pressed_once(KEYCODE_Y)) adjust[6]++;
+ if (machine.input().code_pressed_once(KEYCODE_U)) adjust[7]++;
+ if (machine.input().code_pressed_once(KEYCODE_I)) adjust[8]++;
+ if (machine.input().code_pressed_once(KEYCODE_A)) adjust[1]--;
+ if (machine.input().code_pressed_once(KEYCODE_S)) adjust[2]--;
+ if (machine.input().code_pressed_once(KEYCODE_D)) adjust[3]--;
+ if (machine.input().code_pressed_once(KEYCODE_F)) adjust[4]--;
+ if (machine.input().code_pressed_once(KEYCODE_G)) adjust[5]--;
+ if (machine.input().code_pressed_once(KEYCODE_H)) adjust[6]--;
+ if (machine.input().code_pressed_once(KEYCODE_J)) adjust[7]--;
+ if (machine.input().code_pressed_once(KEYCODE_K)) adjust[8]--;
+ if (machine.input().code_pressed_once(KEYCODE_C)) adjust[0]++;
+ if (machine.input().code_pressed_once(KEYCODE_V)) adjust[0]--;
+ if (machine.input().code_pressed_once(KEYCODE_Z)) printf("b:%02x 1:%02x 2:%02x 3:%02x 4:%02x 5:%02x 6:%02x 7:%02x 8:%02x\n",
+ adjust[0],adjust[1],adjust[2],adjust[3],adjust[4],adjust[5],adjust[6],adjust[7],adjust[8]);
+ }
+ #define adjust(x) adjust[x]
+ #else
+ #define adjust(x) 0
+ #endif
+
+ switch(m_cycle)
+ {
+
+ // Sprite 3, raster counter, raster IRQ, bad line
+ case 1:
+ if (m_rasterline == (VIC2_LINES - 1))
+ {
+ m_vblanking = 1;
+
+ // if (LIGHTPEN_BUTTON)
+ {
+ m_reg[0x13] = VIC2_X_VALUE;
+ m_reg[0x14] = VIC2_Y_VALUE;
+ }
+ vic2_set_interrupt(8);
+ }
+ else
+ {
+ m_rasterline++;
+
+ if (m_rasterline == VIC2_FIRST_DMA_LINE)
+ m_bad_lines_enabled = SCREENON;
+
+ m_is_bad_line = ((m_rasterline >= VIC2_FIRST_DMA_LINE) && (m_rasterline <= VIC2_LAST_DMA_LINE) &&
+ ((m_rasterline & 0x07) == VERTICALPOS) && m_bad_lines_enabled);
+
+ m_draw_this_line = ((VIC2_RASTER_2_EMU(m_rasterline) >= VIC2_RASTER_2_EMU(VIC2_FIRST_DISP_LINE)) &&
+ (VIC2_RASTER_2_EMU(m_rasterline ) <= VIC2_RASTER_2_EMU(VIC2_LAST_DISP_LINE)));
+ }
+
+ m_border_on_sample[0] = m_border_on;
+ vic2_spr_ptr_access(3);
+ vic2_spr_data_access(3, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x08)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ if (m_spr_dma_on & 0x08) m_rdy_cycles += (2 + adjust(1));
+
+ m_cycle++;
+ break;
+
+ // Sprite 3
+ case 2:
+ if (m_vblanking)
+ {
+ // Vertical blank, reset counters
+ m_rasterline = m_vc_base = 0;
+ m_ref_cnt = 0xff;
+ m_vblanking = 0;
+
+ // Trigger raster IRQ if IRQ in line 0
+ if (RASTERLINE == 0)
+ {
+ vic2_set_interrupt(1);
+ }
+ }
+
+ if (m_rasterline == RASTERLINE)
+ {
+ vic2_set_interrupt(1);
+ }
+
+ m_graphic_x = VIC2_X_2_EMU(0);
+
+ vic2_spr_data_access(3, 1);
+ vic2_spr_data_access(3, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 4
+ case 3:
+ vic2_spr_ptr_access(4);
+ vic2_spr_data_access(4, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x10)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ if (m_spr_dma_on & 0x10) m_rdy_cycles += (2 + adjust(2));
+
+ m_cycle++;
+ break;
+
+ // Sprite 4
+ case 4:
+ vic2_spr_data_access(4, 1);
+ vic2_spr_data_access(4, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 5
+ case 5:
+ vic2_spr_ptr_access(5);
+ vic2_spr_data_access(5, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x20)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ if (m_spr_dma_on & 0x20) m_rdy_cycles += (2 + adjust(3));
+
+ m_cycle++;
+ break;
+
+ // Sprite 5
+ case 6:
+ vic2_spr_data_access(5, 1);
+ vic2_spr_data_access(5, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 6
+ case 7:
+ vic2_spr_ptr_access(6);
+ vic2_spr_data_access(6, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x40)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ if (m_spr_dma_on & 0x40) m_rdy_cycles += (2 + adjust(4));
+
+ m_cycle++;
+ break;
+
+ // Sprite 6
+ case 8:
+ vic2_spr_data_access(6, 1);
+ vic2_spr_data_access(6, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 7
+ case 9:
+ vic2_spr_ptr_access(7);
+ vic2_spr_data_access(7, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x80)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ if (m_spr_dma_on & 0x80) m_rdy_cycles += (2 + adjust(5));
+
+ m_cycle++;
+ break;
+
+ // Sprite 7
+ case 10:
+ vic2_spr_data_access(7, 1);
+ vic2_spr_data_access(7, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Refresh
+ case 11:
+ vic2_refresh_access();
+ vic2_display_if_bad_line();
+
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Refresh, fetch if bad line
+ case 12:
+ vic2_refresh_access();
+ vic2_fetch_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Refresh, fetch if bad line, raster_x
+ case 13:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_refresh_access();
+ vic2_fetch_if_bad_line();
+
+ m_raster_x = 0xfffc;
+
+ if ((m_in_rdy_workaround_func(0) == 0 ) && (m_is_bad_line))
+ m_rdy_cycles += (43+adjust(0));
+
+ m_cycle++;
+ break;
+
+ // Refresh, fetch if bad line, RC, VC
+ case 14:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_refresh_access();
+ vic2_rc_if_bad_line();
+
+ m_vc = m_vc_base;
+
+ if ((m_in_rdy_workaround_func(0) == 1 ) && (m_is_bad_line))
+ m_rdy_cycles += (42+adjust(0));
+
+ m_cycle++;
+ break;
+
+ // Refresh, fetch if bad line, sprite y expansion
+ case 15:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_refresh_access();
+ vic2_fetch_if_bad_line();
+
+ for (i = 0; i < 8; i++)
+ if (m_spr_exp_y & (1 << i))
+ m_mc_base[i] += 2;
+
+ m_ml_index = 0;
+ vic2_matrix_access();
+
+ if ((m_in_rdy_workaround_func(0) == 2 ) && (m_is_bad_line))
+ m_rdy_cycles += (41+adjust(0));
+
+ m_cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 16:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_graphics_access();
+ vic2_fetch_if_bad_line();
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ if (m_spr_exp_y & mask)
+ m_mc_base[i]++;
+ if ((m_mc_base[i] & 0x3f) == 0x3f)
+ m_spr_dma_on &= ~mask;
+ }
+
+ vic2_matrix_access();
+
+ if ((m_in_rdy_workaround_func(0) == 3 ) && (m_is_bad_line))
+ m_rdy_cycles += (40+adjust(0));
+
+ m_cycle++;
+ break;
+
+ // Graphics, check border
+ case 17:
+ if (COLUMNS40)
+ {
+ if (m_rasterline == m_dy_stop)
+ m_ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (m_rasterline == m_dy_start)
+ m_border_on = m_ud_border_on = 0;
+ else
+ if (m_ud_border_on == 0)
+ m_border_on = 0;
+ } else
+ if (m_ud_border_on == 0)
+ m_border_on = 0;
+ }
+ }
+
+ // Second sample of border state
+ m_border_on_sample[1] = m_border_on;
+
+ vic2_draw_background();
+ vic2_draw_graphics();
+ vic2_sample_border();
+ vic2_graphics_access();
+ vic2_fetch_if_bad_line();
+ vic2_matrix_access();
+
+ if ((m_in_rdy_workaround_func(0) == 4 ) && (m_is_bad_line))
+ m_rdy_cycles += (40+adjust(0));
+
+ m_cycle++;
+ break;
+
+ // Check border
+ case 18:
+ if (!COLUMNS40)
+ {
+ if (m_rasterline == m_dy_stop)
+ m_ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (m_rasterline == m_dy_start)
+ m_border_on = m_ud_border_on = 0;
+ else
+ if (m_ud_border_on == 0)
+ m_border_on = 0;
+ } else
+ if (m_ud_border_on == 0)
+ m_border_on = 0;
+ }
+ }
+
+ // Third sample of border state
+ m_border_on_sample[2] = m_border_on;
+
+ // Graphics
+
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ vic2_draw_graphics();
+ vic2_sample_border();
+ vic2_graphics_access();
+ vic2_fetch_if_bad_line();
+ vic2_matrix_access();
+ m_last_char_data = m_char_data;
+
+ m_cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 55:
+ vic2_draw_graphics();
+ vic2_sample_border();
+ vic2_graphics_access();
+ vic2_display_if_bad_line();
+
+ // sprite y expansion
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if (SPRITE_Y_EXPAND (i))
+ m_spr_exp_y ^= mask;
+
+ vic2_check_sprite_dma();
+
+ vic2_resume_cpu();
+
+ m_cycle++;
+ break;
+
+ // Check border, sprite DMA
+ case 56:
+ if (!COLUMNS40)
+ m_border_on = 1;
+
+ // Fourth sample of border state
+ m_border_on_sample[3] = m_border_on;
+
+ vic2_draw_graphics();
+ vic2_sample_border();
+ vic2_idle_access();
+ vic2_display_if_bad_line();
+ vic2_check_sprite_dma();
+
+ m_cycle++;
+ break;
+
+ // Check border, sprites
+ case 57:
+ if (COLUMNS40)
+ m_border_on = 1;
+
+ // Fifth sample of border state
+ m_border_on_sample[4] = m_border_on;
+
+ // Sample spr_disp_on and spr_data for sprite drawing
+ m_spr_draw = m_spr_disp_on;
+ if (m_spr_draw)
+ memcpy(m_spr_draw_data, m_spr_data, 8 * 4);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if ((m_spr_disp_on & mask) && !(m_spr_dma_on & mask))
+ m_spr_disp_on &= ~mask;
+
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_idle_access();
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 0, sprite DMA, MC, RC
+ case 58:
+ vic2_draw_background();
+ vic2_sample_border();
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ m_mc[i] = m_mc_base[i];
+ if ((m_spr_dma_on & mask) && ((m_rasterline & 0xff) == SPRITE_Y_POS(i)))
+ m_spr_disp_on |= mask;
+ }
+
+ vic2_spr_ptr_access(0);
+ vic2_spr_data_access(0, 0);
+
+ if (m_rc == 7)
+ {
+ m_vc_base = m_vc;
+ m_display_state = 0;
+ }
+
+ if (m_is_bad_line || m_display_state)
+ {
+ m_display_state = 1;
+ m_rc = (m_rc + 1) & 7;
+ }
+
+ if (m_spr_dma_on & 0x01)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ if (m_spr_dma_on & 0x01) m_rdy_cycles += (2 + adjust(6));
+
+ m_cycle++;
+ break;
+
+ // Sprite 0
+ case 59:
+ vic2_draw_background();
+ vic2_sample_border();
+ vic2_spr_data_access(0, 1);
+ vic2_spr_data_access(0, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 1, draw
+ case 60:
+ vic2_draw_background();
+ vic2_sample_border();
+
+ if (m_draw_this_line)
+ {
+ vic2_draw_sprites();
+
+ if (m_border_on_sample[0])
+ for (i = 0; i < 4; i++)
+ m_bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[i]);
+
+ if (m_border_on_sample[1])
+ m_bitmap->plot_box(VIC2_X_2_EMU(4 * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[4]);
+
+ if (m_border_on_sample[2])
+ for (i = 5; i < 43; i++)
+ m_bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[i]);
+
+ if (m_border_on_sample[3])
+ m_bitmap->plot_box(VIC2_X_2_EMU(43 * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[43]);
+
+ if (m_border_on_sample[4])
+ {
+ for (i = 44; i < 48; i++)
+ m_bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[i]);
+ for (i = 48; i < 51; i++)
+ m_bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, m_border_color_sample[47]);
+ }
+ }
+
+ vic2_spr_ptr_access(1);
+ vic2_spr_data_access(1, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x02)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ if (m_spr_dma_on & 0x02) m_rdy_cycles += (2 + adjust(7));
+
+ m_cycle++;
+ break;
+
+ // Sprite 1
+ case 61:
+ vic2_spr_data_access(1, 1);
+ vic2_spr_data_access(1, 2);
+ vic2_display_if_bad_line();
+
+ m_cycle++;
+ break;
+
+ // Sprite 2
+ case 62:
+ vic2_spr_ptr_access(2);
+ vic2_spr_data_access(2, 0);
+ vic2_display_if_bad_line();
+
+ if (m_spr_dma_on & 0x04)
+ vic2_suspend_cpu();
+ else
+ vic2_resume_cpu();
+
+ if (m_spr_dma_on & 0x04) m_rdy_cycles += (2 + adjust(8));
+
+ m_cycle++;
+ break;
+
+ // Sprite 2
+ case 63:
+ vic2_spr_data_access(2, 1);
+ vic2_spr_data_access(2, 2);
+ vic2_display_if_bad_line();
+
+ if (m_rasterline == m_dy_stop)
+ m_ud_border_on = 1;
+ else
+ if (SCREENON && (m_rasterline == m_dy_start))
+ m_ud_border_on = 0;
+
+ // Last cycle
+ m_cycle = 1;
+ }
+
+ if ((cpu_cycles == vic_cycles) && (m_rdy_cycles > 0))
+ {
+ device_spin_until_time (m_cpu, m_cpu->cycles_to_attotime(m_rdy_cycles));
+ m_rdy_cycles = 0;
+ }
+
+ m_raster_x += 8;
+ m_icount--;
+ } while (m_icount > 0);
+}
+
+// Graphics display (8 pixels)
+void mos6566_device::vic2_draw_graphics()
+{
+ if (m_draw_this_line == 0)
+ {
+ UINT16 p = m_graphic_x + HORIZONTALPOS;
+ m_fore_coll_buf[p + 7] = 0;
+ m_fore_coll_buf[p + 6] = 0;
+ m_fore_coll_buf[p + 5] = 0;
+ m_fore_coll_buf[p + 4] = 0;
+ m_fore_coll_buf[p + 3] = 0;
+ m_fore_coll_buf[p + 2] = 0;
+ m_fore_coll_buf[p + 1] = 0;
+ m_fore_coll_buf[p + 0] = 0;
+ }
+ else if (m_ud_border_on)
+ {
+ UINT16 p = m_graphic_x + HORIZONTALPOS;
+ m_fore_coll_buf[p + 7] = 0;
+ m_fore_coll_buf[p + 6] = 0;
+ m_fore_coll_buf[p + 5] = 0;
+ m_fore_coll_buf[p + 4] = 0;
+ m_fore_coll_buf[p + 3] = 0;
+ m_fore_coll_buf[p + 2] = 0;
+ m_fore_coll_buf[p + 1] = 0;
+ m_fore_coll_buf[p + 0] = 0;
+ vic2_draw_background();
+ }
+ else
+ {
+ UINT8 tmp_col;
+ UINT16 p = m_graphic_x + HORIZONTALPOS;
+ switch (GFXMODE)
+ {
+ case 0:
+ vic2_draw_mono(p, m_colors[0], m_color_data & 0x0f);
+ break;
+ case 1:
+ if (m_color_data & 0x08)
+ vic2_draw_multi(p, m_colors[0], m_colors[1], m_colors[2], m_color_data & 0x07);
+ else
+ vic2_draw_mono(p, m_colors[0], m_color_data & 0x0f);
+ break;
+ case 2:
+ vic2_draw_mono(p, m_char_data & 0x0f, m_char_data >> 4);
+ break;
+ case 3:
+ vic2_draw_multi(p, m_colors[0], m_char_data >> 4, m_char_data & 0x0f, m_color_data & 0x0f);
+ break;
+ case 4:
+ if (m_char_data & 0x80)
+ if (m_char_data & 0x40)
+ tmp_col = m_colors[3];
+ else
+ tmp_col = m_colors[2];
+ else
+ if (m_char_data & 0x40)
+ tmp_col = m_colors[1];
+ else
+ tmp_col = m_colors[0];
+ vic2_draw_mono(p, tmp_col, m_color_data & 0x0f);
+ break;
+ case 5:
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = 0;
+ m_fore_coll_buf[p + 7] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = 0;
+ m_fore_coll_buf[p + 6] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = 0;
+ m_fore_coll_buf[p + 5] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = 0;
+ m_fore_coll_buf[p + 4] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = 0;
+ m_fore_coll_buf[p + 3] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = 0;
+ m_fore_coll_buf[p + 2] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = 0;
+ m_fore_coll_buf[p + 1] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = 0;
+ m_fore_coll_buf[p + 0] = 0;
+ break;
+ case 6:
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = 0;
+ m_fore_coll_buf[p + 7] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = 0;
+ m_fore_coll_buf[p + 6] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = 0;
+ m_fore_coll_buf[p + 5] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = 0;
+ m_fore_coll_buf[p + 4] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = 0;
+ m_fore_coll_buf[p + 3] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = 0;
+ m_fore_coll_buf[p + 2] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = 0;
+ m_fore_coll_buf[p + 1] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = 0;
+ m_fore_coll_buf[p + 0] = 0;
+ break;
+ case 7:
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = 0;
+ m_fore_coll_buf[p + 7] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = 0;
+ m_fore_coll_buf[p + 6] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = 0;
+ m_fore_coll_buf[p + 5] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = 0;
+ m_fore_coll_buf[p + 4] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = 0;
+ m_fore_coll_buf[p + 3] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = 0;
+ m_fore_coll_buf[p + 2] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = 0;
+ m_fore_coll_buf[p + 1] = 0;
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = 0;
+ m_fore_coll_buf[p + 0] = 0;
+ break;
+ }
+ }
+}
+
+void mos6566_device::vic2_draw_sprites()
+{
+ int i;
+ UINT8 snum, sbit;
+ UINT8 spr_coll = 0, gfx_coll = 0;
+ UINT32 plane0_l, plane0_r, plane1_l, plane1_r;
+ UINT32 sdata_l = 0, sdata_r = 0;
+
+ for (i = 0; i < 0x400; i++)
+ m_spr_coll_buf[i] = 0;
+
+ for (snum = 0, sbit = 1; snum < 8; snum++, sbit <<= 1)
+ {
+ if ((m_spr_draw & sbit) && (SPRITE_X_POS(snum) <= (403 - (VIC2_FIRSTCOLUMN + 1))))
+ {
+ UINT16 p = SPRITE_X_POS(snum) + VIC2_X_2_EMU(0) + 8;
+ UINT8 color = SPRITE_COLOR(snum);
+ UINT32 sdata = (m_spr_draw_data[snum][0] << 24) | (m_spr_draw_data[snum][1] << 16) | (m_spr_draw_data[snum][2] << 8);
+
+ if (SPRITE_X_EXPAND(snum))
+ {
+ if (SPRITE_X_POS(snum) > (403 - 24 - (VIC2_FIRSTCOLUMN + 1)))
+ continue;
+
+ if (SPRITE_MULTICOLOR(snum))
+ {
+ sdata_l = (m_expandx_multi[(sdata >> 24) & 0xff] << 16) | m_expandx_multi[(sdata >> 16) & 0xff];
+ sdata_r = m_expandx_multi[(sdata >> 8) & 0xff] << 16;
+ plane0_l = (sdata_l & 0x55555555) | (sdata_l & 0x55555555) << 1;
+ plane1_l = (sdata_l & 0xaaaaaaaa) | (sdata_l & 0xaaaaaaaa) >> 1;
+ plane0_r = (sdata_r & 0x55555555) | (sdata_r & 0x55555555) << 1;
+ plane1_r = (sdata_r & 0xaaaaaaaa) | (sdata_r & 0xaaaaaaaa) >> 1;
+ for (i = 0; i < 32; i++, plane0_l <<= 1, plane1_l <<= 1)
+ {
+ UINT8 col;
+
+ if (plane1_l & 0x80000000)
+ {
+ if (m_fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ if (plane0_l & 0x80000000)
+ col = m_spritemulti[3];
+ else
+ col = color;
+ }
+ else
+ {
+ if (plane0_l & 0x80000000)
+ {
+ if (m_fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ col = m_spritemulti[1];
+ }
+ else
+ continue;
+ }
+
+ if (m_spr_coll_buf[p + i])
+ spr_coll |= m_spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (m_fore_coll_buf[p + i] == 0)
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = col;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = col;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+
+ for (; i < 48; i++, plane0_r <<= 1, plane1_r <<= 1)
+ {
+ UINT8 col;
+
+ if(plane1_r & 0x80000000)
+ {
+ if (m_fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (plane0_r & 0x80000000)
+ col = m_spritemulti[3];
+ else
+ col = color;
+ }
+ else
+ {
+ if (plane0_r & 0x80000000)
+ {
+ if (m_fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ col = m_spritemulti[1];
+ }
+ else
+ continue;
+ }
+
+ if (m_spr_coll_buf[p + i])
+ spr_coll |= m_spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (m_fore_coll_buf[p + i] == 0)
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = col;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = col;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ else
+ {
+ sdata_l = (m_expandx[(sdata >> 24) & 0xff] << 16) | m_expandx[(sdata >> 16) & 0xff];
+ sdata_r = m_expandx[(sdata >> 8) & 0xff] << 16;
+
+ for (i = 0; i < 32; i++, sdata_l <<= 1)
+ if (sdata_l & 0x80000000)
+ {
+ if (m_fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (m_spr_coll_buf[p + i])
+ spr_coll |= m_spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (m_fore_coll_buf[p + i] == 0)
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = color;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = color;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+
+ for (; i < 48; i++, sdata_r <<= 1)
+ if (sdata_r & 0x80000000)
+ {
+ if (m_fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (m_spr_coll_buf[p + i])
+ spr_coll |= m_spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (m_fore_coll_buf[p + i] == 0)
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = color;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = color;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (SPRITE_MULTICOLOR(snum))
+ {
+ UINT32 plane0 = (sdata & 0x55555555) | (sdata & 0x55555555) << 1;
+ UINT32 plane1 = (sdata & 0xaaaaaaaa) | (sdata & 0xaaaaaaaa) >> 1;
+
+ for (i = 0; i < 24; i++, plane0 <<= 1, plane1 <<= 1)
+ {
+ UINT8 col;
+
+ if (plane1 & 0x80000000)
+ {
+ if (m_fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (plane0 & 0x80000000)
+ col = m_spritemulti[3];
+ else
+ col = color;
+ }
+ else
+ {
+ if (m_fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (plane0 & 0x80000000)
+ col = m_spritemulti[1];
+ else
+ continue;
+ }
+
+ if (m_spr_coll_buf[p + i])
+ spr_coll |= m_spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (m_fore_coll_buf[p + i] == 0)
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = col;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = col;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < 24; i++, sdata <<= 1)
+ {
+ if (sdata & 0x80000000)
+ {
+ if (m_fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ if (m_spr_coll_buf[p + i])
+ {
+ spr_coll |= m_spr_coll_buf[p + i] | sbit;
+ }
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (m_fore_coll_buf[p + i] == 0)
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = color;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ m_bitmap->pix16(VIC2_RASTER_2_EMU(m_rasterline), p + i) = color;
+ m_spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (SPRITE_COLL)
+ SPRITE_COLL |= spr_coll;
+ else
+ {
+ SPRITE_COLL = spr_coll;
+ if (SPRITE_COLL)
+ vic2_set_interrupt(4);
+ }
+
+ if (SPRITE_BG_COLL)
+ SPRITE_BG_COLL |= gfx_coll;
+ else
+ {
+ SPRITE_BG_COLL = gfx_coll;
+ if (SPRITE_BG_COLL)
+ vic2_set_interrupt(2);
+ }
+}
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+UINT32 mos6566_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ if (m_on)
+ copybitmap(bitmap, *m_bitmap, 0, 0, 0, 0, cliprect);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( mos6566_device::read )
+{
+ UINT8 val = 0;
+
+ offset &= 0x3f;
+
+ switch (offset)
+ {
+ case 0x11:
+ val = (m_reg[offset] & ~0x80) | ((m_rasterline & 0x100) >> 1);
+ break;
+
+ case 0x12:
+ val = m_rasterline & 0xff;
+ break;
+
+ case 0x16:
+ val = m_reg[offset] | 0xc0;
+ break;
+
+ case 0x18:
+ val = m_reg[offset] | 0x01;
+ break;
+
+ case 0x19: /* interrupt flag register */
+ /* vic2_clear_interrupt(0xf); */
+ val = m_reg[offset] | 0x70;
+ break;
+
+ case 0x1a:
+ val = m_reg[offset] | 0xf0;
+ break;
+
+ case 0x1e: /* sprite to sprite collision detect */
+ val = m_reg[offset];
+ m_reg[offset] = 0;
+ vic2_clear_interrupt(4);
+ break;
+
+ case 0x1f: /* sprite to background collision detect */
+ val = m_reg[offset];
+ m_reg[offset] = 0;
+ vic2_clear_interrupt(2);
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ val = m_reg[offset];
+ break;
+
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ case 0x10:
+ case 0x17:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ val = m_reg[offset];
+ break;
+
+ case 0x2f:
+ case 0x30:
+ if (IS_VICIIE)
+ {
+ val = m_reg[offset];
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ }
+ else
+ val = 0xff;
+ break;
+
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f: /* not used */
+ // val = m_reg[offset]; //
+ val = 0xff;
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ break;
+
+ default:
+ val = m_reg[offset];
+ }
+
+ if ((offset != 0x11) && (offset != 0x12))
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+
+ return val;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE8_MEMBER( mos6566_device::write )
+{
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ offset &= 0x3f;
+
+ switch (offset)
+ {
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ case 0x09:
+ case 0x0b:
+ case 0x0d:
+ case 0x0f:
+ m_reg[offset] = data; /* sprite y positions */
+ break;
+
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ case 0x08:
+ case 0x0a:
+ case 0x0c:
+ case 0x0e:
+ m_reg[offset] = data; /* sprite x positions */
+ break;
+
+ case 0x10:
+ m_reg[offset] = data; /* sprite x positions */
+ break;
+
+ case 0x17: /* sprite y size */
+ m_spr_exp_y |= ~data;
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x1d: /* sprite x size */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x1b: /* sprite background priority */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x1c: /* sprite multicolor mode select */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ /* sprite colors */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x25: /* sprite multicolor */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ m_spritemulti[1] = SPRITE_MULTICOLOR1;
+ }
+ break;
+
+ case 0x26: /* sprite multicolor */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ m_spritemulti[3] = SPRITE_MULTICOLOR2;
+ }
+ break;
+
+ case 0x19:
+ vic2_clear_interrupt(data & 0x0f);
+ break;
+
+ case 0x1a: /* irq mask */
+ m_reg[offset] = data;
+ vic2_set_interrupt(0); // beamrider needs this
+ break;
+
+ case 0x11:
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ if (data & 8)
+ {
+ m_dy_start = ROW25_YSTART;
+ m_dy_stop = ROW25_YSTOP;
+ }
+ else
+ {
+ m_dy_start = ROW24_YSTART;
+ m_dy_stop = ROW24_YSTOP;
+ }
+ }
+ break;
+
+ case 0x12:
+ if (data != m_reg[offset])
+ {
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x16:
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x18:
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ m_videoaddr = VIDEOADDR;
+ m_chargenaddr = CHARGENADDR;
+ m_bitmapaddr = BITMAPADDR;
+ }
+ break;
+
+ case 0x21: /* background color */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ m_colors[0] = BACKGROUNDCOLOR;
+ }
+ break;
+
+ case 0x22: /* background color 1 */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ m_colors[1] = MULTICOLOR1;
+ }
+ break;
+
+ case 0x23: /* background color 2 */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ m_colors[2] = MULTICOLOR2;
+ }
+ break;
+
+ case 0x24: /* background color 3 */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ m_colors[3] = FOREGROUNDCOLOR;
+ }
+ break;
+
+ case 0x20: /* framecolor */
+ if (m_reg[offset] != data)
+ {
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x2f:
+ if (IS_VICIIE)
+ {
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x30:
+ if (IS_VICIIE)
+ {
+ m_reg[offset] = data;
+ }
+ break;
+
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ m_reg[offset] = data;
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ break;
+
+ default:
+ m_reg[offset] = data;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// lp_w - light pen strobe
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( mos6566_device::lp_w )
+{
+}
diff --git a/src/mess/video/mos6566.h b/src/mess/video/mos6566.h
new file mode 100644
index 00000000000..da24d87cb5c
--- /dev/null
+++ b/src/mess/video/mos6566.h
@@ -0,0 +1,488 @@
+/***************************************************************************
+
+ MOS 6566/6567/6569 Video Interface Chip II (VIC-II) emulation
+
+ Copyright the MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+ _____ _____
+ DB6 1 |* \_/ | 40 Vcc
+ DB5 2 | | 39 DB7
+ DB4 3 | | 38 DB8
+ DB3 4 | | 37 DB9
+ DB2 5 | | 36 DB10
+ DB1 6 | | 35 DB11
+ DB0 7 | | 34 A13
+ _IRQ 8 | | 33 A12
+ LP 9 | | 32 A11
+ _CS 10 | MOS6566 | 31 A10
+ R/W 11 | | 30 A9
+ BA 12 | | 29 A8
+ Vdd 13 | | 28 A7
+ COLOR 14 | | 27 A6
+ S/LUM 15 | | 26 A5
+ AEC 16 | | 25 A4
+ PH0 17 | | 24 A3
+ PHIN 18 | | 23 A2
+ PHCOL 19 | | 22 A1
+ Vss 20 |_____________| 21 A0
+
+ _____ _____
+ DB6 1 |* \_/ | 40 Vcc
+ DB5 2 | | 39 DB7
+ DB4 3 | | 38 DB8
+ DB3 4 | | 37 DB9
+ DB2 5 | | 36 DB10
+ DB1 6 | | 35 DB11
+ DB0 7 | | 34 A10
+ _IRQ 8 | | 33 A9
+ LP 9 | MOS6567 | 32 A8
+ _CS 10 | MOS6569 | 31 A7
+ R/W 11 | MOS8562 | 30 A6
+ BA 12 | MOS8565 | 29 A5/A13
+ Vdd 13 | | 28 A4/A12
+ COLOR 14 | | 27 A3/A11
+ S/LUM 15 | | 26 A2/A10
+ AEC 16 | | 25 A1/A9
+ PH0 17 | | 24 A0/A8
+ _RAS 18 | | 23 A11
+ CAS 19 | | 22 PHIN
+ Vss 20 |_____________| 21 PHCL
+
+ _____ _____
+ D6 1 |* \_/ | 48 Vcc
+ D5 2 | | 47 D7
+ D4 3 | | 46 D8
+ D3 4 | | 45 D9
+ D2 5 | | 44 D10
+ D1 6 | | 43 D11
+ D0 7 | | 42 MA10
+ _IRQ 8 | | 41 MA9
+ _LP 9 | | 40 MA8
+ BA 10 | | 39 A7
+ _DMARQST 11 | | 38 A6
+ AEC 12 | MOS8564 | 37 MA5
+ _CS 13 | MOS8566 | 36 MA4
+ R/W 14 | | 35 MA3
+ _DMAACK 15 | | 34 MA2
+ CHROMA 16 | | 33 MA1
+ SYNC/LUM 17 | | 32 MA0
+ 1 MHZ 18 | | 31 MA11
+ _RAS 19 | | 30 PHI IN
+ _CAS 20 | | 29 PHI COLOR
+ MUX 21 | | 28 K2
+ _IOACC 22 | | 27 K1
+ 2 MHZ 23 | | 26 K0
+ Vss 24 |_____________| 25 Z80 PHI
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __MOS656X__
+#define __MOS656X__
+
+#include "emu.h"
+
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_MOS6566_ADD(_tag, _screen_tag, _clock, _config, _videoram_map, _colorram_map) \
+ MCFG_DEVICE_ADD(_tag, MOS6566, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_0, _videoram_map) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_1, _colorram_map) \
+ MCFG_SCREEN_ADD(_screen_tag, RASTER) \
+ MCFG_SCREEN_REFRESH_RATE(VIC6566_VRETRACERATE) \
+ MCFG_SCREEN_SIZE(VIC6567_COLUMNS, VIC6567_LINES) \
+ MCFG_SCREEN_VISIBLE_AREA(0, VIC6567_VISIBLECOLUMNS - 1, 0, VIC6567_VISIBLELINES - 1) \
+ MCFG_SCREEN_UPDATE_DEVICE(_tag, mos6566_device, screen_update) \
+ MCFG_PALETTE_LENGTH(16)
+
+#define MCFG_MOS6567_ADD(_tag, _screen_tag, _clock, _config, _videoram_map, _colorram_map) \
+ MCFG_DEVICE_ADD(_tag, MOS6567, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_0, _videoram_map) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_1, _colorram_map) \
+ MCFG_SCREEN_ADD(_screen_tag, RASTER) \
+ MCFG_SCREEN_REFRESH_RATE(VIC6567_VRETRACERATE) \
+ MCFG_SCREEN_SIZE(VIC6567_COLUMNS, VIC6567_LINES) \
+ MCFG_SCREEN_VISIBLE_AREA(0, VIC6567_VISIBLECOLUMNS - 1, 0, VIC6567_VISIBLELINES - 1) \
+ MCFG_SCREEN_UPDATE_DEVICE(_tag, mos6567_device, screen_update) \
+ MCFG_PALETTE_LENGTH(16)
+
+#define MCFG_MOS8562_ADD(_tag, _screen_tag, _clock, _config, _videoram_map, _colorram_map) \
+ MCFG_DEVICE_ADD(_tag, MOS8562, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_0, _videoram_map) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_1, _colorram_map) \
+ MCFG_SCREEN_ADD(_screen_tag, RASTER) \
+ MCFG_SCREEN_REFRESH_RATE(VIC6567_VRETRACERATE) \
+ MCFG_SCREEN_SIZE(VIC6567_COLUMNS, VIC6567_LINES) \
+ MCFG_SCREEN_VISIBLE_AREA(0, VIC6567_VISIBLECOLUMNS - 1, 0, VIC6567_VISIBLELINES - 1) \
+ MCFG_SCREEN_UPDATE_DEVICE(_tag, mos8562_device, screen_update) \
+ MCFG_PALETTE_LENGTH(16)
+
+#define MCFG_MOS6569_ADD(_tag, _screen_tag, _clock, _config, _videoram_map, _colorram_map) \
+ MCFG_DEVICE_ADD(_tag, MOS6569, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_0, _videoram_map) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_1, _colorram_map) \
+ MCFG_SCREEN_ADD(_screen_tag, RASTER) \
+ MCFG_SCREEN_REFRESH_RATE(VIC6569_VRETRACERATE) \
+ MCFG_SCREEN_SIZE(VIC6569_COLUMNS, VIC6569_LINES) \
+ MCFG_SCREEN_VISIBLE_AREA(0, VIC6569_VISIBLECOLUMNS - 1, 0, VIC6569_VISIBLELINES - 1) \
+ MCFG_SCREEN_UPDATE_DEVICE(_tag, mos6569_device, screen_update) \
+ MCFG_PALETTE_LENGTH(16)
+
+#define MCFG_MOS8565_ADD(_tag, _screen_tag, _clock, _config, _videoram_map, _colorram_map) \
+ MCFG_DEVICE_ADD(_tag, MOS8565, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_0, _videoram_map) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_1, _colorram_map) \
+ MCFG_SCREEN_ADD(_screen_tag, RASTER) \
+ MCFG_SCREEN_REFRESH_RATE(VIC6569_VRETRACERATE) \
+ MCFG_SCREEN_SIZE(VIC6569_COLUMNS, VIC6569_LINES) \
+ MCFG_SCREEN_VISIBLE_AREA(0, VIC6569_VISIBLECOLUMNS - 1, 0, VIC6569_VISIBLELINES - 1) \
+ MCFG_SCREEN_UPDATE_DEVICE(_tag, mos8565_device, screen_update) \
+ MCFG_PALETTE_LENGTH(16)
+
+
+#define MOS6566_INTERFACE(_name) \
+ const mos6566_interface (_name) =
+
+#define MOS6567_INTERFACE(_name) \
+ const mos6566_interface (_name) =
+
+#define MOS6569_INTERFACE(_name) \
+ const mos6566_interface (_name) =
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define VIC6566_CLOCK (XTAL_8MHz / 8) // 1000000
+#define VIC6567R56A_CLOCK (XTAL_8MHz / 8) // 1000000
+#define VIC6567_CLOCK (XTAL_14_31818MHz / 14) // 1022727
+#define VIC6569_CLOCK (XTAL_17_734472MHz / 18) // 985248
+
+#define VIC6566_DOTCLOCK (VIC6566_CLOCK * 8) // 8000000
+#define VIC6567R56A_DOTCLOCK (VIC6567R56A_CLOCK * 8) // 8000000
+#define VIC6567_DOTCLOCK (VIC6567_CLOCK * 8) // 8181818
+#define VIC6569_DOTCLOCK (VIC6569_CLOCK * 8) // 7881988
+
+#define VIC6567_CYCLESPERLINE 65
+#define VIC6569_CYCLESPERLINE 63
+
+#define VIC6567_LINES 263
+#define VIC6569_LINES 312
+
+#define VIC6566_VRETRACERATE ((float)VIC6566_CLOCK / 262 / 64)
+#define VIC6567R56A_VRETRACERATE ((float)VIC6567R56A_CLOCK / 262 / 64)
+#define VIC6567_VRETRACERATE ((float)VIC6567_CLOCK / 263 / 65)
+#define VIC6569_VRETRACERATE ((float)VIC6569_CLOCK / 312 / 63)
+
+#define VIC6566_HRETRACERATE (VIC6566_CLOCK / VIC6566_CYCLESPERLINE)
+#define VIC6567_HRETRACERATE (VIC6567_CLOCK / VIC6567_CYCLESPERLINE)
+#define VIC6569_HRETRACERATE (VIC6569_CLOCK / VIC6569_CYCLESPERLINE)
+
+#define VIC2_HSIZE 320
+#define VIC2_VSIZE 200
+
+#define VIC6567_VISIBLELINES 235
+#define VIC6569_VISIBLELINES 284
+
+#define VIC6567_FIRST_DMA_LINE 0x30
+#define VIC6569_FIRST_DMA_LINE 0x30
+
+#define VIC6567_LAST_DMA_LINE 0xf7
+#define VIC6569_LAST_DMA_LINE 0xf7
+
+#define VIC6567_FIRST_DISP_LINE 0x29
+#define VIC6569_FIRST_DISP_LINE 0x10
+
+#define VIC6567_LAST_DISP_LINE (VIC6567_FIRST_DISP_LINE + VIC6567_VISIBLELINES - 1)
+#define VIC6569_LAST_DISP_LINE (VIC6569_FIRST_DISP_LINE + VIC6569_VISIBLELINES - 1)
+
+#define VIC6567_RASTER_2_EMU(a) ((a >= VIC6567_FIRST_DISP_LINE) ? (a - VIC6567_FIRST_DISP_LINE) : (a + 222))
+#define VIC6569_RASTER_2_EMU(a) (a - VIC6569_FIRST_DISP_LINE)
+
+#define VIC6567_FIRSTCOLUMN 50
+#define VIC6569_FIRSTCOLUMN 50
+
+#define VIC6567_VISIBLECOLUMNS 418
+#define VIC6569_VISIBLECOLUMNS 403
+
+#define VIC6567_X_2_EMU(a) (a)
+#define VIC6569_X_2_EMU(a) (a)
+
+#define VIC6567_STARTVISIBLELINES ((VIC6567_LINES - VIC6567_VISIBLELINES)/2)
+#define VIC6569_STARTVISIBLELINES 16 /* ((VIC6569_LINES - VIC6569_VISIBLELINES)/2) */
+
+#define VIC6567_FIRSTRASTERLINE 34
+#define VIC6569_FIRSTRASTERLINE 0
+
+#define VIC6567_COLUMNS 512
+#define VIC6569_COLUMNS 504
+
+#define VIC6567_STARTVISIBLECOLUMNS ((VIC6567_COLUMNS - VIC6567_VISIBLECOLUMNS)/2)
+#define VIC6569_STARTVISIBLECOLUMNS ((VIC6569_COLUMNS - VIC6569_VISIBLECOLUMNS)/2)
+
+#define VIC6567_FIRSTRASTERCOLUMNS 412
+#define VIC6569_FIRSTRASTERCOLUMNS 404
+
+#define VIC6569_FIRST_X 0x194
+#define VIC6567_FIRST_X 0x19c
+
+#define VIC6569_FIRST_VISIBLE_X 0x1e0
+#define VIC6567_FIRST_VISIBLE_X 0x1e8
+
+#define VIC6569_MAX_X 0x1f7
+#define VIC6567_MAX_X 0x1ff
+
+#define VIC6569_LAST_VISIBLE_X 0x17c
+#define VIC6567_LAST_VISIBLE_X 0x184
+
+#define VIC6569_LAST_X 0x193
+#define VIC6567_LAST_X 0x19b
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+// ======================> mos6566_interface
+
+struct mos6566_interface
+{
+ const char *m_screen_tag;
+ const char *m_cpu_tag;
+
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_rdy_cb;
+
+ devcb_read8 m_in_x_cb;
+ devcb_read8 m_in_y_cb;
+ devcb_read8 m_in_button_cb;
+
+ devcb_read8 m_in_rdy_cb;
+};
+
+
+// ======================> mos6566_device
+
+class mos6566_device : public device_t,
+ public device_memory_interface,
+ public device_execute_interface,
+ public mos6566_interface
+{
+public:
+ // construction/destruction
+ mos6566_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+ mos6566_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+ DECLARE_WRITE_LINE_MEMBER( lp_w );
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ enum
+ {
+ TYPE_6566, // NTSC-M (SRAM)
+ TYPE_6567, // NTSC-M (NMOS)
+ TYPE_8562, // NTSC-M (HMOS)
+ TYPE_8564, // NTSC-M VIC-IIe (C128)
+
+ TYPE_6569, // PAL-B
+ TYPE_6572, // PAL-N
+ TYPE_6573, // PAL-M
+ TYPE_8565, // PAL-B (HMOS)
+ TYPE_8566, // PAL-B VIC-IIe (C128)
+ TYPE_8569 // PAL-N VIC-IIe (C128)
+ };
+
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void execute_run();
+
+ int m_icount;
+ int m_variant;
+
+ const address_space_config m_videoram_space_config;
+ const address_space_config m_colorram_space_config;
+
+ inline void vic2_set_interrupt( int mask );
+ inline void vic2_clear_interrupt( int mask );
+ inline UINT8 read_videoram(offs_t offset);
+ inline UINT8 read_colorram(offs_t offset);
+ inline void vic2_idle_access();
+ inline void vic2_spr_ptr_access( int num );
+ inline void vic2_spr_data_access( int num, int bytenum );
+ inline void vic2_display_if_bad_line();
+ inline void vic2_suspend_cpu();
+ inline void vic2_resume_cpu();
+ inline void vic2_refresh_access();
+ inline void vic2_fetch_if_bad_line();
+ inline void vic2_rc_if_bad_line();
+ inline void vic2_sample_border();
+ inline void vic2_check_sprite_dma();
+ inline void vic2_matrix_access();
+ inline void vic2_graphics_access();
+ inline void vic2_draw_background();
+ inline void vic2_draw_mono( UINT16 p, UINT8 c0, UINT8 c1 );
+ inline void vic2_draw_multi( UINT16 p, UINT8 c0, UINT8 c1, UINT8 c2, UINT8 c3 );
+ void vic2_draw_graphics();
+ void vic2_draw_sprites();
+
+ screen_device *m_screen; // screen which sets bitmap properties
+ cpu_device *m_cpu;
+
+ UINT8 m_rdy_cycles;
+ UINT8 m_reg[0x80];
+
+ int m_on; /* rastering of the screen */
+
+ UINT16 m_chargenaddr, m_videoaddr, m_bitmapaddr;
+
+ bitmap_ind16 *m_bitmap;
+
+ UINT16 m_colors[4], m_spritemulti[4];
+
+ int m_rasterline;
+ UINT64 m_cycles_counter;
+ UINT8 m_cycle;
+ UINT16 m_raster_x;
+ UINT16 m_graphic_x;
+
+ /* convert multicolor byte to background/foreground for sprite collision */
+ UINT16 m_expandx[256];
+ UINT16 m_expandx_multi[256];
+
+ /* Display */
+ UINT16 m_dy_start;
+ UINT16 m_dy_stop;
+
+ /* GFX */
+ UINT8 m_draw_this_line;
+ UINT8 m_is_bad_line;
+ UINT8 m_bad_lines_enabled;
+ UINT8 m_display_state;
+ UINT8 m_char_data;
+ UINT8 m_gfx_data;
+ UINT8 m_color_data;
+ UINT8 m_last_char_data;
+ UINT8 m_matrix_line[40]; // Buffer for video line, read in Bad Lines
+ UINT8 m_color_line[40]; // Buffer for color line, read in Bad Lines
+ UINT8 m_vblanking;
+ UINT16 m_ml_index;
+ UINT8 m_rc;
+ UINT16 m_vc;
+ UINT16 m_vc_base;
+ UINT8 m_ref_cnt;
+
+ /* Sprites */
+ UINT8 m_spr_coll_buf[0x400]; // Buffer for sprite-sprite collisions and priorities
+ UINT8 m_fore_coll_buf[0x400]; // Buffer for foreground-sprite collisions and priorities
+ UINT8 m_spr_draw_data[8][4]; // Sprite data for drawing
+ UINT8 m_spr_exp_y;
+ UINT8 m_spr_dma_on;
+ UINT8 m_spr_draw;
+ UINT8 m_spr_disp_on;
+ UINT16 m_spr_ptr[8];
+ UINT8 m_spr_data[8][4];
+ UINT16 m_mc_base[8]; // Sprite data counter bases
+ UINT16 m_mc[8]; // Sprite data counters
+
+ /* Border */
+ UINT8 m_border_on;
+ UINT8 m_ud_border_on;
+ UINT8 m_border_on_sample[5];
+ UINT8 m_border_color_sample[0x400 / 8]; // Samples of border color at each "displayed" cycle
+
+ /* Cycles */
+ UINT64 m_first_ba_cycle;
+ UINT8 m_device_suspended;
+
+ /* IRQ */
+ devcb_resolved_write_line m_out_irq_func;
+
+ /* RDY */
+ devcb_resolved_write_line m_out_rdy_func;
+ devcb_resolved_read8 m_in_rdy_workaround_func;
+
+ /* lightpen */
+ devcb_resolved_read8 m_in_lightpen_button_func;
+ devcb_resolved_read8 m_in_lightpen_x_func;
+ devcb_resolved_read8 m_in_lightpen_y_func;
+};
+
+
+// ======================> mos6567_device
+
+class mos6567_device : public mos6566_device
+{
+public:
+ // construction/destruction
+ mos6567_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ mos6567_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> mos8562_device
+
+class mos8562_device : public mos6567_device
+{
+public:
+ // construction/destruction
+ mos8562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> mos6569_device
+
+class mos6569_device : public mos6566_device
+{
+public:
+ // construction/destruction
+ mos6569_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ mos6569_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void execute_run();
+};
+
+
+// ======================> mos8565_device
+
+class mos8565_device : public mos6569_device
+{
+public:
+ // construction/destruction
+ mos8565_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// device type definition
+extern const device_type MOS6566;
+extern const device_type MOS6567;
+extern const device_type MOS8562;
+extern const device_type MOS6569;
+extern const device_type MOS8565;
+
+
+
+#endif
diff --git a/src/mess/video/mz700.c b/src/mess/video/mz700.c
new file mode 100644
index 00000000000..02da7fbd0b5
--- /dev/null
+++ b/src/mess/video/mz700.c
@@ -0,0 +1,135 @@
+/***************************************************************************
+ * Sharp MZ700
+ *
+ * video hardware
+ *
+ * Juergen Buchmueller <pullmoll@t-online.de>, Jul 2000
+ *
+ * Reference: http://sharpmz.computingmuseum.com
+ *
+ ***************************************************************************/
+
+#include "emu.h"
+#include "machine/pit8253.h"
+#include "includes/mz700.h"
+
+
+#ifndef VERBOSE
+#define VERBOSE 1
+#endif
+
+#define LOG(N,M,A) \
+ do { \
+ if(VERBOSE>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",machine.time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+
+PALETTE_INIT( mz700 )
+{
+ int i;
+
+ machine.colortable = colortable_alloc(machine, 8);
+
+ for (i = 0; i < 8; i++)
+ colortable_palette_set_color(machine.colortable, i, MAKE_RGB((i & 2) ? 0xff : 0x00, (i & 4) ? 0xff : 0x00, (i & 1) ? 0xff : 0x00));
+
+ for (i = 0; i < 256; i++)
+ {
+ colortable_entry_set_value(machine.colortable, i*2, i & 7);
+ colortable_entry_set_value(machine.colortable, i*2+1, (i >> 4) & 7);
+ }
+}
+
+
+SCREEN_UPDATE_IND16( mz700 )
+{
+ mz_state *state = screen.machine().driver_data<mz_state>();
+ UINT8 *videoram = state->m_videoram;
+ int offs;
+ mz_state *mz = screen.machine().driver_data<mz_state>();
+
+ bitmap.fill(get_black_pen(screen.machine()), cliprect);
+
+ for(offs = 0; offs < 40*25; offs++)
+ {
+ int sx, sy, code, color;
+
+ sy = (offs / 40) * 8;
+ sx = (offs % 40) * 8;
+
+ color = mz->m_colorram[offs];
+ code = videoram[offs] | (color & 0x80) << 1;
+
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], code, color, 0, 0, sx, sy);
+ }
+
+ return 0;
+}
+
+
+/***************************************************************************
+ MZ-800
+***************************************************************************/
+
+VIDEO_START( mz800 )
+{
+ mz_state *mz = machine.driver_data<mz_state>();
+ gfx_element_set_source(machine.gfx[0], mz->m_cgram);
+}
+
+SCREEN_UPDATE_IND16( mz800 )
+{
+ mz_state *state = screen.machine().driver_data<mz_state>();
+ UINT8 *videoram = state->m_videoram;
+ mz_state *mz = screen.machine().driver_data<mz_state>();
+
+ bitmap.fill(get_black_pen(screen.machine()), cliprect);
+
+ if (mz->m_mz700_mode)
+ return SCREEN_UPDATE16_CALL(mz700);
+ else
+ {
+ if (mz->m_hires_mode)
+ {
+
+ }
+ else
+ {
+ int x, y;
+ UINT8 *start_addr = videoram;
+
+ for (x = 0; x < 40; x++)
+ {
+ for (y = 0; y < 200; y++)
+ {
+ bitmap.pix16(y, x * 8 + 0) = BIT(start_addr[x * 8 + y], 0);
+ bitmap.pix16(y, x * 8 + 1) = BIT(start_addr[x * 8 + y], 1);
+ bitmap.pix16(y, x * 8 + 2) = BIT(start_addr[x * 8 + y], 2);
+ bitmap.pix16(y, x * 8 + 3) = BIT(start_addr[x * 8 + y], 3);
+ bitmap.pix16(y, x * 8 + 4) = BIT(start_addr[x * 8 + y], 4);
+ bitmap.pix16(y, x * 8 + 5) = BIT(start_addr[x * 8 + y], 5);
+ bitmap.pix16(y, x * 8 + 6) = BIT(start_addr[x * 8 + y], 6);
+ bitmap.pix16(y, x * 8 + 7) = BIT(start_addr[x * 8 + y], 7);
+ }
+ }
+ }
+
+ return 0;
+ }
+}
+
+/***************************************************************************
+ CGRAM
+***************************************************************************/
+
+WRITE8_MEMBER(mz_state::mz800_cgram_w)
+{
+ m_cgram[offset] = data;
+
+ gfx_element_mark_dirty(machine().gfx[0], offset/8);
+}
diff --git a/src/mess/video/mz80.c b/src/mess/video/mz80.c
new file mode 100644
index 00000000000..19857cfdd8a
--- /dev/null
+++ b/src/mess/video/mz80.c
@@ -0,0 +1,145 @@
+/***************************************************************************
+
+ MZ80 driver by Miodrag Milanovic
+
+ 22/11/2008 Preliminary driver.
+
+****************************************************************************/
+
+#include "includes/mz80.h"
+
+const gfx_layout mz80k_charlayout =
+{
+ 8, 8, /* 8x8 characters */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ {0}, /* no bitplanes; 1 bit per pixel */
+ {0, 1, 2, 3, 4, 5, 6, 7},
+ {0 * 8, 1 * 8, 2 * 8, 3 * 8, 4 * 8, 5 * 8, 6 * 8, 7 * 8},
+ 8*8 /* size of one char */
+};
+
+const gfx_layout mz80kj_charlayout =
+{
+ 8, 8, /* 8x8 characters */
+ 256, /* 256 characters + 256 blanks */
+ 1, /* 1 bits per pixel */
+ {0}, /* no bitplanes; 1 bit per pixel */
+ {7, 6, 5, 4, 3, 2, 1, 0},
+ {0 * 8, 1 * 8, 2 * 8, 3 * 8, 4 * 8, 5 * 8, 6 * 8, 7 * 8},
+ 8*8 /* size of one char */
+};
+
+/* Video hardware */
+VIDEO_START( mz80k )
+{
+ mz80_state *state = machine.driver_data<mz80_state>();
+ state->m_p_chargen = state->memregion("chargen")->base();
+}
+
+SCREEN_UPDATE_IND16( mz80k )
+{
+ mz80_state *state = screen.machine().driver_data<mz80_state>();
+ state->m_mz80k_vertical ^= 1;
+ state->m_mz80k_cursor_cnt++;
+ UINT8 y,ra,chr,gfx;
+ UINT16 x,sy=0,ma=0;
+
+ for(y = 0; y < 25; y++ )
+ {
+ for (ra = 0; ra < 8; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 40; x++)
+ {
+ chr = state->m_p_videoram[x];
+ gfx = state->m_p_chargen[(chr<<3) | ra];
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=40;
+ }
+ return 0;
+}
+
+// same as above except bits are in reverse order
+SCREEN_UPDATE_IND16( mz80kj )
+{
+ mz80_state *state = screen.machine().driver_data<mz80_state>();
+ state->m_mz80k_vertical ^= 1;
+ state->m_mz80k_cursor_cnt++;
+ UINT8 y,ra,chr,gfx;
+ UINT16 x,sy=0,ma=0;
+
+ for(y = 0; y < 25; y++ )
+ {
+ for (ra = 0; ra < 8; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 40; x++)
+ {
+ chr = state->m_p_videoram[x];
+ gfx = state->m_p_chargen[(chr<<3) | ra];
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 0);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 7);
+ }
+ }
+ ma+=40;
+ }
+ return 0;
+}
+
+// has twice as much video ram and uses a scroll register
+SCREEN_UPDATE_IND16( mz80a )
+{
+ mz80_state *state = screen.machine().driver_data<mz80_state>();
+ state->m_mz80k_vertical ^= 1;
+ state->m_mz80k_cursor_cnt++;
+ UINT8 y,ra,chr,gfx;
+ UINT16 x,sy=0, ma=state->m_p_ram[0x17d] | (state->m_p_ram[0x17e] << 8);
+
+ for(y = 0; y < 25; y++ )
+ {
+ for (ra = 0; ra < 8; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 40; x++)
+ {
+ chr = state->m_p_videoram[x&0x7ff];
+ gfx = state->m_p_chargen[(chr<<3) | ra];
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=40;
+ }
+ return 0;
+}
diff --git a/src/mess/video/nascom1.c b/src/mess/video/nascom1.c
new file mode 100644
index 00000000000..9382f0eb5e0
--- /dev/null
+++ b/src/mess/video/nascom1.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+
+ nascom1.c
+
+ Functions to emulate the video hardware of the nascom1.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/nascom1.h"
+
+SCREEN_UPDATE_IND16( nascom1 )
+{
+ nascom1_state *state = screen.machine().driver_data<nascom1_state>();
+ UINT8 *videoram = state->m_videoram;
+ int sy, sx;
+
+ for (sx = 0; sx < 48; sx++)
+ {
+ drawgfx_opaque (bitmap, cliprect,
+ screen.machine().gfx[0], videoram[0x03ca + sx],
+ 1, 0, 0, sx * 8, 0);
+ }
+
+ for (sy = 0; sy < 15; sy++)
+ {
+ for (sx = 0; sx < 48; sx++)
+ {
+ drawgfx_opaque (bitmap, cliprect,
+ screen.machine().gfx[0], videoram[0x000a + (sy * 64) + sx],
+ 1, 0, 0, sx * 8, (sy + 1) * 16);
+ }
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( nascom2 )
+{
+ nascom1_state *state = screen.machine().driver_data<nascom1_state>();
+ UINT8 *videoram = state->m_videoram;
+ int sy, sx;
+
+ for (sx = 0; sx < 48; sx++)
+ {
+ drawgfx_opaque (bitmap, cliprect,
+ screen.machine().gfx[0], videoram[0x03ca + sx],
+ 1, 0, 0, sx * 8, 0);
+ }
+
+ for (sy = 0; sy < 15; sy++)
+ {
+ for (sx = 0; sx < 48; sx++)
+ {
+ drawgfx_opaque (bitmap, cliprect,
+ screen.machine().gfx[0], videoram[0x000a + (sy * 64) + sx],
+ 1, 0, 0, sx * 8, (sy + 1) * 14);
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/nc.c b/src/mess/video/nc.c
new file mode 100644
index 00000000000..f80e56817b7
--- /dev/null
+++ b/src/mess/video/nc.c
@@ -0,0 +1,119 @@
+/***************************************************************************
+
+ nc.c
+
+ Functions to emulate the video hardware of the Amstrad PCW.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/nc.h"
+#include "machine/ram.h"
+
+/***************************************************************************
+ Start the video hardware emulation.
+***************************************************************************/
+
+VIDEO_START( nc )
+{
+}
+
+/* two colours */
+static const unsigned short nc_colour_table[NC_NUM_COLOURS] =
+{
+ 0, 1,2,3
+};
+
+/* black/white */
+static const rgb_t nc_palette[NC_NUM_COLOURS] =
+{
+ MAKE_RGB(0x060, 0x060, 0x060),
+ MAKE_RGB(0x000, 0x000, 0x000),
+ MAKE_RGB(0x080, 0x0a0, 0x060),
+ MAKE_RGB(0x000, 0x000, 0x000)
+};
+
+
+/* Initialise the palette */
+PALETTE_INIT( nc )
+{
+ palette_set_colors(machine, 0, nc_palette, ARRAY_LENGTH(nc_palette));
+}
+
+
+void nc200_video_set_backlight(running_machine &machine, int state)
+{
+ nc_state *drvstate = machine.driver_data<nc_state>();
+ drvstate->m_nc200_backlight = state;
+}
+
+
+/***************************************************************************
+ Draw the game screen in the given bitmap_ind16.
+ Do NOT call osd_update_display() from this function,
+ it will be called by the main emulation engine.
+***************************************************************************/
+SCREEN_UPDATE_IND16( nc )
+{
+ nc_state *state = screen.machine().driver_data<nc_state>();
+ int y;
+ int b;
+ int x;
+ int height, width;
+ int pens[2];
+
+ if (state->m_type==NC_TYPE_200)
+ {
+ height = NC200_SCREEN_HEIGHT;
+ width = NC200_SCREEN_WIDTH;
+
+ if (state->m_nc200_backlight)
+ {
+ pens[0] = 2;
+ pens[1] = 3;
+ }
+ else
+ {
+ pens[0] = 0;
+ pens[1] = 1;
+ }
+ }
+ else
+ {
+ height = NC_SCREEN_HEIGHT;
+ width = NC_SCREEN_WIDTH;
+ pens[0] = 2;
+ pens[1] = 3;
+ }
+
+
+ for (y=0; y<height; y++)
+ {
+ int by;
+ /* 64 bytes per line */
+ char *line_ptr = ((char*)screen.machine().device<ram_device>(RAM_TAG)->pointer()) + state->m_display_memory_start + (y<<6);
+
+ x = 0;
+ for (by=0; by<width>>3; by++)
+ {
+ int px;
+ unsigned char byte;
+
+ byte = line_ptr[0];
+
+ px = x;
+ for (b=0; b<8; b++)
+ {
+ bitmap.pix16(y, px) = pens[(byte>>7) & 0x01];
+ byte = byte<<1;
+ px++;
+ }
+
+ x = px;
+
+ line_ptr = line_ptr+1;
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/nes.c b/src/mess/video/nes.c
new file mode 100644
index 00000000000..7865d848d82
--- /dev/null
+++ b/src/mess/video/nes.c
@@ -0,0 +1,70 @@
+/***************************************************************************
+
+ video/nes.c
+
+ Routines to control the unique NES video hardware/PPU.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/ppu2c0x.h"
+#include "includes/nes.h"
+#include "machine/nes_mmc.h"
+
+static void nes_vh_reset( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ state->m_ppu->set_vidaccess_callback(nes_ppu_vidaccess);
+}
+
+VIDEO_START( nes )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ state->m_last_frame_flip = 0;
+
+ machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(FUNC(nes_vh_reset),&machine));
+}
+
+PALETTE_INIT( nes )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ state->m_ppu->init_palette(machine, 0);
+}
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+SCREEN_UPDATE_IND16( nes )
+{
+ nes_state *state = screen.machine().driver_data<nes_state>();
+
+ /* render the ppu */
+ state->m_ppu->render(bitmap, 0, 0, 0, 0);
+
+ /* if this is a disk system game, check for the flip-disk key */
+ if (state->m_disk_expansion && state->m_pcb_id == NO_BOARD)
+ {
+ // latch this input so it doesn't go at warp speed
+ if ((screen.machine().root_device().ioport("FLIPDISK")->read() & 0x01) && (!state->m_last_frame_flip))
+ {
+ state->m_last_frame_flip = 1;
+ state->m_fds_current_side++;
+ if (state->m_fds_current_side > state->m_fds_sides)
+ state->m_fds_current_side = 0;
+
+ if (state->m_fds_current_side == 0)
+ popmessage("No disk inserted.");
+ else
+ popmessage("Disk set to side %d", state->m_fds_current_side);
+ }
+
+ if (!(screen.machine().root_device().ioport("FLIPDISK")->read() & 0x01))
+ state->m_last_frame_flip = 0;
+ }
+ return 0;
+}
diff --git a/src/mess/video/newbrain.c b/src/mess/video/newbrain.c
new file mode 100644
index 00000000000..bbe25093598
--- /dev/null
+++ b/src/mess/video/newbrain.c
@@ -0,0 +1,132 @@
+#include "includes/newbrain.h"
+#include "newbrain.lh"
+
+void newbrain_state::video_start()
+{
+ /* find memory regions */
+ m_char_rom = memregion("chargen")->base();
+
+ /* register for state saving */
+ save_item(NAME(m_tvcnsl));
+ save_item(NAME(m_tvctl));
+ save_item(NAME(m_tvram));
+ save_item(NAME(m_segment_data));
+}
+
+void newbrain_state::screen_update(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ address_space *program = m_maincpu->memory().space(AS_PROGRAM);
+
+ int y, sx;
+ int columns = (m_tvctl & NEWBRAIN_VIDEO_80L) ? 80 : 40;
+ int excess = (m_tvctl & NEWBRAIN_VIDEO_32_40) ? 24 : 4;
+ int ucr = (m_tvctl & NEWBRAIN_VIDEO_UCR) ? 1 : 0;
+ int fs = (m_tvctl & NEWBRAIN_VIDEO_FS) ? 1 : 0;
+ int rv = (m_tvctl & NEWBRAIN_VIDEO_RV) ? 1 : 0;
+ int gr = 0;
+
+ UINT16 videoram_addr = m_tvram;
+ UINT8 rc = 0;
+
+ for (y = 0; y < 250; y++)
+ {
+ int x = 0;
+
+ for (sx = 0; sx < columns; sx++)
+ {
+ int bit;
+
+ UINT8 videoram_data = program->read_byte(videoram_addr + sx);
+ UINT8 charrom_data;
+
+ if (gr)
+ {
+ /* render video ram data */
+ charrom_data = videoram_data;
+ }
+ else
+ {
+ /* render character rom data */
+ UINT16 charrom_addr = (rc << 8) | ((BIT(videoram_data, 7) & fs) << 7) | (videoram_data & 0x7f);
+ charrom_data = m_char_rom[charrom_addr & 0xfff];
+
+ if ((videoram_data & 0x80) && !fs)
+ {
+ /* invert character */
+ charrom_data ^= 0xff;
+ }
+
+ if ((videoram_data & 0x60) && !ucr)
+ {
+ /* strip bit D0 */
+ charrom_data &= 0xfe;
+ }
+ }
+
+ for (bit = 0; bit < 8; bit++)
+ {
+ int color = BIT(charrom_data, 7) ^ rv;
+
+ bitmap.pix16(y, x++) = color;
+
+ if (columns == 40)
+ {
+ bitmap.pix16(y, x++) = color;
+ }
+
+ charrom_data <<= 1;
+ }
+ }
+
+ if (gr)
+ {
+ /* get new data for each line */
+ videoram_addr += columns;
+ videoram_addr += excess;
+ }
+ else
+ {
+ /* increase row counter */
+ rc++;
+
+ if (rc == (ucr ? 8 : 10))
+ {
+ /* reset row counter */
+ rc = 0;
+
+ videoram_addr += columns;
+ videoram_addr += excess;
+ }
+ }
+ }
+}
+
+UINT32 newbrain_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ if (m_enrg1 & NEWBRAIN_ENRG1_TVP)
+ {
+ screen_update(bitmap, cliprect);
+ }
+ else
+ {
+ bitmap.fill(get_black_pen(machine()), cliprect);
+ }
+
+ return 0;
+}
+
+/* Machine Drivers */
+
+MACHINE_CONFIG_FRAGMENT( newbrain_video )
+ MCFG_DEFAULT_LAYOUT(layout_newbrain)
+
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(newbrain_state, screen_update)
+ MCFG_SCREEN_REFRESH_RATE(50)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
+ MCFG_SCREEN_SIZE(640, 250)
+ MCFG_SCREEN_VISIBLE_AREA(0, 639, 0, 249)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(black_and_white)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/newport.c b/src/mess/video/newport.c
new file mode 100644
index 00000000000..697cf16bd2e
--- /dev/null
+++ b/src/mess/video/newport.c
@@ -0,0 +1,1689 @@
+/*
+ SGI "Newport" graphics board used in the Indy and some Indigo2s
+
+ Newport is modular, consisting of the following custom chips:
+ - REX3: Raster Engine, which is basically a blitter which can also draw antialiased lines.
+ REX also acts as the interface to the rest of the system - all the other chips on
+ a Newport board are accessed through it.
+ - RB2: Frame buffer input controller
+ - RO1: Frame buffer output controller
+ - XMAP9: Final display generator
+ - CMAP: Palette mapper
+ - VC2: Video timing controller / CRTC
+
+ Taken from the Linux Newport driver, slave addresses for Newport devices are:
+ VC2 0
+ Both CMAPs 1
+ CMAP 0 2
+ CMAP 1 3
+ Both XMAPs 4
+ XMAP 0 5
+ XMAP 1 6
+ RAMDAC 7
+ VIDEO (CC1) 8
+ VIDEO (AB1) 9
+*/
+
+#include "emu.h"
+#include "video/newport.h"
+
+#define VERBOSE_LEVEL ( 0 )
+
+INLINE void ATTR_PRINTF(3,4) verboselog(running_machine &machine, int n_level, const char *s_fmt, ... )
+{
+ if( VERBOSE_LEVEL >= n_level )
+ {
+ va_list v;
+ char buf[ 32768 ];
+ va_start( v, s_fmt );
+ vsprintf( buf, s_fmt, v );
+ va_end( v );
+ logerror( "%08x: %s", cpu_get_pc(machine.device("maincpu")), buf );
+ }
+}
+
+static READ32_HANDLER( newport_cmap0_r );
+static WRITE32_HANDLER( newport_cmap0_w );
+static READ32_HANDLER( newport_cmap1_r );
+static READ32_HANDLER( newport_xmap0_r );
+static WRITE32_HANDLER( newport_xmap0_w );
+static READ32_HANDLER( newport_xmap1_r );
+static WRITE32_HANDLER( newport_xmap1_w );
+static READ32_HANDLER( newport_vc2_r );
+static WRITE32_HANDLER( newport_vc2_w );
+
+typedef struct
+{
+ UINT16 nRegister[0x21];
+ UINT16 nRAM[0x8000];
+ UINT8 nRegIdx;
+ UINT16 nRegData;
+} VC2_t;
+
+#define VC2_VIDENTRY pNVID->VC2.nRegister[0x00]
+#define VC2_CURENTRY pNVID->VC2.nRegister[0x01]
+#define VC2_CURSORX pNVID->VC2.nRegister[0x02]
+#define VC2_CURSORY pNVID->VC2.nRegister[0x03]
+#define VC2_CURCURSORX pNVID->VC2.nRegister[0x04]
+#define VC2_DIDENTRY pNVID->VC2.nRegister[0x05]
+#define VC2_SCANLINELEN pNVID->VC2.nRegister[0x06]
+#define VC2_RAMADDR pNVID->VC2.nRegister[0x07]
+#define VC2_VTFRAMEPTR pNVID->VC2.nRegister[0x08]
+#define VC2_VTLINEPTR pNVID->VC2.nRegister[0x09]
+#define VC2_VTLINERUN pNVID->VC2.nRegister[0x0a]
+#define VC2_VLINECNT pNVID->VC2.nRegister[0x0b]
+#define VC2_CURTABLEPTR pNVID->VC2.nRegister[0x0c]
+#define VC2_WORKCURSORY pNVID->VC2.nRegister[0x0d]
+#define VC2_DIDFRAMEPTR pNVID->VC2.nRegister[0x0e]
+#define VC2_DIDLINEPTR pNVID->VC2.nRegister[0x0f]
+#define VC2_DISPLAYCTRL pNVID->VC2.nRegister[0x10]
+#define VC2_CONFIG pNVID->VC2.nRegister[0x1f]
+
+typedef struct
+{
+ UINT32 nRegister[0x08];
+ UINT32 nModeTable[0x20];
+} XMAP_t;
+
+#define XMAP0_CONFIG pNVID->XMAP0.nRegister[0x00]
+#define XMAP0_REVISION pNVID->XMAP0.nRegister[0x01]
+#define XMAP0_ENTRIES pNVID->XMAP0.nRegister[0x02]
+#define XMAP0_CURCMAP pNVID->XMAP0.nRegister[0x03]
+#define XMAP0_POPUPCMAP pNVID->XMAP0.nRegister[0x04]
+#define XMAP0_MODETBLIDX pNVID->XMAP0.nRegister[0x07]
+
+#define XMAP1_CONFIG pNVID->XMAP1.nRegister[0x00]
+#define XMAP1_REVISION pNVID->XMAP1.nRegister[0x01]
+#define XMAP1_ENTRIES pNVID->XMAP1.nRegister[0x02]
+#define XMAP1_CURCMAP pNVID->XMAP1.nRegister[0x03]
+#define XMAP1_POPUPCMAP pNVID->XMAP1.nRegister[0x04]
+#define XMAP1_MODETBLIDX pNVID->XMAP1.nRegister[0x07]
+
+
+typedef struct
+{
+ UINT32 nDrawMode1;
+ UINT32 nDrawMode0;
+ UINT32 nLSMode;
+ UINT32 nLSPattern;
+ UINT32 nLSPatSave;
+ UINT32 nZPattern;
+ UINT32 nColorBack;
+ UINT32 nColorVRAM;
+ UINT32 nAlphaRef;
+ //UINT32 nStall0;
+ UINT32 nSMask0X;
+ UINT32 nSMask0Y;
+ UINT32 nSetup;
+ UINT32 nStepZ;
+ UINT32 nXStart;
+ UINT32 nYStart;
+ UINT32 nXEnd;
+ UINT32 nYEnd;
+ UINT32 nXSave;
+ UINT32 nXYMove;
+ UINT32 nBresD;
+ UINT32 nBresS1;
+ UINT32 nBresOctInc1;
+ UINT32 nBresRndInc2;
+ UINT32 nBresE1;
+ UINT32 nBresS2;
+ UINT32 nAWeight0;
+ UINT32 nAWeight1;
+ UINT32 nXStartF;
+ UINT32 nYStartF;
+ UINT32 nXEndF;
+ UINT32 nYEndF;
+ UINT32 nXStartI;
+ //UINT32 nYEndF1;
+ UINT32 nXYStartI;
+ UINT32 nXYEndI;
+ UINT32 nXStartEndI;
+ UINT32 nColorRed;
+ UINT32 nColorAlpha;
+ UINT32 nColorGreen;
+ UINT32 nColorBlue;
+ UINT32 nSlopeRed;
+ UINT32 nSlopeAlpha;
+ UINT32 nSlopeGreen;
+ UINT32 nSlopeBlue;
+ UINT32 nWriteMask;
+ UINT32 nZeroFract;
+ UINT32 nZeroOverflow;
+ //UINT32 nColorIndex;
+ UINT32 nHostDataPortMSW;
+ UINT32 nHostDataPortLSW;
+ UINT32 nDCBMode;
+ UINT32 nDCBRegSelect;
+ UINT32 nDCBSlvSelect;
+ UINT32 nDCBDataMSW;
+ UINT32 nDCBDataLSW;
+ UINT32 nSMask1X;
+ UINT32 nSMask1Y;
+ UINT32 nSMask2X;
+ UINT32 nSMask2Y;
+ UINT32 nSMask3X;
+ UINT32 nSMask3Y;
+ UINT32 nSMask4X;
+ UINT32 nSMask4Y;
+ UINT32 nTopScanline;
+ UINT32 nXYWin;
+ UINT32 nClipMode;
+ UINT32 nConfig;
+ UINT32 nStatus;
+ UINT8 nXFerWidth;
+#if 0
+ UINT32 nCurrentX;
+ UINT32 nCurrentY;
+#endif
+ UINT32 nKludge_SkipLine;
+} REX3_t;
+
+
+typedef struct
+{
+ UINT16 nPaletteIndex;
+ UINT32 nPalette[0x10000];
+} CMAP_t;
+
+typedef struct _newport_video_t newport_video_t;
+struct _newport_video_t
+{
+ VC2_t VC2;
+ XMAP_t XMAP0;
+ XMAP_t XMAP1;
+ REX3_t REX3;
+ UINT32 *base;
+ UINT8 nDrawGreen;
+ CMAP_t CMAP0;
+};
+static newport_video_t *pNVID;
+
+VIDEO_START( newport )
+{
+ pNVID = auto_alloc_clear(machine, newport_video_t);
+ pNVID->nDrawGreen = 0;
+ pNVID->REX3.nDrawMode0 = 0x00000000;
+ pNVID->REX3.nDrawMode1 = 0x3002f001;
+ pNVID->REX3.nDCBMode = 0x00000780;
+ pNVID->REX3.nKludge_SkipLine = 0;
+ pNVID->base = auto_alloc_array_clear(machine, UINT32, (1280+64) * (1024+64));
+}
+
+SCREEN_UPDATE_RGB32( newport )
+{
+ int y;
+
+ bitmap.fill(get_black_pen(screen.machine()), cliprect );
+
+ /* loop over rows and copy to the destination */
+ for( y = cliprect.min_y; y <= cliprect.max_y; y++ )
+ {
+ UINT32 *src = &pNVID->base[1344 * y];
+ UINT32 *dest = &bitmap.pix32(y, cliprect.min_x);
+ int x;
+
+ /* loop over columns */
+ for( x = cliprect.min_x; x < cliprect.max_x; x++ )
+ {
+ *dest++ = (*src++) & 0x00f8f8f8;
+ }
+ }
+ return 0;
+}
+
+static WRITE32_HANDLER( newport_cmap0_w )
+{
+ //running_machine &machine = space->machine();
+
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0x00:
+ //verboselog(machine, 2, "CMAP0 Palette Index Write: %04x\n", data & 0x0000ffff );
+ pNVID->CMAP0.nPaletteIndex = data & 0x0000ffff;
+ break;
+ case 0x02:
+ //verboselog(machine, 2, "CMAP0 Palette Entry %04x Write: %08x\n", pNVID->CMAP0.nPaletteIndex, ( data >> 8 ) & 0x00ffffff );
+ pNVID->CMAP0.nPalette[pNVID->CMAP0.nPaletteIndex] = ( data >> 8 ) & 0x00ffffff;
+ break;
+ default:
+ //verboselog(machine, 2, "Unknown CMAP0 Register %d Write: %08x\n", pNVID->REX3.nDCBRegSelect, data );
+ break;
+ }
+}
+
+static READ32_HANDLER( newport_cmap0_r )
+{
+ //running_machine &machine = space->machine();
+
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0x04:
+ //verboselog(machine, 2, "CMAP0 Status Read: %08x\n", 0x00000008 );
+ return 0x00000008;
+ case 0x06: /* Revision */
+ //verboselog(machine, 2, "CMAP0 Revision Read: CMAP Rev 1, Board Rev 2, 8bpp\n" );
+ return 0x000000a1;
+ default:
+ //verboselog(machine, 2, "Unknown CMAP0 Register %d Read\n", pNVID->REX3.nDCBRegSelect );
+ return 0x00000000;
+ }
+}
+
+static READ32_HANDLER( newport_cmap1_r )
+{
+ //running_machine &machine = space->machine();
+
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0x04:
+ //verboselog(machine, 2, "CMAP1 Status Read: %08x\n", 0x00000008 );
+ return 0x00000008;
+ case 0x06: /* Revision */
+ //verboselog(machine, 2, "CMAP1 Revision Read: CMAP Rev 1, Board Rev 2, 8bpp\n" );
+ return 0x000000a1;
+ default:
+ //verboselog(machine, 2, "Unknown CMAP0 Register %d Read\n", pNVID->REX3.nDCBRegSelect );
+ return 0x00000000;
+ }
+}
+
+static READ32_HANDLER( newport_xmap0_r )
+{
+ UINT8 nModeIdx;
+ //running_machine &machine = space->machine();
+
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0:
+ //verboselog(machine, 2, "XMAP0 Config Read: %08x\n", XMAP0_CONFIG );
+ return XMAP0_CONFIG;
+ case 1:
+ //verboselog(machine, 2, "XMAP0 Revision Read: %08x\n", 0x00 );
+ return 0x00000000;
+ case 2:
+ //verboselog(machine, 2, "XMAP0 FIFO Availability Read: %08x\n", 0x02 );
+ return 0x00000002;
+ case 3:
+ //verboselog(machine, 2, "XMAP0 Cursor CMAP MSB Read: %08x\n", XMAP0_CURCMAP );
+ return XMAP0_CURCMAP;
+ case 4:
+ //verboselog(machine, 2, "XMAP0 Pop Up CMAP MSB Read: %08x\n", XMAP0_POPUPCMAP );
+ return XMAP0_POPUPCMAP;
+ case 5:
+ nModeIdx = ( XMAP0_MODETBLIDX & 0x0000007c ) >> 2;
+ switch( XMAP0_MODETBLIDX & 0x00000003 )
+ {
+ case 0:
+ //verboselog(machine, 2, "XMAP0 Mode Register Read: %02x (Byte 0): %08x\n", nModeIdx, ( pNVID->XMAP0.nModeTable[ nModeIdx ] & 0x00ff0000 ) >> 16 );
+ return ( pNVID->XMAP0.nModeTable[ nModeIdx ] & 0x00ff0000 ) >> 16;
+ case 1:
+ //verboselog(machine, 2, "XMAP0 Mode Register Read: %02x (Byte 1): %08x\n", nModeIdx, ( pNVID->XMAP0.nModeTable[ nModeIdx ] & 0x0000ff00 ) >> 8 );
+ return ( pNVID->XMAP0.nModeTable[ nModeIdx ] & 0x0000ff00 ) >> 8;
+ case 2:
+ //verboselog(machine, 2, "XMAP0 Mode Register Read: %02x (Byte 2): %08x\n", nModeIdx, ( pNVID->XMAP0.nModeTable[ nModeIdx ] & 0x000000ff ) );
+ return ( pNVID->XMAP0.nModeTable[ nModeIdx ] & 0x000000ff );
+ }
+ break;
+ case 6:
+ //verboselog(machine, 2, "XMAP0 Unused Read: %08x\n", 0x00000000 );
+ return 0x00000000;
+ case 7:
+ //verboselog(machine, 2, "XMAP0 Mode Table Address Read: %08x\n", XMAP0_MODETBLIDX );
+ return XMAP0_MODETBLIDX;
+ }
+
+ //verboselog(machine, 2, "XMAP0 Unknown pNVID->REX3.nDCBRegSelect Value: %02x, returning 0\n", pNVID->REX3.nDCBRegSelect );
+ return 0x00000000;
+}
+
+static WRITE32_HANDLER( newport_xmap0_w )
+{
+ UINT8 n8BitVal = data & 0x000000ff;
+ //running_machine &machine = space->machine();
+
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0:
+ //verboselog(machine, 2, "XMAP0 Config Write: %02x\n", n8BitVal );
+ XMAP0_CONFIG = n8BitVal;
+ break;
+ case 1:
+ //verboselog(machine, 2, "XMAP0 Revision Write (Ignored): %02x\n", n8BitVal );
+ break;
+ case 2:
+ //verboselog(machine, 2, "XMAP0 FIFO Availability Write (Ignored): %02x\n", n8BitVal );
+ break;
+ case 3:
+ //verboselog(machine, 2, "XMAP0 Cursor CMAP MSB Write: %02x\n", n8BitVal );
+ XMAP0_CURCMAP = n8BitVal;
+ break;
+ case 4:
+ //verboselog(machine, 2, "XMAP0 Pop Up CMAP MSB Write: %02x\n", n8BitVal );
+ XMAP0_POPUPCMAP = n8BitVal;
+ break;
+ case 5:
+ //verboselog(machine, 2, "XMAP0 Mode Register Write: %02x = %06x\n", ( data & 0xff000000 ) >> 24, data & 0x00ffffff );
+ pNVID->XMAP0.nModeTable[ ( data & 0xff000000 ) >> 24 ] = data & 0x00ffffff;
+ break;
+ case 6:
+ //verboselog(machine, 2, "XMAP0 Unused Write (Ignored): %08x\n", data );
+ break;
+ case 7:
+ //verboselog(machine, 2, "XMAP0 Mode Table Address Write: %02x\n", n8BitVal );
+ XMAP0_MODETBLIDX = n8BitVal;
+ break;
+ }
+}
+
+static READ32_HANDLER( newport_xmap1_r )
+{
+ UINT8 nModeIdx;
+ //running_machine &machine = space->machine();
+
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0:
+ //verboselog(machine, 2, "XMAP1 Config Read: %08x\n", XMAP1_CONFIG );
+ return XMAP1_CONFIG;
+ case 1:
+ //verboselog(machine, 2, "XMAP1 Revision Read: %08x\n", 0x00 );
+ return 0x00000000;
+ case 2:
+ //verboselog(machine, 2, "XMAP1 FIFO Availability Read: %08x\n", 0x02 );
+ return 0x00000002;
+ case 3:
+ //verboselog(machine, 2, "XMAP1 Cursor CMAP MSB Read: %08x\n", XMAP1_CURCMAP );
+ return XMAP1_CURCMAP;
+ case 4:
+ //verboselog(machine, 2, "XMAP1 Pop Up CMAP MSB Read: %08x\n", XMAP1_POPUPCMAP );
+ return XMAP1_POPUPCMAP;
+ case 5:
+ nModeIdx = ( XMAP1_MODETBLIDX & 0x0000007c ) >> 2;
+ switch( XMAP1_MODETBLIDX & 0x00000003 )
+ {
+ case 0:
+ //verboselog(machine, 2, "XMAP1 Mode Register Read: %02x (Byte 0): %08x\n", nModeIdx, ( pNVID->XMAP1.nModeTable[ nModeIdx ] & 0x00ff0000 ) >> 16 );
+ return ( pNVID->XMAP1.nModeTable[ nModeIdx ] & 0x00ff0000 ) >> 16;
+ case 1:
+ //verboselog(machine, 2, "XMAP1 Mode Register Read: %02x (Byte 1): %08x\n", nModeIdx, ( pNVID->XMAP1.nModeTable[ nModeIdx ] & 0x0000ff00 ) >> 8 );
+ return ( pNVID->XMAP1.nModeTable[ nModeIdx ] & 0x0000ff00 ) >> 8;
+ case 2:
+ //verboselog(machine, 2, "XMAP1 Mode Register Read: %02x (Byte 2): %08x\n", nModeIdx, ( pNVID->XMAP1.nModeTable[ nModeIdx ] & 0x000000ff ) );
+ return ( pNVID->XMAP1.nModeTable[ nModeIdx ] & 0x000000ff );
+ }
+ break;
+ case 6:
+ //verboselog(machine, 2, "XMAP1 Unused Read: %08x\n", 0x00000000 );
+ return 0x00000000;
+ case 7:
+ //verboselog(machine, 2, "XMAP1 Mode Table Address Read: %08x\n", XMAP0_MODETBLIDX );
+ return XMAP1_MODETBLIDX;
+ }
+
+ //verboselog(machine, 2, "XMAP1 Unknown pNVID->REX3.nDCBRegSelect Value: %02x, returning 0\n", pNVID->REX3.nDCBRegSelect );
+ return 0x00000000;
+}
+
+static WRITE32_HANDLER( newport_xmap1_w )
+{
+ UINT8 n8BitVal = data & 0x000000ff;
+ //running_machine &machine = space->machine();
+
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0:
+ //verboselog(machine, 2, "XMAP1 Config Write: %02x\n", n8BitVal );
+ XMAP1_CONFIG = n8BitVal;
+ break;
+ case 1:
+ //verboselog(machine, 2, "XMAP1 Revision Write (Ignored): %02x\n", n8BitVal );
+ break;
+ case 2:
+ //verboselog(machine, 2, "XMAP1 FIFO Availability Write (Ignored): %02x\n", n8BitVal );
+ break;
+ case 3:
+ //verboselog(machine, 2, "XMAP1 Cursor CMAP MSB Write: %02x\n", n8BitVal );
+ XMAP1_CURCMAP = n8BitVal;
+ break;
+ case 4:
+ //verboselog(machine, 2, "XMAP1 Pop Up CMAP MSB Write: %02x\n", n8BitVal );
+ XMAP1_POPUPCMAP = n8BitVal;
+ break;
+ case 5:
+ //verboselog(machine, 2, "XMAP1 Mode Register Write: %02x = %06x\n", ( data & 0xff000000 ) >> 24, data & 0x00ffffff );
+ pNVID->XMAP1.nModeTable[ ( data & 0xff000000 ) >> 24 ] = data & 0x00ffffff;
+ break;
+ case 6:
+ //verboselog(machine, 2, "XMAP1 Unused Write (Ignored): %08x\n", data );
+ break;
+ case 7:
+ //verboselog(machine, 2, "XMAP1 Mode Table Address Write: %02x\n", n8BitVal );
+ XMAP1_MODETBLIDX = n8BitVal;
+ break;
+ }
+}
+
+static READ32_HANDLER( newport_vc2_r )
+{
+ UINT16 ret16;
+ //running_machine &machine = space->machine();
+
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0x01: /* Register Read */
+ //verboselog(machine, 2, "VC2 Register Read: %02x, %08x\n", pNVID->VC2.nRegIdx, pNVID->VC2.nRegister[pNVID->VC2.nRegIdx] );
+ return pNVID->VC2.nRegister[pNVID->VC2.nRegIdx];
+ case 0x03: /* RAM Read */
+ //verboselog(machine, 2, "VC2 RAM Read: %04x = %08x\n", VC2_RAMADDR, pNVID->VC2.nRAM[VC2_RAMADDR] );
+ ret16 = pNVID->VC2.nRAM[VC2_RAMADDR];
+ VC2_RAMADDR++;
+ if( VC2_RAMADDR == 0x8000 )
+ {
+ VC2_RAMADDR = 0x0000;
+ }
+ return ret16;
+ default:
+ //verboselog(machine, 2, "Unknown VC2 Register Read: %02x\n", pNVID->REX3.nDCBRegSelect );
+ return 0;
+ }
+ return 0;
+}
+
+static WRITE32_HANDLER( newport_vc2_w )
+{
+ //running_machine &machine = space->machine();
+
+ switch( pNVID->REX3.nXFerWidth )
+ {
+ case 0x01: /* Register Select */
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0x00:
+ pNVID->VC2.nRegIdx = ( data & 0x000000ff ) >> 0;
+ //verboselog(machine, 2, "VC2 Register Select: %02x\n", pNVID->VC2.nRegIdx );
+ break;
+ default:
+ //verboselog(machine, 2, "Unknown VC2 Register Select: DCB Register %02x, data = 0x%08x\n", pNVID->REX3.nDCBRegSelect, data );
+ break;
+ }
+ break;
+ case 0x02: /* RAM Write */
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0x03:
+ //verboselog(machine, 2, "VC2 RAM Write: %04x = %08x\n", VC2_RAMADDR, data & 0x0000ffff );
+ pNVID->VC2.nRAM[VC2_RAMADDR] = data & 0x0000ffff;
+ VC2_RAMADDR++;
+ if( VC2_RAMADDR == 0x8000 )
+ {
+ VC2_RAMADDR = 0x0000;
+ }
+ break;
+ default:
+ //verboselog(machine, 2, "Unknown 2-byte Write: DCB Register %02x, data = 0x%08x\n", pNVID->REX3.nDCBRegSelect, data );
+ break;
+ }
+ break;
+ case 0x03: /* Register Write */
+ switch( pNVID->REX3.nDCBRegSelect )
+ {
+ case 0x00:
+ //verboselog(machine, 2, "VC2 Register Setup:\n" );
+ pNVID->VC2.nRegIdx = ( data & 0xff000000 ) >> 24;
+ pNVID->VC2.nRegData = ( data & 0x00ffff00 ) >> 8;
+ switch( pNVID->VC2.nRegIdx )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " Video Entry Pointer: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " Cursor Entry Pointer: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " Cursor X Location: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " Cursor Y Location: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x04:
+ //verboselog(machine, 2, " Current Cursor X: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x05:
+ //verboselog(machine, 2, " DID Entry Pointer: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x06:
+ //verboselog(machine, 2, " Scanline Length: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x07:
+ //verboselog(machine, 2, " RAM Address: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x08:
+ //verboselog(machine, 2, " VT Frame Table Ptr: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x09:
+ //verboselog(machine, 2, " VT Line Sequence Ptr: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x0a:
+ //verboselog(machine, 2, " VT Lines in Run: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x0b:
+ //verboselog(machine, 2, " Vertical Line Count: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x0c:
+ //verboselog(machine, 2, " Cursor Table Ptr: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x0d:
+ //verboselog(machine, 2, " Working Cursor Y: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x0e:
+ //verboselog(machine, 2, " DID Frame Table Ptr: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x0f:
+ //verboselog(machine, 2, " DID Line Table Ptr: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x10:
+ //verboselog(machine, 2, " Display Control: %04x\n", pNVID->VC2.nRegData );
+ break;
+ case 0x1f:
+ //verboselog(machine, 2, " Configuration: %04x\n", pNVID->VC2.nRegData );
+ pNVID->VC2.nRegister[0x20] = pNVID->VC2.nRegData;
+ break;
+ default:
+ //verboselog(machine, 2, " Unknown VC2 Register: %04x\n", pNVID->VC2.nRegData );
+ break;
+ }
+ pNVID->VC2.nRegister[pNVID->VC2.nRegIdx] = pNVID->VC2.nRegData;
+ break;
+ default:
+ //verboselog(machine, 2, "Unknown VC2 Register Write: %02x = %08x\n", pNVID->REX3.nDCBRegSelect, data );
+ break;
+ }
+ break;
+ default:
+ //verboselog(machine, 2, "Unknown VC2 XFer Width: Width %02x, DCB Register %02x, Value 0x%08x\n", pNVID->REX3.nXFerWidth, pNVID->REX3.nDCBRegSelect, data );
+ break;
+ }
+}
+
+READ32_HANDLER( newport_rex3_r )
+{
+// UINT32 nTemp;
+ //running_machine &machine = space->machine();
+
+// if( offset >= ( 0x0800 / 4 ) )
+// {
+// //verboselog(machine, 2, "%08x:\n", 0xbf0f0000 + ( offset << 2 ) );
+// }
+ switch( offset )
+ {
+ case 0x0000/4:
+ case 0x0800/4:
+ //verboselog(machine, 2, "REX3 Draw Mode 1 Read: %08x\n", pNVID->REX3.nDrawMode1 );
+ return pNVID->REX3.nDrawMode1;
+ case 0x0004/4:
+ case 0x0804/4:
+ //verboselog(machine, 2, "REX3 Draw Mode 0 Read: %08x\n", pNVID->REX3.nDrawMode0 );
+ return pNVID->REX3.nDrawMode0;
+ case 0x0008/4:
+ case 0x0808/4:
+ //verboselog(machine, 2, "REX3 Line Stipple Mode Read: %08x\n", pNVID->REX3.nLSMode );
+ return pNVID->REX3.nLSMode;
+ case 0x000c/4:
+ case 0x080c/4:
+ //verboselog(machine, 2, "REX3 Line Stipple Pattern Read: %08x\n", pNVID->REX3.nLSPattern );
+ return pNVID->REX3.nLSPattern;
+ case 0x0010/4:
+ case 0x0810/4:
+ //verboselog(machine, 2, "REX3 Line Stipple Pattern (Save) Read: %08x\n", pNVID->REX3.nLSPatSave );
+ return pNVID->REX3.nLSPatSave;
+ case 0x0014/4:
+ case 0x0814/4:
+ //verboselog(machine, 2, "REX3 Pattern Register Read: %08x\n", pNVID->REX3.nZPattern );
+ return pNVID->REX3.nZPattern;
+ case 0x0018/4:
+ case 0x0818/4:
+ //verboselog(machine, 2, "REX3 Opaque Pattern / Blendfunc Dest Color Read: %08x\n", pNVID->REX3.nColorBack );
+ return pNVID->REX3.nColorBack;
+ case 0x001c/4:
+ case 0x081c/4:
+ //verboselog(machine, 2, "REX3 VRAM Fastclear Color Read: %08x\n", pNVID->REX3.nColorVRAM );
+ return pNVID->REX3.nColorVRAM;
+ case 0x0020/4:
+ case 0x0820/4:
+ //verboselog(machine, 2, "REX3 AFUNCTION Reference Alpha Read: %08x\n", pNVID->REX3.nAlphaRef );
+ return pNVID->REX3.nAlphaRef;
+ case 0x0028/4:
+ case 0x0828/4:
+ //verboselog(machine, 2, "REX3 Screenmask 0 X Min/Max Read: %08x\n", pNVID->REX3.nSMask0X );
+ return pNVID->REX3.nSMask0X;
+ case 0x002c/4:
+ case 0x082c/4:
+ //verboselog(machine, 2, "REX3 Screenmask 0 Y Min/Max Read: %08x\n", pNVID->REX3.nSMask0Y );
+ return pNVID->REX3.nSMask0Y;
+ case 0x0030/4:
+ case 0x0830/4:
+ //verboselog(machine, 2, "REX3 Line/Span Setup Read: %08x\n", pNVID->REX3.nSetup );
+ return pNVID->REX3.nSetup;
+ case 0x0034/4:
+ case 0x0834/4:
+ //verboselog(machine, 2, "REX3 ZPattern Enable Read: %08x\n", pNVID->REX3.nStepZ );
+ return pNVID->REX3.nStepZ;
+ case 0x0100/4:
+ case 0x0900/4:
+ //verboselog(machine, 2, "REX3 X Start Read: %08x\n", pNVID->REX3.nXStart );
+ return pNVID->REX3.nXStart;
+ case 0x0104/4:
+ case 0x0904/4:
+ //verboselog(machine, 2, "REX3 YStart Read: %08x\n", pNVID->REX3.nYStart );
+ return pNVID->REX3.nYStart;
+ case 0x0108/4:
+ case 0x0908/4:
+ //verboselog(machine, 2, "REX3 XEnd Read: %08x\n", pNVID->REX3.nXEnd );
+ return pNVID->REX3.nXEnd;
+ case 0x010c/4:
+ case 0x090c/4:
+ //verboselog(machine, 2, "REX3 YEnd Read: %08x\n", pNVID->REX3.nYEnd );
+ return pNVID->REX3.nYEnd;
+ case 0x0110/4:
+ case 0x0910/4:
+ //verboselog(machine, 2, "REX3 XSave Read: %08x\n", pNVID->REX3.nXSave );
+ return pNVID->REX3.nXSave;
+ case 0x0114/4:
+ case 0x0914/4:
+ //verboselog(machine, 2, "REX3 XYMove Read: %08x\n", pNVID->REX3.nXYMove );
+ return pNVID->REX3.nXYMove;
+ case 0x0118/4:
+ case 0x0918/4:
+ //verboselog(machine, 2, "REX3 Bresenham D Read: %08x\n", pNVID->REX3.nBresD );
+ return pNVID->REX3.nBresD;
+ case 0x011c/4:
+ case 0x091c/4:
+ //verboselog(machine, 2, "REX3 Bresenham S1 Read: %08x\n", pNVID->REX3.nBresS1 );
+ return pNVID->REX3.nBresS1;
+ case 0x0120/4:
+ case 0x0920/4:
+ //verboselog(machine, 2, "REX3 Bresenham Octant & Incr1 Read: %08x\n", pNVID->REX3.nBresOctInc1 );
+ return pNVID->REX3.nBresOctInc1;
+ case 0x0124/4:
+ case 0x0924/4:
+ //verboselog(machine, 2, "REX3 Bresenham Octant Rounding Mode & Incr2 Read: %08x\n", pNVID->REX3.nBresRndInc2 );
+ return pNVID->REX3.nBresRndInc2;
+ case 0x0128/4:
+ case 0x0928/4:
+ //verboselog(machine, 2, "REX3 Bresenham E1 Read: %08x\n", pNVID->REX3.nBresE1 );
+ return pNVID->REX3.nBresE1;
+ case 0x012c/4:
+ case 0x092c/4:
+ //verboselog(machine, 2, "REX3 Bresenham S2 Read: %08x\n", pNVID->REX3.nBresS2 );
+ return pNVID->REX3.nBresS2;
+ case 0x0130/4:
+ case 0x0930/4:
+ //verboselog(machine, 2, "REX3 AA Line Weight Table 1/2 Read: %08x\n", pNVID->REX3.nAWeight0 );
+ return pNVID->REX3.nAWeight0;
+ case 0x0134/4:
+ case 0x0934/4:
+ //verboselog(machine, 2, "REX3 AA Line Weight Table 2/2 Read: %08x\n", pNVID->REX3.nAWeight1 );
+ return pNVID->REX3.nAWeight1;
+ case 0x0138/4:
+ case 0x0938/4:
+ //verboselog(machine, 2, "REX3 GL XStart Read: %08x\n", pNVID->REX3.nXStartF );
+ return pNVID->REX3.nXStartF;
+ case 0x013c/4:
+ case 0x093c/4:
+ //verboselog(machine, 2, "REX3 GL YStart Read: %08x\n", pNVID->REX3.nYStartF );
+ return pNVID->REX3.nYStartF;
+ case 0x0140/4:
+ case 0x0940/4:
+ //verboselog(machine, 2, "REX3 GL XEnd Read: %08x\n", pNVID->REX3.nXEndF );
+ return pNVID->REX3.nXEndF;
+ case 0x0144/4:
+ case 0x0944/4:
+ //verboselog(machine, 2, "REX3 GL YEnd Read: %08x\n", pNVID->REX3.nYEndF );
+ return pNVID->REX3.nYEndF;
+ case 0x0148/4:
+ case 0x0948/4:
+ //verboselog(machine, 2, "REX3 XStart (integer) Read: %08x\n", pNVID->REX3.nXStartI );
+ return pNVID->REX3.nXStartI;
+ case 0x014c/4:
+ case 0x094c/4:
+ //verboselog(machine, 2, "REX3 GL XEnd (copy) Read: %08x\n", pNVID->REX3.nXEndF );
+ return pNVID->REX3.nXEndF;
+ case 0x0150/4:
+ case 0x0950/4:
+ //verboselog(machine, 2, "REX3 XYStart (integer) Read: %08x\n", pNVID->REX3.nXYStartI );
+ return pNVID->REX3.nXYStartI;
+ case 0x0154/4:
+ case 0x0954/4:
+ //verboselog(machine, 2, "REX3 XYEnd (integer) Read: %08x\n", pNVID->REX3.nXYEndI );
+ return pNVID->REX3.nXYEndI;
+ case 0x0158/4:
+ case 0x0958/4:
+ //verboselog(machine, 2, "REX3 XStartEnd (integer) Read: %08x\n", pNVID->REX3.nXStartEndI );
+ return pNVID->REX3.nXStartEndI;
+ case 0x0200/4:
+ case 0x0a00/4:
+ //verboselog(machine, 2, "REX3 Red/CI Full State Read: %08x\n", pNVID->REX3.nColorRed );
+ return pNVID->REX3.nColorRed;
+ case 0x0204/4:
+ case 0x0a04/4:
+ //verboselog(machine, 2, "REX3 Alpha Full State Read: %08x\n", pNVID->REX3.nColorAlpha );
+ return pNVID->REX3.nColorAlpha;
+ case 0x0208/4:
+ case 0x0a08/4:
+ //verboselog(machine, 2, "REX3 Green Full State Read: %08x\n", pNVID->REX3.nColorGreen );
+ return pNVID->REX3.nColorGreen;
+ case 0x020c/4:
+ case 0x0a0c/4:
+ //verboselog(machine, 2, "REX3 Blue Full State Read: %08x\n", pNVID->REX3.nColorBlue );
+ return pNVID->REX3.nColorBlue;
+ case 0x0210/4:
+ case 0x0a10/4:
+ //verboselog(machine, 2, "REX3 Red/CI Slope Read: %08x\n", pNVID->REX3.nSlopeRed );
+ return pNVID->REX3.nSlopeRed;
+ case 0x0214/4:
+ case 0x0a14/4:
+ //verboselog(machine, 2, "REX3 Alpha Slope Read: %08x\n", pNVID->REX3.nSlopeAlpha );
+ return pNVID->REX3.nSlopeAlpha;
+ case 0x0218/4:
+ case 0x0a18/4:
+ //verboselog(machine, 2, "REX3 Green Slope Read: %08x\n", pNVID->REX3.nSlopeGreen );
+ return pNVID->REX3.nSlopeGreen;
+ case 0x021c/4:
+ case 0x0a1c/4:
+ //verboselog(machine, 2, "REX3 Blue Slope Read: %08x\n", pNVID->REX3.nSlopeBlue );
+ return pNVID->REX3.nSlopeBlue;
+ case 0x0220/4:
+ case 0x0a20/4:
+ //verboselog(machine, 2, "REX3 Write Mask Read: %08x\n", pNVID->REX3.nWriteMask );
+ return pNVID->REX3.nWriteMask;
+ case 0x0224/4:
+ case 0x0a24/4:
+ //verboselog(machine, 2, "REX3 Packed Color Fractions Read: %08x\n", pNVID->REX3.nZeroFract );
+ return pNVID->REX3.nZeroFract;
+ case 0x0228/4:
+ case 0x0a28/4:
+ //verboselog(machine, 2, "REX3 Color Index Zeros Overflow Read: %08x\n", pNVID->REX3.nZeroOverflow );
+ return pNVID->REX3.nZeroOverflow;
+ case 0x022c/4:
+ case 0x0a2c/4:
+ //verboselog(machine, 2, "REX3 Red/CI Slope (copy) Read: %08x\n", pNVID->REX3.nSlopeRed );
+ return pNVID->REX3.nSlopeRed;
+ case 0x0230/4:
+ case 0x0a30/4:
+ //verboselog(machine, 2, "REX3 Host Data Port MSW Read: %08x\n", pNVID->REX3.nHostDataPortMSW );
+ return pNVID->REX3.nHostDataPortMSW;
+ case 0x0234/4:
+ case 0x0a34/4:
+ //verboselog(machine, 2, "REX3 Host Data Port LSW Read: %08x\n", pNVID->REX3.nHostDataPortLSW );
+ return pNVID->REX3.nHostDataPortLSW;
+ case 0x0238/4:
+ case 0x0a38/4:
+ //verboselog(machine, 2, "REX3 Display Control Bus Mode Read: %08x\n", pNVID->REX3.nDCBMode );
+ return pNVID->REX3.nDCBMode;
+ case 0x0240/4:
+ case 0x0a40/4:
+ switch( pNVID->REX3.nDCBSlvSelect )
+ {
+ case 0x00:
+ return newport_vc2_r( space, 0, mem_mask );
+ case 0x02:
+ return newport_cmap0_r( space, 0, mem_mask );
+ case 0x03:
+ return newport_cmap1_r( space, 0, mem_mask );
+ case 0x05:
+ return newport_xmap0_r( space, 0, mem_mask );
+ case 0x06:
+ return newport_xmap1_r( space, 0, mem_mask );
+ default:
+ //verboselog(machine, 2, "REX3 Display Control Bus Data MSW Read: %08x\n", pNVID->REX3.nDCBDataMSW );
+ break;
+ }
+ return pNVID->REX3.nDCBDataMSW;
+ case 0x0244/4:
+ case 0x0a44/4:
+ //verboselog(machine, 2, "REX3 Display Control Bus Data LSW Read: %08x\n", pNVID->REX3.nDCBDataLSW );
+ return pNVID->REX3.nDCBDataLSW;
+ case 0x1300/4:
+ //verboselog(machine, 2, "REX3 Screenmask 1 X Min/Max Read: %08x\n", pNVID->REX3.nSMask1X );
+ return pNVID->REX3.nSMask1X;
+ case 0x1304/4:
+ //verboselog(machine, 2, "REX3 Screenmask 1 Y Min/Max Read: %08x\n", pNVID->REX3.nSMask1Y );
+ return pNVID->REX3.nSMask1Y;
+ case 0x1308/4:
+ //verboselog(machine, 2, "REX3 Screenmask 2 X Min/Max Read: %08x\n", pNVID->REX3.nSMask2X );
+ return pNVID->REX3.nSMask2X;
+ case 0x130c/4:
+ //verboselog(machine, 2, "REX3 Screenmask 2 Y Min/Max Read: %08x\n", pNVID->REX3.nSMask2Y );
+ return pNVID->REX3.nSMask2Y;
+ case 0x1310/4:
+ //verboselog(machine, 2, "REX3 Screenmask 3 X Min/Max Read: %08x\n", pNVID->REX3.nSMask3X );
+ return pNVID->REX3.nSMask3X;
+ case 0x1314/4:
+ //verboselog(machine, 2, "REX3 Screenmask 3 Y Min/Max Read: %08x\n", pNVID->REX3.nSMask3Y );
+ return pNVID->REX3.nSMask3Y;
+ case 0x1318/4:
+ //verboselog(machine, 2, "REX3 Screenmask 4 X Min/Max Read: %08x\n", pNVID->REX3.nSMask4X );
+ return pNVID->REX3.nSMask4X;
+ case 0x131c/4:
+ //verboselog(machine, 2, "REX3 Screenmask 4 Y Min/Max Read: %08x\n", pNVID->REX3.nSMask4Y );
+ return pNVID->REX3.nSMask4Y;
+ case 0x1320/4:
+ //verboselog(machine, 2, "REX3 Top of Screen Scanline Read: %08x\n", pNVID->REX3.nTopScanline );
+ return pNVID->REX3.nTopScanline;
+ case 0x1324/4:
+ //verboselog(machine, 2, "REX3 Clipping Mode Read: %08x\n", pNVID->REX3.nXYWin );
+ return pNVID->REX3.nXYWin;
+ case 0x1328/4:
+ //verboselog(machine, 2, "REX3 Clipping Mode Read: %08x\n", pNVID->REX3.nClipMode );
+ return pNVID->REX3.nClipMode;
+ case 0x1330/4:
+ //verboselog(machine, 2, "REX3 Config Read: %08x\n", pNVID->REX3.nConfig );
+ return pNVID->REX3.nConfig;
+ case 0x1338/4:
+ //verboselog(machine, 2, "REX3 Status Read: %08x\n", 0x00000001 );
+// nTemp = pNVID->REX3.nStatus;
+ pNVID->REX3.nStatus = 0;
+ return 0x00000001;
+ case 0x133c/4:
+ //verboselog(machine, 2, "REX3 User Status Read: %08x\n", 0x00000001 );
+ return 0x00000001;
+ default:
+ //verboselog(machine, 2, "Unknown REX3 Read: %08x (%08x)\n", 0x1f0f0000 + ( offset << 2 ), mem_mask );
+ return 0;
+ }
+ return 0;
+}
+
+static void DoREX3Command(running_machine &machine)
+{
+ UINT32 nCommand = ( ( pNVID->REX3.nDrawMode0 & ( 1 << 15 ) ) >> 15 ) |
+ ( ( pNVID->REX3.nDrawMode0 & ( 1 << 5 ) ) >> 4 ) |
+ ( ( pNVID->REX3.nDrawMode0 & ( 1 << 9 ) ) >> 7 ) |
+ ( ( pNVID->REX3.nDrawMode0 & ( 1 << 8 ) ) >> 5 ) |
+ ( ( pNVID->REX3.nDrawMode0 & 0x0000001c ) << 2 ) |
+ ( ( pNVID->REX3.nDrawMode0 & 0x00000003 ) << 7 );
+ UINT16 nX, nY;
+ UINT16 nStartX = ( pNVID->REX3.nXYStartI >> 16 ) & 0x0000ffff;
+ UINT16 nStartY = ( pNVID->REX3.nXYStartI >> 0 ) & 0x0000ffff;
+ UINT16 nEndX = ( pNVID->REX3.nXYEndI >> 16 ) & 0x0000ffff;
+ UINT16 nEndY = ( pNVID->REX3.nXYEndI >> 0 ) & 0x0000ffff;
+ INT16 nMoveX, nMoveY;
+
+ switch( nCommand )
+ {
+ case 0x00000110:
+ nX = nStartX;
+ nY = nStartY;
+ //verboselog(machine, 3, "Tux Logo Draw: %04x, %04x = %08x\n", nX, nY, pNVID->CMAP0.nPalette[ ( pNVID->REX3.nHostDataPortMSW & 0xff000000 ) >> 24 ] );
+// pNVID->REX3.nKludge_SkipLine = 1;
+ pNVID->REX3.nBresOctInc1 = 0;
+ pNVID->base[ nY*(1280+64) + nX ] = pNVID->CMAP0.nPalette[ ( pNVID->REX3.nHostDataPortMSW & 0xff000000 ) >> 24 ];
+ nX++;
+ if( nX > ( ( pNVID->REX3.nXYEndI & 0xffff0000 ) >> 16 ) )
+ {
+ nY++;
+ nX = pNVID->REX3.nXSave;
+ }
+ pNVID->REX3.nXYStartI = ( nX << 16 ) | nY;
+ pNVID->REX3.nXStartI = nX;
+ pNVID->REX3.nXStart = 0 | ( ( pNVID->REX3.nXYStartI & 0xffff0000 ) >> 5 );
+ pNVID->REX3.nYStart = 0 | ( ( pNVID->REX3.nXYStartI & 0x0000ffff ) << 11 );
+ break;
+ case 0x0000011e:
+ //verboselog(machine, 3, "Block draw: %04x, %04x to %04x, %04x = %08x\n", nStartX, nStartY, nEndX, nEndY, pNVID->CMAP0.nPalette[ pNVID->REX3.nZeroFract ] );
+ for( nY = nStartY; nY <= nEndY; nY++ )
+ {
+ //verboselog(machine, 3, "Pixel: %04x, %04x = %08x\n", nStartX, nY, pNVID->CMAP0.nPalette[ pNVID->REX3.nZeroFract ] );
+ for( nX = nStartX; nX <= nEndX; nX++ )
+ {
+ pNVID->base[ nY*(1280+64) + nX ] = pNVID->CMAP0.nPalette[ pNVID->REX3.nZeroFract ];
+ }
+ }
+ break;
+ case 0x00000119:
+ if( !pNVID->REX3.nKludge_SkipLine )
+ {
+ //verboselog(machine, 3, "Pattern Line Draw: %08x at %04x, %04x color %08x\n", pNVID->REX3.nZPattern, pNVID->REX3.nXYStartI >> 16, pNVID->REX3.nXYStartI & 0x0000ffff, pNVID->CMAP0.nPalette[ pNVID->REX3.nZeroFract ] );
+ for( nX = nStartX; nX <= nEndX && nX < ( nStartX + 32 ); nX++ )
+ {
+ if( pNVID->REX3.nZPattern & ( 1 << ( 31 - ( nX - nStartX ) ) ) )
+ {
+ pNVID->base[ nStartY*(1280+64) + nX ] = pNVID->CMAP0.nPalette[ pNVID->REX3.nZeroFract ];
+ }
+ }
+ if( pNVID->REX3.nBresOctInc1 & 0x01000000 )
+ {
+ nStartY--;
+ }
+ else
+ {
+ nStartY++;
+ }
+ pNVID->REX3.nXYStartI = ( nStartX << 16 ) | nStartY;
+ pNVID->REX3.nYStart = 0 | ( ( pNVID->REX3.nXYStartI & 0x0000ffff ) << 11 );
+ }
+ break;
+ case 0x0000019e:
+ nMoveX = (INT16)( ( pNVID->REX3.nXYMove >> 16 ) & 0x0000ffff );
+ nMoveY = (INT16)( pNVID->REX3.nXYMove & 0x0000ffff );
+ //verboselog(machine, 1, "FB to FB Copy: %04x, %04x - %04x, %04x to %04x, %04x\n", nStartX, nStartY, nEndX, nEndY, nStartX + nMoveX, nStartY + nMoveY );
+ for( nY = nStartY; nY <= nEndY; nY++ )
+ {
+ for( nX = nStartX; nX <= nEndX; nX++ )
+ {
+ pNVID->base[ (nY + nMoveY)*(1280+64) + (nX + nMoveX) ] = pNVID->base[ nY*(1280+64) + nX ];
+ }
+ }
+ break;
+ default:
+ //verboselog(machine, 1, "Unknown draw command: %08x\n", nCommand );
+ break;
+ }
+}
+
+WRITE32_HANDLER( newport_rex3_w )
+{
+ UINT32 nTemp=0;
+ running_machine &machine = space->machine();
+
+ if( offset & 0x00000200 )
+ {
+ //verboselog(machine, 2, "Start Cmd\n" );
+ }
+ switch( offset )
+ {
+ case 0x0000/4:
+ case 0x0800/4:
+ //verboselog(machine, 2, "REX3 Draw Mode 1 Write: %08x\n", data );
+ switch( data & 0x00000007 )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " Planes Enabled: None\n" );
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " Planes Enabled: R/W RGB/CI\n" );
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " Planes Enabled: R/W RGBA\n" );
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " Planes Enabled: R/W OLAY\n" );
+ break;
+ case 0x04:
+ //verboselog(machine, 2, " Planes Enabled: R/W PUP\n" );
+ break;
+ case 0x05:
+ //verboselog(machine, 2, " Planes Enabled: R/W CID\n" );
+ break;
+ default:
+ //verboselog(machine, 2, " Unknown Plane Enable Value\n" );
+ break;
+ }
+ switch( ( data & 0x00000018 ) >> 3 )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " Plane Draw Depth: 4 bits\n" );
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " Plane Draw Depth: 8 bits\n" );
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " Plane Draw Depth: 12 bits\n" );
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " Plane Draw Depth: 32 bits\n" );
+ break;
+ }
+ //verboselog(machine, 2, " DBuf Source Buffer: %d\n", ( data & 0x00000020 ) >> 5 );
+ //verboselog(machine, 2, " GL Y Coordinates: %d\n", ( data & 0x00000040 ) >> 6 );
+ //verboselog(machine, 2, " Enable Pxl Packing: %d\n", ( data & 0x00000080 ) >> 7 );
+ switch( ( data & 0x00000300 ) >> 8 )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " HOSTRW Depth: 4 bits\n" );
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " HOSTRW Depth: 8 bits\n" );
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " HOSTRW Depth: 12 bits\n" );
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " HOSTRW Depth: 32 bits\n" );
+ break;
+ }
+ //verboselog(machine, 2, " DWord Transfers: %d\n", ( data & 0x00000400 ) >> 10 );
+ //verboselog(machine, 2, " Swap Endianness: %d\n", ( data & 0x00000800 ) >> 11 );
+ //verboselog(machine, 2, " Compare Src > Dest: %d\n", ( data & 0x00001000 ) >> 12 );
+ //verboselog(machine, 2, " Compare Src = Dest: %d\n", ( data & 0x00002000 ) >> 13 );
+ //verboselog(machine, 2, " Compare Src < Dest: %d\n", ( data & 0x00004000 ) >> 14 );
+ //verboselog(machine, 2, " RGB Mode Select: %d\n", ( data & 0x00008000 ) >> 15 );
+ //verboselog(machine, 2, " Enable Dithering: %d\n", ( data & 0x00010000 ) >> 16 );
+ //verboselog(machine, 2, " Enable Fast Clear: %d\n", ( data & 0x00020000 ) >> 17 );
+ //verboselog(machine, 2, " Enable Blending: %d\n", ( data & 0x00040000 ) >> 18 );
+ switch( ( data & 0x00380000 ) >> 19 )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " Src Blend Factor: 0\n" );
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " Src Blend Factor: 1\n" );
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " Src Blend Factor: Normalized Dest (or COLORBACK)\n" );
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " Src Blend Factor: 1 - Normalized Dest (or COLORBACK)\n" );
+ break;
+ case 0x04:
+ //verboselog(machine, 2, " Src Blend Factor: Normalized Src\n" );
+ break;
+ case 0x05:
+ //verboselog(machine, 2, " Src Blend Factor: 1 - Normalized Src\n" );
+ break;
+ default:
+ //verboselog(machine, 2, " Unknown Src Blend Factor: %02x\n", ( data & 0x00380000 ) >> 19 );
+ break;
+ }
+ switch( ( data & 0x01c00000 ) >> 22 )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " Dest Blend Factor: 0\n" );
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " Dest Blend Factor: 1\n" );
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " Dest Blend Factor: Normalized Dest (or COLORBACK)\n" );
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " Dest Blend Factor: 1 - Normalized Dest (or COLORBACK)\n" );
+ break;
+ case 0x04:
+ //verboselog(machine, 2, " Dest Blend Factor: Normalized Src\n" );
+ break;
+ case 0x05:
+ //verboselog(machine, 2, " Dest Blend Factor: 1 - Normalized Src\n" );
+ break;
+ default:
+ //verboselog(machine, 2, " Unknown Src Blend Factor: %02x\n", ( data & 0x00380000 ) >> 19 );
+ break;
+ }
+ //verboselog(machine, 2, " COLORBACK Dest Blend: %d\n", ( data & 0x02000000 ) >> 25 );
+ //verboselog(machine, 2, " Enable Pxl Prefetch: %d\n", ( data & 0x04000000 ) >> 26 );
+ //verboselog(machine, 2, " SFACTOR Src Alpha: %d\n", ( data & 0x08000000 ) >> 27 );
+ switch( ( data & 0xf0000000 ) >> 28 )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " Logical Op. Type: 0\n" );
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " Logical Op. Type: Src & Dst\n" );
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " Logical Op. Type: Src & ~Dst\n" );
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " Logical Op. Type: Src\n" );
+ break;
+ case 0x04:
+ //verboselog(machine, 2, " Logical Op. Type: ~Src & Dst\n" );
+ break;
+ case 0x05:
+ //verboselog(machine, 2, " Logical Op. Type: Dst\n" );
+ break;
+ case 0x06:
+ //verboselog(machine, 2, " Logical Op. Type: Src ^ Dst\n" );
+ break;
+ case 0x07:
+ //verboselog(machine, 2, " Logical Op. Type: Src | Dst\n" );
+ break;
+ case 0x08:
+ //verboselog(machine, 2, " Logical Op. Type: ~(Src | Dst)\n" );
+ break;
+ case 0x09:
+ //verboselog(machine, 2, " Logical Op. Type: ~(Src ^ Dst)\n" );
+ break;
+ case 0x0a:
+ //verboselog(machine, 2, " Logical Op. Type: ~Dst\n" );
+ break;
+ case 0x0b:
+ //verboselog(machine, 2, " Logical Op. Type: Src | ~Dst\n" );
+ break;
+ case 0x0c:
+ //verboselog(machine, 2, " Logical Op. Type: ~Src\n" );
+ break;
+ case 0x0d:
+ //verboselog(machine, 2, " Logical Op. Type: ~Src | Dst\n" );
+ break;
+ case 0x0e:
+ //verboselog(machine, 2, " Logical Op. Type: ~(Src & Dst)\n" );
+ break;
+ case 0x0f:
+ //verboselog(machine, 2, " Logical Op. Type: 1\n" );
+ break;
+ }
+ pNVID->REX3.nDrawMode1 = data;
+// if( offset >= ( 0x800 / 4 ) )
+// {
+// DoREX3Command();
+// }
+ break;
+ case 0x0004/4:
+ //verboselog(machine, 2, "REX3 Draw Mode 0 Write: %08x\n", data );
+ switch( data & 0x00000003 )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " Primitive Function: No Op\n" );
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " Primitive Function: Read From FB\n" );
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " Primitive Function: Draw To FB\n" );
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " Primitive Function: Copy FB To FB\n" );
+ break;
+ }
+ switch( ( data & 0x0000001c ) >> 2 )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " Addressing Mode: Span/Point\n" );
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " Addressing Mode: Block\n" );
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " Addressing Mode: Bresenham Line, Integer Endpoints\n" );
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " Addressing Mode: Bresenham Line, Fractional Endpoints\n" );
+ break;
+ case 0x04:
+ //verboselog(machine, 2, " Addressing Mode: AA Bresenham Line\n" );
+ break;
+ default:
+ //verboselog(machine, 2, " Unknown Addressing Mode: %02x\n", ( data & 0x0000001c ) >> 2 );
+ break;
+ }
+ //verboselog(machine, 2, " Iterator Setup: %d\n", ( data & 0x00000020 ) >> 5 );
+ //verboselog(machine, 2, " RGB/CI Draw Source: %d\n", ( data & 0x00000040 ) >> 6 );
+ //verboselog(machine, 2, " Alpha Draw Source: %d\n", ( data & 0x00000080 ) >> 7 );
+ //verboselog(machine, 2, " Stop On X: %d\n", ( data & 0x00000100 ) >> 8 );
+ //verboselog(machine, 2, " Stop On Y: %d\n", ( data & 0x00000200 ) >> 9 );
+ //verboselog(machine, 2, " Skip Start Point: %d\n", ( data & 0x00000400 ) >> 10 );
+ //verboselog(machine, 2, " Skip End Point: %d\n", ( data & 0x00000800 ) >> 11 );
+ //verboselog(machine, 2, " Enable Patterning: %d\n", ( data & 0x00001000 ) >> 12 );
+ //verboselog(machine, 2, " Enable Stippling: %d\n", ( data & 0x00002000 ) >> 13 );
+ //verboselog(machine, 2, " Stipple Advance: %d\n", ( data & 0x00004000 ) >> 14 );
+ //verboselog(machine, 2, " Limit Draw To 32px: %d\n", ( data & 0x00008000 ) >> 15 );
+ //verboselog(machine, 2, " Z Opaque Stipple %d\n", ( data & 0x00010000 ) >> 16 );
+ //verboselog(machine, 2, " LS Opaque Stipple: %d\n", ( data & 0x00020000 ) >> 17 );
+ //verboselog(machine, 2, " Enable Lin. Shade: %d\n", ( data & 0x00040000 ) >> 18 );
+ //verboselog(machine, 2, " Left-Right Only: %d\n", ( data & 0x00080000 ) >> 19 );
+ //verboselog(machine, 2, " Offset by XYMove: %d\n", ( data & 0x00100000 ) >> 20 );
+ //verboselog(machine, 2, " Enable CI Clamping: %d\n", ( data & 0x00200000 ) >> 21 );
+ //verboselog(machine, 2, " Enable End Filter: %d\n", ( data & 0x00400000 ) >> 22 );
+ //verboselog(machine, 2, " Enable Y+2 Stride: %d\n", ( data & 0x00800000 ) >> 23 );
+ pNVID->REX3.nDrawMode0 = data;
+ break;
+ case 0x0804/4:
+ //verboselog(machine, 2, "REX3 Draw Mode 0 Write: %08x\n", data );
+ pNVID->REX3.nDrawMode0 = data;
+ break;
+ case 0x0008/4:
+ case 0x0808/4:
+ //verboselog(machine, 2, "REX3 Line Stipple Mode Write: %08x\n", data );
+ pNVID->REX3.nLSMode = data & 0x0fffffff;
+ break;
+ case 0x000C/4:
+ case 0x080c/4:
+ //verboselog(machine, 2, "REX3 Line Stipple Pattern Write: %08x\n", data );
+ pNVID->REX3.nLSPattern = data;
+ break;
+ case 0x0010/4:
+ case 0x0810/4:
+ //verboselog(machine, 2, "REX3 Line Stipple Pattern (Save) Write: %08x\n", data );
+ pNVID->REX3.nLSPatSave = data;
+ break;
+ case 0x0014/4:
+ case 0x0814/4:
+ //verboselog(machine, 2, "REX3 Pattern Register Write: %08x\n", data );
+ pNVID->REX3.nZPattern = data;
+ if( offset & 0x00000200 )
+ {
+ DoREX3Command(machine);
+ }
+ break;
+ case 0x0018/4:
+ case 0x0818/4:
+ //verboselog(machine, 2, "REX3 Opaque Pattern / Blendfunc Dest Color Write: %08x\n", data );
+ pNVID->REX3.nColorBack = data;
+ break;
+ case 0x001c/4:
+ case 0x081c/4:
+ //verboselog(machine, 2, "REX3 VRAM Fastclear Color Write: %08x\n", data );
+ pNVID->REX3.nColorVRAM = data;
+ break;
+ case 0x0020/4:
+ case 0x0820/4:
+ //verboselog(machine, 2, "REX3 AFUNCTION Reference Alpha Write: %08x\n", data );
+ pNVID->REX3.nAlphaRef = data & 0x000000ff;
+ break;
+ case 0x0024/4:
+ case 0x0824/4:
+ //verboselog(machine, 2, "REX3 Stall GFIFO Write: %08x\n", data );
+ break;
+ case 0x0028/4:
+ case 0x0828/4:
+ //verboselog(machine, 2, "REX3 Screenmask 0 X Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask0X = data;
+ break;
+ case 0x002c/4:
+ case 0x082c/4:
+ //verboselog(machine, 2, "REX3 Screenmask 0 Y Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask0Y = data;
+ break;
+ case 0x0030/4:
+ case 0x0830/4:
+ //verboselog(machine, 2, "REX3 Line/Span Setup Write: %08x\n", data );
+ pNVID->REX3.nSetup = data;
+ break;
+ case 0x0034/4:
+ case 0x0834/4:
+ //verboselog(machine, 2, "REX3 ZPattern Enable Write: %08x\n", data );
+ pNVID->REX3.nStepZ = data;
+ break;
+ case 0x0038/4:
+ case 0x0838/4:
+ //verboselog(machine, 2, "REX3 Update LSPATTERN/LSRCOUNT\n" );
+ pNVID->REX3.nLSPattern = pNVID->REX3.nLSPatSave;
+ break;
+ case 0x003c/4:
+ case 0x083c/4:
+ //verboselog(machine, 2, "REX3 Update LSPATSAVE/LSRCNTSAVE\n" );
+ pNVID->REX3.nLSPatSave = pNVID->REX3.nLSPattern;
+ break;
+ case 0x0100/4:
+ case 0x0900/4:
+ //verboselog(machine, 2, "REX3 XStart Write: %08x\n", data );
+ pNVID->REX3.nXStart = data & ( 0x0000fffff << 7 );
+ break;
+ case 0x0104/4:
+ case 0x0904/4:
+ //verboselog(machine, 2, "REX3 YStart Write: %08x\n", data );
+ pNVID->REX3.nYStart = data & ( 0x0000fffff << 7 );
+ break;
+ case 0x0108/4:
+ case 0x0908/4:
+ //verboselog(machine, 2, "REX3 XEnd Write: %08x\n", data );
+ pNVID->REX3.nXEnd = data & ( 0x0000fffff << 7 );
+ break;
+ case 0x010c/4:
+ case 0x090c/4:
+ //verboselog(machine, 2, "REX3 YEnd Write: %08x\n", data );
+ pNVID->REX3.nYEnd = data & ( 0x0000fffff << 7 );
+ break;
+ case 0x0110/4:
+ case 0x0910/4:
+ //verboselog(machine, 2, "REX3 XSave Write: %08x\n", data );
+ pNVID->REX3.nXSave = data & 0x0000ffff;
+ pNVID->REX3.nXStartI = pNVID->REX3.nXSave & 0x0000ffff;
+ break;
+ case 0x0114/4:
+ case 0x0914/4:
+ //verboselog(machine, 2, "REX3 XYMove Write: %08x\n", data );
+ pNVID->REX3.nXYMove = data;
+ if( offset & 0x00000200 )
+ {
+ DoREX3Command(machine);
+ }
+ break;
+ case 0x0118/4:
+ case 0x0918/4:
+ //verboselog(machine, 2, "REX3 Bresenham D Write: %08x\n", data );
+ pNVID->REX3.nBresD = data & 0x07ffffff;
+ break;
+ case 0x011c/4:
+ case 0x091c/4:
+ //verboselog(machine, 2, "REX3 Bresenham S1 Write: %08x\n", data );
+ pNVID->REX3.nBresS1 = data & 0x0001ffff;
+ break;
+ case 0x0120/4:
+ case 0x0920/4:
+ //verboselog(machine, 2, "REX3 Bresenham Octant & Incr1 Write: %08x\n", data );
+ pNVID->REX3.nBresOctInc1 = data & 0x070fffff;
+ break;
+ case 0x0124/4:
+ case 0x0924/4:
+ //verboselog(machine, 2, "REX3 Bresenham Octant Rounding Mode & Incr2 Write: %08x\n", data );
+ pNVID->REX3.nBresRndInc2 = data & 0xff1fffff;
+ break;
+ case 0x0128/4:
+ case 0x0928/4:
+ //verboselog(machine, 2, "REX3 Bresenham E1 Write: %08x\n", data );
+ pNVID->REX3.nBresE1 = data & 0x0000ffff;
+ break;
+ case 0x012c/4:
+ case 0x092c/4:
+ //verboselog(machine, 2, "REX3 Bresenham S2 Write: %08x\n", data );
+ pNVID->REX3.nBresS2 = data & 0x03ffffff;
+ break;
+ case 0x0130/4:
+ case 0x0930/4:
+ //verboselog(machine, 2, "REX3 AA Line Weight Table 1/2 Write: %08x\n", data );
+ pNVID->REX3.nAWeight0 = data;
+ break;
+ case 0x0134/4:
+ case 0x0934/4:
+ //verboselog(machine, 2, "REX3 AA Line Weight Table 2/2 Write: %08x\n", data );
+ pNVID->REX3.nAWeight1 = data;
+ break;
+ case 0x0138/4:
+ case 0x0938/4:
+ //verboselog(machine, 2, "REX3 GL XStart Write: %08x\n", data );
+ pNVID->REX3.nXStartF = data & ( 0x0000ffff << 7 );
+ break;
+ case 0x013c/4:
+ case 0x093c/4:
+ //verboselog(machine, 2, "REX3 GL YStart Write: %08x\n", data );
+ pNVID->REX3.nYStartF = data & ( 0x0000ffff << 7 );
+ break;
+ case 0x0140/4:
+ case 0x0940/4:
+ //verboselog(machine, 2, "REX3 GL XEnd Write: %08x\n", data );
+ pNVID->REX3.nXEndF = data & ( 0x0000ffff << 7 );
+ break;
+ case 0x0144/4:
+ case 0x0944/4:
+ //verboselog(machine, 2, "REX3 GL YEnd Write: %08x\n", data );
+ pNVID->REX3.nYEndF = data & ( 0x0000ffff << 7 );
+ break;
+ case 0x0148/4:
+ case 0x0948/4:
+ //verboselog(machine, 2, "REX3 XStart (integer) Write: %08x\n", data );
+ pNVID->REX3.nXStartI = data & 0x0000ffff;
+ pNVID->REX3.nXSave = pNVID->REX3.nXStartI;
+ pNVID->REX3.nXStart = 0 | ( ( pNVID->REX3.nXStartI & 0x0000ffff ) << 11 );
+ break;
+ case 0x014c/4:
+ case 0x094c/4:
+ //verboselog(machine, 2, "REX3 GL XEnd (copy) Write: %08x\n", data );
+ pNVID->REX3.nXEndF = data & ( 0x0000ffff << 7 );
+ break;
+ case 0x0150/4:
+ case 0x0950/4:
+ //verboselog(machine, 2, "REX3 XYStart (integer) Write: %08x\n", data );
+ pNVID->REX3.nXYStartI = data;
+ pNVID->REX3.nXStartI = ( data & 0xffff0000 ) >> 16;
+ pNVID->REX3.nXSave = pNVID->REX3.nXStartI;
+ pNVID->REX3.nXStart = 0 | ( ( pNVID->REX3.nXYStartI & 0xffff0000 ) >> 5 );
+ pNVID->REX3.nYStart = 0 | ( ( pNVID->REX3.nXYStartI & 0x0000ffff ) << 11 );
+ break;
+ case 0x0154/4:
+ case 0x0954/4:
+ //verboselog(machine, 2, "REX3 XYEnd (integer) Write: %08x\n", data );
+ pNVID->REX3.nXYEndI = data;
+ pNVID->REX3.nXEnd = 0 | ( ( pNVID->REX3.nXYEndI & 0xffff0000 ) >> 5 );
+ pNVID->REX3.nYEnd = 0 | ( ( pNVID->REX3.nXYEndI & 0x0000ffff ) << 11 );
+ if( offset & 0x00000200 )
+ {
+ DoREX3Command(machine);
+ }
+ break;
+ case 0x0158/4:
+ case 0x0958/4:
+ //verboselog(machine, 2, "REX3 XStartEnd (integer) Write: %08x\n", data );
+ pNVID->REX3.nXStartEndI = data;
+ pNVID->REX3.nXYEndI = ( pNVID->REX3.nXYEndI & 0x0000ffff ) | ( ( pNVID->REX3.nXStartEndI & 0x0000ffff ) << 16 );
+ pNVID->REX3.nXYStartI = ( pNVID->REX3.nXYStartI & 0x0000ffff ) | ( pNVID->REX3.nXStartEndI & 0xffff0000 );
+ pNVID->REX3.nXSave = pNVID->REX3.nXStartI;
+ pNVID->REX3.nXStart = 0 | ( ( pNVID->REX3.nXStartEndI & 0xffff0000 ) >> 5 );
+ pNVID->REX3.nXEnd = 0 | ( ( pNVID->REX3.nXStartEndI & 0x0000ffff ) << 11 );
+ break;
+ case 0x0200/4:
+ case 0x0a00/4:
+ //verboselog(machine, 2, "REX3 Red/CI Full State Write: %08x\n", data );
+ pNVID->REX3.nColorRed = data & 0x00ffffff;
+ break;
+ case 0x0204/4:
+ case 0x0a04/4:
+ //verboselog(machine, 2, "REX3 Alpha Full State Write: %08x\n", data );
+ pNVID->REX3.nColorAlpha = data & 0x000fffff;
+ break;
+ case 0x0208/4:
+ case 0x0a08/4:
+ //verboselog(machine, 2, "REX3 Green Full State Write: %08x\n", data );
+ pNVID->REX3.nColorGreen = data & 0x000fffff;
+ break;
+ case 0x020c/4:
+ case 0x0a0c/4:
+ //verboselog(machine, 2, "REX3 Blue Full State Write: %08x\n", data );
+ pNVID->REX3.nColorBlue = data & 0x000fffff;
+ break;
+ case 0x0210/4:
+ case 0x0a10/4:
+ //verboselog(machine, 2, "REX3 Red/CI Slope Write: %08x\n", data );
+ data &= 0x807fffff;
+ switch( data & 0x80000000 )
+ {
+ case 0x00000000:
+ nTemp = data & 0x007fffff;
+ break;
+ case 0x80000000:
+ nTemp = 0x00800000 - ( data & 0x007fffff );
+ nTemp |= 0x00800000;
+ break;
+ }
+ pNVID->REX3.nSlopeRed = nTemp;
+ break;
+ case 0x0214/4:
+ case 0x0a14/4:
+ //verboselog(machine, 2, "REX3 Alpha Slope Write: %08x\n", data );
+ data &= 0x8007ffff;
+ switch( data & 0x80000000 )
+ {
+ case 0x00000000:
+ nTemp = data & 0x0007ffff;
+ break;
+ case 0x80000000:
+ nTemp = 0x00080000 - ( data & 0x0007ffff );
+ nTemp |= 0x00080000;
+ break;
+ }
+ pNVID->REX3.nSlopeAlpha = nTemp;
+ break;
+ case 0x0218/4:
+ case 0x0a18/4:
+ //verboselog(machine, 2, "REX3 Green Slope Write: %08x\n", data );
+ data &= 0x8007ffff;
+ switch( data & 0x80000000 )
+ {
+ case 0x00000000:
+ nTemp = data & 0x0007ffff;
+ break;
+ case 0x80000000:
+ nTemp = 0x00080000 - ( data & 0x0007ffff );
+ nTemp |= 0x00080000;
+ break;
+ }
+ pNVID->REX3.nSlopeGreen = nTemp;
+ break;
+ case 0x021c/4:
+ case 0x0a1c/4:
+ //verboselog(machine, 2, "REX3 Blue Slope Write: %08x\n", data );
+ data &= 0x8007ffff;
+ switch( data & 0x80000000 )
+ {
+ case 0x00000000:
+ nTemp = data & 0x0007ffff;
+ break;
+ case 0x80000000:
+ nTemp = 0x00080000 - ( data & 0x0007ffff );
+ nTemp |= 0x00080000;
+ break;
+ }
+ pNVID->REX3.nSlopeBlue = nTemp;
+ break;
+ case 0x0220/4:
+ case 0x0a20/4:
+ //verboselog(machine, 2, "REX3 Write Mask Write: %08x\n", data );
+ pNVID->REX3.nWriteMask = data & 0x00ffffff;
+ break;
+ case 0x0224/4:
+ case 0x0a24/4:
+ //verboselog(machine, 2, "REX3 Packed Color Fractions Write: %08x\n", data );
+ pNVID->REX3.nZeroFract = data;
+ break;
+ case 0x0228/4:
+ case 0x0a28/4:
+ //verboselog(machine, 2, "REX3 Color Index Zeros Overflow Write: %08x\n", data );
+ pNVID->REX3.nZeroOverflow = data;
+ break;
+ case 0x022c/4:
+ case 0x0a2c/4:
+ //verboselog(machine, 2, "REX3 Red/CI Slope (copy) Write: %08x\n", data );
+ pNVID->REX3.nSlopeRed = data;
+ break;
+ case 0x0230/4:
+ case 0x0a30/4:
+ //verboselog(machine, 3, "REX3 Host Data Port MSW Write: %08x\n", data );
+ pNVID->REX3.nHostDataPortMSW = data;
+ if( offset & 0x00000200 )
+ {
+ DoREX3Command(machine);
+ }
+ break;
+ case 0x0234/4:
+ case 0x0a34/4:
+ //verboselog(machine, 2, "REX3 Host Data Port LSW Write: %08x\n", data );
+ pNVID->REX3.nHostDataPortLSW = data;
+ break;
+ case 0x0238/4:
+ case 0x0a38/4:
+ //verboselog(machine, 2, "REX3 Display Control Bus Mode Write: %08x\n", data );
+ switch( data & 0x00000003 )
+ {
+ case 0x00:
+ //verboselog(machine, 2, " Transfer Width: 4 bytes\n" );
+ pNVID->REX3.nXFerWidth = 4;
+ break;
+ case 0x01:
+ //verboselog(machine, 2, " Transfer Width: 1 bytes\n" );
+ pNVID->REX3.nXFerWidth = 1;
+ break;
+ case 0x02:
+ //verboselog(machine, 2, " Transfer Width: 2 bytes\n" );
+ pNVID->REX3.nXFerWidth = 2;
+ break;
+ case 0x03:
+ //verboselog(machine, 2, " Transfer Width: 3 bytes\n" );
+ pNVID->REX3.nXFerWidth = 3;
+ break;
+ }
+ //verboselog(machine, 2, " DCB Reg Select Adr: %d\n", ( data & 0x00000070 ) >> 4 );
+ //verboselog(machine, 2, " DCB Slave Address: %d\n", ( data & 0x00000780 ) >> 7 );
+// //verboselog(machine, 2, " Use Sync XFer ACK: %d\n", ( data & 0x00000800 ) >> 11 );
+// //verboselog(machine, 2, " Use Async XFer ACK: %d\n", ( data & 0x00001000 ) >> 12 );
+// //verboselog(machine, 2, " GIO CLK Cycle Width: %d\n", ( data & 0x0003e000 ) >> 13 );
+// //verboselog(machine, 2, " GIO CLK Cycle Hold: %d\n", ( data & 0x007c0000 ) >> 18 );
+// //verboselog(machine, 2, " GIO CLK Cycle Setup: %d\n", ( data & 0x0f800000 ) >> 23 );
+// //verboselog(machine, 2, " Swap Byte Ordering: %d\n", ( data & 0x10000000 ) >> 28 );
+ pNVID->REX3.nDCBRegSelect = ( data & 0x00000070 ) >> 4;
+ pNVID->REX3.nDCBSlvSelect = ( data & 0x00000780 ) >> 7;
+ pNVID->REX3.nDCBMode = data & 0x1fffffff;
+ break;
+ case 0x0240/4:
+ case 0x0a40/4:
+ pNVID->REX3.nDCBDataMSW = data;
+ switch( pNVID->REX3.nDCBSlvSelect )
+ {
+ case 0x00:
+ newport_vc2_w( space, 0, data, mem_mask );
+ break;
+ case 0x01:
+ newport_cmap0_w( space, 0, data, mem_mask );
+ break;
+ case 0x04:
+ newport_xmap0_w( space, 0, data, mem_mask );
+ newport_xmap1_w( space, 0, data, mem_mask );
+ break;
+ case 0x05:
+ newport_xmap0_w( space, 0, data, mem_mask );
+ break;
+ case 0x06:
+ newport_xmap1_w( space, 0, data, mem_mask );
+ break;
+ default:
+ //verboselog(machine, 2, "REX3 Display Control Bus Data MSW Write: %08x\n", data );
+ break;
+ }
+ break;
+ case 0x0244/4:
+ case 0x0a44/4:
+ //verboselog(machine, 2, "REX3 Display Control Bus Data LSW Write: %08x\n", data );
+ pNVID->REX3.nDCBDataLSW = data;
+ break;
+ case 0x1300/4:
+ //verboselog(machine, 2, "REX3 Screenmask 1 X Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask1X = data;
+ break;
+ case 0x1304/4:
+ //verboselog(machine, 2, "REX3 Screenmask 1 Y Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask1Y = data;
+ break;
+ case 0x1308/4:
+ //verboselog(machine, 2, "REX3 Screenmask 2 X Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask2X = data;
+ break;
+ case 0x130c/4:
+ //verboselog(machine, 2, "REX3 Screenmask 2 Y Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask2Y = data;
+ break;
+ case 0x1310/4:
+ //verboselog(machine, 2, "REX3 Screenmask 3 X Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask3X = data;
+ break;
+ case 0x1314/4:
+ //verboselog(machine, 2, "REX3 Screenmask 3 Y Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask3Y = data;
+ break;
+ case 0x1318/4:
+ //verboselog(machine, 2, "REX3 Screenmask 4 X Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask4X = data;
+ break;
+ case 0x131c/4:
+ //verboselog(machine, 2, "REX3 Screenmask 4 Y Min/Max Write: %08x\n", data );
+ pNVID->REX3.nSMask4Y = data;
+ break;
+ case 0x1320/4:
+ //verboselog(machine, 2, "REX3 Top of Screen Scanline Write: %08x\n", data );
+ pNVID->REX3.nTopScanline = data & 0x000003ff;
+ break;
+ case 0x1324/4:
+ //verboselog(machine, 2, "REX3 Clipping Mode Write: %08x\n", data );
+ pNVID->REX3.nXYWin = data;
+ break;
+ case 0x1328/4:
+ //verboselog(machine, 2, "REX3 Clipping Mode Write: %08x\n", data );
+ pNVID->REX3.nClipMode = data & 0x00001fff;
+ break;
+ case 0x132c/4:
+ //verboselog(machine, 2, "Request GFIFO Stall\n" );
+ break;
+ case 0x1330/4:
+ //verboselog(machine, 2, "REX3 Config Write: %08x\n", data );
+ pNVID->REX3.nConfig = data & 0x001fffff;
+ break;
+ case 0x1340/4:
+ //verboselog(machine, 2, "Reset DCB Bus and Flush BFIFO\n" );
+ break;
+ default:
+ //verboselog(machine, 2, "Unknown REX3 Write: %08x (%08x): %08x\n", 0xbf0f0000 + ( offset << 2 ), mem_mask, data );
+ break;
+ }
+}
+
+
diff --git a/src/mess/video/newport.h b/src/mess/video/newport.h
new file mode 100644
index 00000000000..4dea6944f92
--- /dev/null
+++ b/src/mess/video/newport.h
@@ -0,0 +1,15 @@
+/*
+ SGI "Newport" graphics board used in the Indy and some Indigo2s
+
+*/
+
+#ifndef _VIDHRDW_NEWPORT_
+#define _VIDHRDW_NEWPORT_
+
+extern VIDEO_START( newport );
+extern SCREEN_UPDATE_RGB32( newport );
+
+READ32_HANDLER( newport_rex3_r );
+WRITE32_HANDLER( newport_rex3_w );
+
+#endif
diff --git a/src/mess/video/nubus_48gc.c b/src/mess/video/nubus_48gc.c
new file mode 100644
index 00000000000..f2e32f802eb
--- /dev/null
+++ b/src/mess/video/nubus_48gc.c
@@ -0,0 +1,354 @@
+/***************************************************************************
+
+ Apple 4*8 Graphics Card (model 630-0400) emulation
+ Apple 8*24 Graphics Card emulation (cards have the same framebuffer chip
+ w/different ROMs and RAMDACs, apparently)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/nubus_48gc.h"
+
+#define GC48_SCREEN_NAME "48gc_screen"
+#define GC48_ROM_REGION "48gc_rom"
+
+#define VRAM_SIZE (0x200000) // 2 megs, maxed out
+
+static SCREEN_UPDATE_RGB32( mac_48gc );
+
+MACHINE_CONFIG_FRAGMENT( macvideo_48gc )
+ MCFG_SCREEN_ADD( GC48_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_UPDATE_STATIC( mac_48gc )
+ MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480)
+// MCFG_SCREEN_SIZE(1152, 870)
+// MCFG_SCREEN_VISIBLE_AREA(0, 1152-1, 0, 870-1)
+// MCFG_SCREEN_REFRESH_RATE(75)
+// MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(1260))
+MACHINE_CONFIG_END
+
+ROM_START( gc48 )
+ ROM_REGION(0x8000, GC48_ROM_REGION, 0)
+ ROM_LOAD( "3410801.bin", 0x0000, 0x8000, CRC(e283da91) SHA1(4ae21d6d7bbaa6fc7aa301bee2b791ed33b1dcf9) )
+ROM_END
+
+ROM_START( gc824 )
+ ROM_REGION(0x8000, GC48_ROM_REGION, 0)
+ ROM_LOAD( "3410868.bin", 0x000000, 0x008000, CRC(57f925fa) SHA1(4d3c0632711b7b31c8e0c5cfdd7ec1904f178336) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_48GC = &device_creator<nubus_48gc_device>;
+const device_type NUBUS_824GC = &device_creator<nubus_824gc_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor jmfb_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( macvideo_48gc );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *jmfb_device::device_rom_region() const
+{
+ return ROM_NAME( gc48 );
+}
+
+const rom_entry *nubus_824gc_device::device_rom_region() const
+{
+ return ROM_NAME( gc824 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// jmfb_device - constructor
+//-------------------------------------------------
+
+jmfb_device::jmfb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+}
+
+nubus_48gc_device::nubus_48gc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ jmfb_device(mconfig, NUBUS_48GC, "Apple 4*8 video card", tag, owner, clock)
+{
+ m_shortname = "nb_48gc";
+ m_is824 = false;
+}
+
+nubus_824gc_device::nubus_824gc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ jmfb_device(mconfig, NUBUS_824GC, "Apple 8*24 video card", tag, owner, clock)
+{
+ m_shortname = "nb_824gc";
+ m_is824 = true;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void jmfb_device::device_start()
+{
+ UINT32 slotspace;
+
+ // set_nubus_device makes m_slot valid
+ set_nubus_device();
+ install_declaration_rom(this, GC48_ROM_REGION);
+
+ slotspace = get_slotspace();
+
+// printf("[JMFB %p] slotspace = %x\n", this, slotspace);
+
+ m_vram = auto_alloc_array(machine(), UINT8, VRAM_SIZE);
+ install_bank(slotspace, slotspace+VRAM_SIZE-1, 0, 0, "bank_48gc", m_vram);
+
+ m_nubus->install_device(slotspace+0x200000, slotspace+0x2003ff, read32_delegate(FUNC(jmfb_device::mac_48gc_r), this), write32_delegate(FUNC(jmfb_device::mac_48gc_w), this));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void jmfb_device::device_reset()
+{
+ m_toggle = 0;
+ m_clutoffs = 0;
+ m_count = 0;
+ m_vbl_disable = 1;
+ m_stride = 80;
+ m_base = 0;
+ m_xres = 640;
+ m_yres = 480;
+ memset(m_vram, 0, VRAM_SIZE);
+}
+
+/***************************************************************************
+
+ Apple 4*8 Graphics Card section
+
+***************************************************************************/
+
+static SCREEN_UPDATE_RGB32( mac_48gc )
+{
+ jmfb_device *card = downcast<jmfb_device *>(screen.owner());
+ UINT32 *scanline, *base;
+ int x, y;
+ UINT8 *vram8 = (UINT8 *)card->m_vram;
+ UINT8 pixels;
+
+ if (!card->m_vbl_disable)
+ {
+ card->raise_slot_irq();
+ }
+
+ vram8 += 0xa00;
+
+ switch (card->m_mode)
+ {
+ case 0: // 1bpp
+ for (y = 0; y < card->m_yres; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < card->m_xres/8; x++)
+ {
+ pixels = vram8[(y * card->m_stride) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[(pixels>>7)&1];
+ *scanline++ = card->m_palette[(pixels>>6)&1];
+ *scanline++ = card->m_palette[(pixels>>5)&1];
+ *scanline++ = card->m_palette[(pixels>>4)&1];
+ *scanline++ = card->m_palette[(pixels>>3)&1];
+ *scanline++ = card->m_palette[(pixels>>2)&1];
+ *scanline++ = card->m_palette[(pixels>>1)&1];
+ *scanline++ = card->m_palette[pixels&1];
+ }
+ }
+ break;
+
+ case 1: // 2bpp
+ for (y = 0; y < card->m_yres; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < card->m_xres/4; x++)
+ {
+ pixels = vram8[(y * card->m_stride) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[(pixels>>6)&0x3];
+ *scanline++ = card->m_palette[(pixels>>4)&0x3];
+ *scanline++ = card->m_palette[(pixels>>2)&0x3];
+ *scanline++ = card->m_palette[pixels&3];
+ }
+ }
+ break;
+
+ case 2: // 4 bpp
+ for (y = 0; y < card->m_yres; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < card->m_xres/2; x++)
+ {
+ pixels = vram8[(y * card->m_stride) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[(pixels>>4)&0xf];
+ *scanline++ = card->m_palette[pixels&0xf];
+ }
+ }
+ break;
+
+ case 3: // 8 bpp
+ for (y = 0; y < card->m_yres; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < card->m_xres; x++)
+ {
+ pixels = vram8[(y * card->m_stride) + (BYTE4_XOR_BE(x))];
+ *scanline++ = card->m_palette[pixels];
+ }
+ }
+ break;
+
+ case 4: // 24 bpp
+ for (y = 0; y < card->m_yres; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ base = (UINT32 *)&card->m_vram[y * card->m_stride];
+ for (x = 0; x < card->m_xres; x++)
+ {
+ *scanline++ = *base++;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER( jmfb_device::mac_48gc_w )
+{
+ COMBINE_DATA(&m_registers[offset&0xff]);
+
+ switch (offset)
+ {
+ case 0x8/4: // base
+// printf("%x to base\n", data);
+ m_base = (data*2)<<4;
+ break;
+
+ case 0xc/4: // stride
+// printf("%x to stride\n", data);
+ // this value is in DWORDs for 1-8 bpp and, uhh, strange for 24bpp
+ if (m_mode < 4)
+ {
+ m_stride = data*4;
+ }
+ else
+ {
+ m_stride = (data*32)/3;
+ }
+ break;
+
+ case 0x200/4: // DAC control
+// printf("%08x to DAC control\n", data);
+ if (m_is824)
+ {
+ m_clutoffs = data&0xff;
+ }
+ else
+ {
+ m_clutoffs = data>>24;
+ }
+ m_count = 0;
+ break;
+
+ case 0x204/4: // DAC data
+ if (m_is824)
+ {
+ m_colors[m_count++] = data&0xff;
+ }
+ else
+ {
+ m_colors[m_count++] = data>>24;
+ }
+
+ if (m_count == 3)
+ {
+// printf("RAMDAC: color %d = %02x %02x %02x\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2]);
+ m_palette[m_clutoffs] = MAKE_RGB(m_colors[0], m_colors[1], m_colors[2]);
+ m_clutoffs++;
+ m_count = 0;
+ }
+ break;
+
+ case 0x208/4: // mode control
+ m_mode = (data>>3)&3;
+ if (m_mode == 3) // this can be 8 or 24 bpp
+ {
+ // check pixel format for 24bpp
+ if (m_is824)
+ {
+ if (data & 2)
+ {
+ m_mode = 4; // 24bpp
+ }
+ }
+ else
+ {
+ if (((data>>5)&3) == 0)
+ {
+ m_mode = 4; // 24bpp
+ }
+ }
+ }
+// printf("%02x to mode (m_mode = %d)\n", data, m_mode);
+ break;
+
+ case 0x13c/4: // bit 1 = VBL disable (1=no interrupts)
+ m_vbl_disable = (data & 2) ? 1 : 0;
+ break;
+
+ case 0x148/4: // write 1 here to clear interrupt
+ if (data == 1)
+ {
+ lower_slot_irq();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+READ32_MEMBER( jmfb_device::mac_48gc_r )
+{
+// printf("48gc_r: @ %x, mask %08x [PC=%x]\n", offset, mem_mask, cpu_get_pc(machine().device("maincpu")));
+
+ switch (offset)
+ {
+ case 0:
+ return 0x0c00; // sense 13" RGB for now
+// return 0x0000; // sense "RGB Kong" monitor
+ break;
+
+ case 0x1c0/4:
+ m_toggle ^= 0xffffffff;
+ return m_toggle;
+ break;
+ }
+
+ return 0;
+}
diff --git a/src/mess/video/nubus_48gc.h b/src/mess/video/nubus_48gc.h
new file mode 100644
index 00000000000..07cb22adeb0
--- /dev/null
+++ b/src/mess/video/nubus_48gc.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#ifndef __NUBUS_48GC_H__
+#define __NUBUS_48GC_H__
+
+#include "emu.h"
+#include "machine/nubus.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> jmfb_device
+
+class jmfb_device :
+ public device_t,
+ public device_nubus_card_interface
+{
+public:
+ // construction/destruction
+ jmfb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ DECLARE_READ32_MEMBER(mac_48gc_r);
+ DECLARE_WRITE32_MEMBER(mac_48gc_w);
+
+public:
+ UINT8 *m_vram;
+ UINT32 m_mode, m_vbl_disable, m_toggle, m_stride, m_base;
+ UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs;
+ UINT32 m_registers[0x100];
+ int m_xres, m_yres;
+ bool m_is824;
+};
+
+class nubus_48gc_device : public jmfb_device
+{
+public:
+ nubus_48gc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class nubus_824gc_device : public jmfb_device
+{
+public:
+ nubus_824gc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual const rom_entry *device_rom_region() const;
+};
+
+// device type definition
+extern const device_type NUBUS_48GC;
+extern const device_type NUBUS_824GC;
+
+#endif /* __NUBUS_48GC_H__ */
diff --git a/src/mess/video/nubus_cb264.c b/src/mess/video/nubus_cb264.c
new file mode 100644
index 00000000000..c58d3e8a9a0
--- /dev/null
+++ b/src/mess/video/nubus_cb264.c
@@ -0,0 +1,306 @@
+/***************************************************************************
+
+ RasterOps ColorBoard 264 NuBus video card emulation
+
+ fixed resolution 640x480 NuBus video card, 1/4/8/16/24 bit color
+ 1.5? MB of VRAM (tests up to 0x1fffff), Bt473 RAMDAC, and two custom gate arrays.
+
+ 0xfsff6004 is color depth: 0 for 1bpp, 1 for 2bpp, 2 for 4bpp, 3 for 8bpp, 4 for 24bpp
+ 0xfsff6014 is VBL ack: write 1 to ack
+ 0xfsff603c is VBL disable: write 1 to disable, 0 to enable
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/nubus_cb264.h"
+
+#define CB264_SCREEN_NAME "cb264_screen"
+#define CB264_ROM_REGION "cb264_rom"
+
+#define VRAM_SIZE (0x200000) // 2 megs, maxed out
+
+static SCREEN_UPDATE_RGB32( cb264 );
+
+MACHINE_CONFIG_FRAGMENT( cb264 )
+ MCFG_SCREEN_ADD( CB264_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_UPDATE_STATIC(cb264)
+ MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480)
+ MCFG_SCREEN_SIZE(1024,768)
+ MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1)
+MACHINE_CONFIG_END
+
+ROM_START( cb264 )
+ ROM_REGION(0x4000, CB264_ROM_REGION, 0)
+ ROM_LOAD16_BYTE( "264-1915.bin", 0x000000, 0x002000, CRC(26c19ee5) SHA1(2b2853d04cc6b0258e85eccd23ebfd4f4f63a084) )
+ ROM_LOAD16_BYTE( "264-1914.bin", 0x000001, 0x002000, CRC(d5fbd5ad) SHA1(98d35ed3fb0bca4a9bee1cdb2af0d3f22b379386) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_CB264 = &device_creator<nubus_cb264_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nubus_cb264_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( cb264 );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *nubus_cb264_device::device_rom_region() const
+{
+ return ROM_NAME( cb264 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nubus_cb264_device - constructor
+//-------------------------------------------------
+
+nubus_cb264_device::nubus_cb264_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NUBUS_CB264, "RasterOps ColorBoard 264 video card", tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_cb264";
+}
+
+nubus_cb264_device::nubus_cb264_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_cb264";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_cb264_device::device_start()
+{
+ UINT32 slotspace;
+
+ // set_nubus_device makes m_slot valid
+ set_nubus_device();
+ install_declaration_rom(this, CB264_ROM_REGION);
+
+ slotspace = get_slotspace();
+
+// printf("[cb264 %p] slotspace = %x\n", this, slotspace);
+
+ m_vram = auto_alloc_array(machine(), UINT8, VRAM_SIZE);
+ install_bank(slotspace, slotspace+VRAM_SIZE-1, 0, 0, "bank_cb264", m_vram);
+
+ m_nubus->install_device(slotspace+0xff6000, slotspace+0xff60ff, read32_delegate(FUNC(nubus_cb264_device::cb264_r), this), write32_delegate(FUNC(nubus_cb264_device::cb264_w), this));
+ m_nubus->install_device(slotspace+0xff7000, slotspace+0xff70ff, read32_delegate(FUNC(nubus_cb264_device::cb264_ramdac_r), this), write32_delegate(FUNC(nubus_cb264_device::cb264_ramdac_w), this));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void nubus_cb264_device::device_reset()
+{
+ m_cb264_toggle = 0;
+ m_count = 0;
+ m_clutoffs = 0;
+ m_cb264_vbl_disable = 1;
+ m_cb264_mode = 0;
+ memset(m_vram, 0, VRAM_SIZE);
+ memset(m_palette, 0, sizeof(m_palette));
+}
+
+/***************************************************************************
+
+ ColorBoard 264 section
+
+***************************************************************************/
+
+static SCREEN_UPDATE_RGB32( cb264 )
+{
+ UINT32 *scanline, *base;
+ int x, y;
+ nubus_cb264_device *card = downcast<nubus_cb264_device *>(screen.owner());
+ UINT8 pixels;
+
+ if (!card->m_cb264_vbl_disable)
+ {
+ card->raise_slot_irq();
+ }
+
+ switch (card->m_cb264_mode)
+ {
+ case 0: // 1 bpp
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640/8; x++)
+ {
+ pixels = card->m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[pixels&0x80];
+ *scanline++ = card->m_palette[(pixels<<1)&0x80];
+ *scanline++ = card->m_palette[(pixels<<2)&0x80];
+ *scanline++ = card->m_palette[(pixels<<3)&0x80];
+ *scanline++ = card->m_palette[(pixels<<4)&0x80];
+ *scanline++ = card->m_palette[(pixels<<5)&0x80];
+ *scanline++ = card->m_palette[(pixels<<6)&0x80];
+ *scanline++ = card->m_palette[(pixels<<7)&0x80];
+ }
+ }
+ break;
+
+ case 1: // 2 bpp (3f/7f/bf/ff)
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640/4; x++)
+ {
+ pixels = card->m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[pixels&0xc0];
+ *scanline++ = card->m_palette[(pixels<<2)&0xc0];
+ *scanline++ = card->m_palette[(pixels<<4)&0xc0];
+ *scanline++ = card->m_palette[(pixels<<6)&0xc0];
+ }
+ }
+ break;
+
+ case 2: // 4 bpp
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 640/2; x++)
+ {
+ pixels = card->m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[pixels&0xf0];
+ *scanline++ = card->m_palette[(pixels<<4)&0xf0];
+ }
+ }
+ break;
+
+ case 3: // 8 bpp
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 640; x++)
+ {
+ pixels = card->m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ *scanline++ = card->m_palette[pixels];
+ }
+ }
+ break;
+
+ case 4: // 24 bpp
+ case 7: // ???
+ {
+ UINT32 *vram32 = (UINT32 *)card->m_vram;
+
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ base = &vram32[y * 1024];
+ for (x = 0; x < 640; x++)
+ {
+ *scanline++ = *base++;
+ }
+ }
+ }
+ break;
+
+ default:
+ fatalerror("cb264: unknown video mode %d", card->m_cb264_mode);
+ break;
+
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_cb264_device::cb264_w )
+{
+ switch (offset)
+ {
+ case 0x4/4: // 0 = 1 bpp, 1 = 2bpp, 2 = 4bpp, 3 = 8bpp, 4 = 24bpp
+ m_cb264_mode = data;
+ break;
+
+ case 0x14/4: // VBL ack
+ lower_slot_irq();
+ break;
+
+ case 0x3c/4: // VBL disable
+ m_cb264_vbl_disable = data;
+ break;
+
+ default:
+// printf("cb264_w: %x to reg %x (mask %x PC %x)\n", data, offset*4, mem_mask, cpu_get_pc(&space->device()));
+ break;
+ }
+}
+
+READ32_MEMBER( nubus_cb264_device::cb264_r )
+{
+ switch (offset)
+ {
+ case 0x0c/4:
+ case 0x28/4:
+ break;
+
+ case 0x34/4:
+ m_cb264_toggle ^= 1;
+ return m_cb264_toggle; // bit 0 is vblank?
+
+ default:
+ logerror("cb264_r: reg %x (mask %x PC %x)\n", offset*4, mem_mask, cpu_get_pc(&space.device()));
+ break;
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_cb264_device::cb264_ramdac_w )
+{
+ switch (offset)
+ {
+ case 0:
+ m_clutoffs = data>>24;
+ m_count = 0;
+ break;
+
+ case 1:
+ m_colors[m_count++] = data>>24;
+
+ if (m_count == 3)
+ {
+ m_palette[m_clutoffs] = MAKE_RGB(m_colors[0], m_colors[1], m_colors[2]);
+ m_clutoffs++;
+ m_count = 0;
+ }
+ break;
+
+ default:
+// printf("%x to unknown RAMDAC register @ %x\n", data, offset);
+ break;
+ }
+}
+
+READ32_MEMBER( nubus_cb264_device::cb264_ramdac_r )
+{
+ return 0;
+}
+
diff --git a/src/mess/video/nubus_cb264.h b/src/mess/video/nubus_cb264.h
new file mode 100644
index 00000000000..ef9603e51a6
--- /dev/null
+++ b/src/mess/video/nubus_cb264.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifndef __NUBUS_CB264_H__
+#define __NUBUS_CB264_H__
+
+#include "emu.h"
+#include "machine/nubus.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> nubus_cb264_device
+
+class nubus_cb264_device :
+ public device_t,
+ public device_nubus_card_interface
+{
+public:
+ // construction/destruction
+ nubus_cb264_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ nubus_cb264_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ DECLARE_READ32_MEMBER(cb264_r);
+ DECLARE_WRITE32_MEMBER(cb264_w);
+ DECLARE_READ32_MEMBER(cb264_ramdac_r);
+ DECLARE_WRITE32_MEMBER(cb264_ramdac_w);
+
+public:
+ UINT8 *m_vram;
+ UINT32 m_cb264_mode, m_cb264_vbl_disable, m_cb264_toggle;
+ UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs;
+};
+
+
+// device type definition
+extern const device_type NUBUS_CB264;
+
+#endif /* __NUBUS_CB264_H__ */
diff --git a/src/mess/video/nubus_m2hires.c b/src/mess/video/nubus_m2hires.c
new file mode 100644
index 00000000000..09c2a3d3282
--- /dev/null
+++ b/src/mess/video/nubus_m2hires.c
@@ -0,0 +1,320 @@
+/***************************************************************************
+
+ Apple Hi-Resolution Video Card emulation
+
+ RAMDAC: control at Fs0940e0, data at Fs0940e4
+ Fs090010 bit 16 is vbl status, bit 17 must be "1" for proper operation
+ Fs08000x are the control registers
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/nubus_m2hires.h"
+
+#define M2HIRES_SCREEN_NAME "m2hires_screen"
+#define M2HIRES_ROM_REGION "m2hires_rom"
+
+#define VRAM_SIZE (0x80000) // 512k max
+
+static SCREEN_UPDATE_RGB32( m2hires );
+
+MACHINE_CONFIG_FRAGMENT( m2hires )
+ MCFG_SCREEN_ADD( M2HIRES_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_UPDATE_STATIC(m2hires)
+ MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480)
+ MCFG_SCREEN_SIZE(1024,768)
+ MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1)
+MACHINE_CONFIG_END
+
+ROM_START( m2hires )
+ ROM_REGION(0x2000, M2HIRES_ROM_REGION, 0)
+ ROM_LOAD( "341-0660.bin", 0x0000, 0x2000, CRC(ea6f7913) SHA1(37c59f38ae34021d0cb86c2e76a598b7e6077c0d) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_M2HIRES = &device_creator<nubus_m2hires_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nubus_m2hires_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( m2hires );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *nubus_m2hires_device::device_rom_region() const
+{
+ return ROM_NAME( m2hires );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nubus_m2hires_device - constructor
+//-------------------------------------------------
+
+nubus_m2hires_device::nubus_m2hires_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NUBUS_M2HIRES, "Macintosh II Hi-Resolution video card", tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_m2hr";
+}
+
+nubus_m2hires_device::nubus_m2hires_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_m2hr";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_m2hires_device::device_start()
+{
+ UINT32 slotspace;
+
+ // set_nubus_device makes m_slot valid
+ set_nubus_device();
+ install_declaration_rom(this, M2HIRES_ROM_REGION, true);
+
+ slotspace = get_slotspace();
+
+// printf("[m2hires %p] slotspace = %x\n", this, slotspace);
+
+ m_vram = auto_alloc_array(machine(), UINT8, VRAM_SIZE);
+ m_vram32 = (UINT32 *)m_vram;
+
+ m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_m2hires_device::vram_r), this), write32_delegate(FUNC(nubus_m2hires_device::vram_w), this));
+ m_nubus->install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32_delegate(FUNC(nubus_m2hires_device::vram_r), this), write32_delegate(FUNC(nubus_m2hires_device::vram_w), this));
+ m_nubus->install_device(slotspace+0x80000, slotspace+0xeffff, read32_delegate(FUNC(nubus_m2hires_device::m2hires_r), this), write32_delegate(FUNC(nubus_m2hires_device::m2hires_w), this));
+
+ m_timer = timer_alloc(0, NULL);
+ m_screen = NULL; // can we look this up now?
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void nubus_m2hires_device::device_reset()
+{
+ m_count = 0;
+ m_clutoffs = 0;
+ m_vbl_disable = 1;
+ m_mode = 0;
+ memset(m_vram, 0, VRAM_SIZE);
+ memset(m_palette, 0, sizeof(m_palette));
+
+ m_palette[0] = MAKE_RGB(255, 255, 255);
+ m_palette[0x80] = MAKE_RGB(0, 0, 0);
+}
+
+
+void nubus_m2hires_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+ if (!m_vbl_disable)
+ {
+ raise_slot_irq();
+ }
+
+ m_timer->adjust(m_screen->time_until_pos(479, 0), 0);
+}
+
+/***************************************************************************
+
+ Spectrum 24 PDQ section
+
+***************************************************************************/
+
+static SCREEN_UPDATE_RGB32( m2hires )
+{
+ UINT32 *scanline;
+ int x, y;
+ nubus_m2hires_device *card = downcast<nubus_m2hires_device *>(screen.owner());
+ UINT8 pixels, *vram;
+
+ // first time? kick off the VBL timer
+ if (!card->m_screen)
+ {
+ card->m_screen = &screen;
+ card->m_timer->adjust(card->m_screen->time_until_pos(479, 0), 0);
+ }
+
+ vram = card->m_vram + 0x20;
+
+ switch (card->m_mode)
+ {
+ case 0: // 1 bpp?
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640/8; x++)
+ {
+ pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[((pixels>>7)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>6)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>5)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>4)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>3)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>2)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>1)&0x1)];
+ *scanline++ = card->m_palette[(pixels&1)];
+ }
+ }
+ break;
+
+ case 1: // 2 bpp
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640/4; x++)
+ {
+ pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[((pixels>>6)&3)];
+ *scanline++ = card->m_palette[((pixels>>4)&3)];
+ *scanline++ = card->m_palette[((pixels>>2)&3)];
+ *scanline++ = card->m_palette[(pixels&3)];
+ }
+ }
+ break;
+
+ case 2: // 4 bpp
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 640/2; x++)
+ {
+ pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[((pixels&0xf0)>>4)];
+ *scanline++ = card->m_palette[(pixels&0xf)];
+ }
+ }
+ break;
+
+ case 3: // 8 bpp
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 640; x++)
+ {
+ pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ *scanline++ = card->m_palette[pixels];
+ }
+ }
+ break;
+
+ default:
+ fatalerror("m2hires: unknown video mode %d", card->m_mode);
+ break;
+
+ }
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_m2hires_device::m2hires_w )
+{
+ data ^= 0xffffffff;
+
+ switch (offset)
+ {
+ case 1: // mode
+ switch (data)
+ {
+ case 0x20000000:
+ m_mode = 0;
+ break;
+
+ case 0x40000000:
+ m_mode = 1;
+ break;
+
+ case 0x80000000:
+ m_mode = 2;
+ break;
+
+ case 0x00010000:
+ m_mode = 3;
+ break;
+ }
+ break;
+
+ case 0x5038: // DAC control
+// printf("%08x to DAC control (PC=%x)\n", data, cpu_get_pc(&space.device()));
+ m_clutoffs = (data>>24)&0xff;
+ break;
+
+ case 0x5039: // DAC data
+ m_colors[m_count++] = (data>>24) & 0xff;
+
+ if (m_count == 3)
+ {
+// printf("RAMDAC: color %d = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], cpu_get_pc(&space.device()) );
+ m_palette[m_clutoffs] = MAKE_RGB(m_colors[0], m_colors[1], m_colors[2]);
+ m_clutoffs++;
+ if (m_clutoffs > 255)
+ {
+ m_clutoffs = 0;
+ }
+ m_count = 0;
+ }
+ break;
+
+ case 0x8000: // enable and ack VBL
+ m_vbl_disable = 0;
+ lower_slot_irq();
+ break;
+
+ case 0x8001: // disable VBL
+ m_vbl_disable = 1;
+ break;
+
+ default:
+// printf("m2hires_w: %08x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, cpu_get_pc(&space.device()));
+ break;
+ }
+}
+
+READ32_MEMBER( nubus_m2hires_device::m2hires_r )
+{
+ if (offset == 0x10010/4)
+ {
+ m_toggle ^= (1<<16);
+ return m_toggle | (1<<17); // bit 17 indicates a 4/8bpp capable ASIC apparently; the firmware won't enter those modes otherwise (although they show in the list)
+ }
+/* else
+ {
+ printf("m2hires_r: @ %x, mask %08x (PC=%x)\n", offset, mem_mask, cpu_get_pc(&space.device()));
+ }*/
+
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_m2hires_device::vram_w )
+{
+ data ^= 0xffffffff;
+ COMBINE_DATA(&m_vram32[offset]);
+}
+
+READ32_MEMBER( nubus_m2hires_device::vram_r )
+{
+ return m_vram32[offset] ^ 0xffffffff;
+}
diff --git a/src/mess/video/nubus_m2hires.h b/src/mess/video/nubus_m2hires.h
new file mode 100644
index 00000000000..1883f8aaa81
--- /dev/null
+++ b/src/mess/video/nubus_m2hires.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#ifndef __NUBUS_M2HIRES_H__
+#define __NUBUS_M2HIRES_H__
+
+#include "emu.h"
+#include "machine/nubus.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> nubus_m2hires_device
+
+class nubus_m2hires_device :
+ public device_t,
+ public device_nubus_card_interface
+{
+public:
+ // construction/destruction
+ nubus_m2hires_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ nubus_m2hires_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ DECLARE_READ32_MEMBER(m2hires_r);
+ DECLARE_WRITE32_MEMBER(m2hires_w);
+ DECLARE_READ32_MEMBER(vram_r);
+ DECLARE_WRITE32_MEMBER(vram_w);
+
+public:
+ UINT8 *m_vram;
+ UINT32 *m_vram32;
+ UINT32 m_mode, m_vbl_disable, m_toggle;
+ UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs;
+ screen_device *m_screen;
+ emu_timer *m_timer;
+};
+
+
+// device type definition
+extern const device_type NUBUS_M2HIRES;
+
+#endif /* __NUBUS_M2HIRES_H__ */
diff --git a/src/mess/video/nubus_radiustpd.c b/src/mess/video/nubus_radiustpd.c
new file mode 100644
index 00000000000..6bc2b2e3681
--- /dev/null
+++ b/src/mess/video/nubus_radiustpd.c
@@ -0,0 +1,218 @@
+/***************************************************************************
+
+ Radius Two Page Display (1280x960?)
+
+ Fsx8000a = DAC data
+ Fsx8000e = DAC control
+ Fsx00000 = VRAM (offset 0x200, stride 0x1b0)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/nubus_radiustpd.h"
+
+#define RADIUSTPD_SCREEN_NAME "tpd_screen"
+#define RADIUSTPD_ROM_REGION "tpd_rom"
+
+#define VRAM_SIZE (0x40000) // 256k. 1152x880 1 bit per pixel fits nicely.
+
+static SCREEN_UPDATE_RGB32( radiustpd );
+
+MACHINE_CONFIG_FRAGMENT( radiustpd )
+ MCFG_SCREEN_ADD( RADIUSTPD_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_UPDATE_STATIC(radiustpd)
+ MCFG_SCREEN_SIZE(1280, 960)
+ MCFG_SCREEN_REFRESH_RATE(70)
+ MCFG_SCREEN_VISIBLE_AREA(0, 1152-1, 0, 880-1)
+MACHINE_CONFIG_END
+
+ROM_START( radiustpd )
+ ROM_REGION(0x8000, RADIUSTPD_ROM_REGION, 0)
+ ROM_LOAD( "tpd_v22.bin", 0x0000, 0x8000, CRC(7dc5ed05) SHA1(4abb64e49201e966c17a255a94b670564b229934) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_RADIUSTPD = &device_creator<nubus_radiustpd_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nubus_radiustpd_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( radiustpd );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *nubus_radiustpd_device::device_rom_region() const
+{
+ return ROM_NAME( radiustpd );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nubus_radiustpd_device - constructor
+//-------------------------------------------------
+
+nubus_radiustpd_device::nubus_radiustpd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NUBUS_RADIUSTPD, "Radius Two Page Display video card", tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_rtpd";
+}
+
+nubus_radiustpd_device::nubus_radiustpd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_rtpd";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_radiustpd_device::device_start()
+{
+ UINT32 slotspace;
+
+ // set_nubus_device makes m_slot valid
+ set_nubus_device();
+ install_declaration_rom(this, RADIUSTPD_ROM_REGION, true, true);
+
+ slotspace = get_slotspace();
+
+ printf("[radiustpd %p] slotspace = %x\n", this, slotspace);
+
+ m_vram = auto_alloc_array(machine(), UINT8, VRAM_SIZE);
+ m_vram32 = (UINT32 *)m_vram;
+
+ m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_radiustpd_device::vram_r), this), write32_delegate(FUNC(nubus_radiustpd_device::vram_w), this));
+ m_nubus->install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32_delegate(FUNC(nubus_radiustpd_device::vram_r), this), write32_delegate(FUNC(nubus_radiustpd_device::vram_w), this));
+ m_nubus->install_device(slotspace+0x80000, slotspace+0xeffff, read32_delegate(FUNC(nubus_radiustpd_device::radiustpd_r), this), write32_delegate(FUNC(nubus_radiustpd_device::radiustpd_w), this));
+ m_nubus->install_device(slotspace+0x980000, slotspace+0x9effff, read32_delegate(FUNC(nubus_radiustpd_device::radiustpd_r), this), write32_delegate(FUNC(nubus_radiustpd_device::radiustpd_w), this));
+
+ m_timer = timer_alloc(0, NULL);
+ m_screen = NULL; // can we look this up now?
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void nubus_radiustpd_device::device_reset()
+{
+ m_count = 0;
+ m_clutoffs = 0;
+ m_vbl_disable = 1;
+ m_mode = 0;
+ memset(m_vram, 0, VRAM_SIZE);
+ memset(m_palette, 0, sizeof(m_palette));
+
+ m_palette[1] = MAKE_RGB(255, 255, 255);
+ m_palette[0] = MAKE_RGB(0, 0, 0);
+}
+
+
+void nubus_radiustpd_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+ if (!m_vbl_disable)
+ {
+ raise_slot_irq();
+ }
+
+ m_timer->adjust(m_screen->time_until_pos(479, 0), 0);
+}
+
+/***************************************************************************
+
+ Two Page Display section
+
+***************************************************************************/
+
+static SCREEN_UPDATE_RGB32( radiustpd )
+{
+ UINT32 *scanline;
+ int x, y;
+ nubus_radiustpd_device *card = downcast<nubus_radiustpd_device *>(screen.owner());
+ UINT8 pixels, *vram;
+
+ // first time? kick off the VBL timer
+ if (!card->m_screen)
+ {
+ card->m_screen = &screen;
+ card->m_timer->adjust(card->m_screen->time_until_pos(479, 0), 0);
+ }
+
+ vram = card->m_vram + 0x200;
+
+ for (y = 0; y < 880; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 1152/8; x++)
+ {
+ pixels = vram[(y * (1152/8)) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[((pixels>>7)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>6)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>5)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>4)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>3)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>2)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>1)&0x1)];
+ *scanline++ = card->m_palette[(pixels&1)];
+ }
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_radiustpd_device::radiustpd_w )
+{
+// printf("TPD: write %08x to %x, mask %08x\n", data, offset, mem_mask);
+}
+
+READ32_MEMBER( nubus_radiustpd_device::radiustpd_r )
+{
+// printf("TPD: read @ %x, mask %08x\n", offset, mem_mask);
+
+ if (offset == 0)
+ {
+ lower_slot_irq();
+ m_vbl_disable = true;
+ }
+
+ if (offset == 0x8000)
+ {
+ m_vbl_disable = false;
+ }
+
+ if (offset == 0x18000)
+ {
+ return 0xffffffff;
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_radiustpd_device::vram_w )
+{
+ data ^= 0xffffffff;
+ COMBINE_DATA(&m_vram32[offset]);
+}
+
+READ32_MEMBER( nubus_radiustpd_device::vram_r )
+{
+ return m_vram32[offset] ^ 0xffffffff;
+}
diff --git a/src/mess/video/nubus_radiustpd.h b/src/mess/video/nubus_radiustpd.h
new file mode 100644
index 00000000000..2b3d5f79e4e
--- /dev/null
+++ b/src/mess/video/nubus_radiustpd.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#ifndef __NUBUS_RADIUSTPD_H__
+#define __NUBUS_RADIUSTPD_H__
+
+#include "emu.h"
+#include "machine/nubus.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> nubus_radiustpd_device
+
+class nubus_radiustpd_device :
+ public device_t,
+ public device_nubus_card_interface
+{
+public:
+ // construction/destruction
+ nubus_radiustpd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ nubus_radiustpd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ DECLARE_READ32_MEMBER(radiustpd_r);
+ DECLARE_WRITE32_MEMBER(radiustpd_w);
+ DECLARE_READ32_MEMBER(vram_r);
+ DECLARE_WRITE32_MEMBER(vram_w);
+
+public:
+ UINT8 *m_vram;
+ UINT32 *m_vram32;
+ UINT32 m_mode, m_vbl_disable, m_toggle;
+ UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs;
+ screen_device *m_screen;
+ emu_timer *m_timer;
+};
+
+
+// device type definition
+extern const device_type NUBUS_RADIUSTPD;
+
+#endif /* __NUBUS_RADIUSTPD_H__ */
diff --git a/src/mess/video/nubus_spec8.c b/src/mess/video/nubus_spec8.c
new file mode 100644
index 00000000000..4ee2911720c
--- /dev/null
+++ b/src/mess/video/nubus_spec8.c
@@ -0,0 +1,360 @@
+/***************************************************************************
+
+ SuperMac Spectrum/8 Series III video card
+
+ There is no sign of acceleration or blitting in any mode, and the acceleration
+ code from the Spectrum PDQ ROM is absent on this one.
+
+ On first boot / with clean PRAM, press SPACE repeatedly when it shows the frame
+ that fills the entire screen. If you get it wrong, delete PRAM and try again.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/nubus_spec8.h"
+
+#define SPEC8S3_SCREEN_NAME "spec8s3_screen"
+#define SPEC8S3_ROM_REGION "spec8s3_rom"
+
+#define VRAM_SIZE (0xc0000) // 768k of VRAM for 1024x768 @ 8 bit
+
+static SCREEN_UPDATE_RGB32( spec8s3 );
+
+MACHINE_CONFIG_FRAGMENT( spec8s3 )
+ MCFG_SCREEN_ADD( SPEC8S3_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_UPDATE_STATIC(spec8s3)
+ MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480)
+ MCFG_SCREEN_SIZE(1024,768)
+ MCFG_SCREEN_VISIBLE_AREA(0, 1024-1, 0, 768-1)
+MACHINE_CONFIG_END
+
+ROM_START( spec8s3 )
+ ROM_REGION(0x8000, SPEC8S3_ROM_REGION, 0)
+ ROM_LOAD( "1003067-0001d.11b.bin", 0x000000, 0x008000, CRC(12188e2b) SHA1(6552d40364eae99b449842a79843d8c0114c4c70) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_SPEC8S3 = &device_creator<nubus_spec8s3_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nubus_spec8s3_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( spec8s3 );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *nubus_spec8s3_device::device_rom_region() const
+{
+ return ROM_NAME( spec8s3 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nubus_spec8s3_device - constructor
+//-------------------------------------------------
+
+nubus_spec8s3_device::nubus_spec8s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NUBUS_SPEC8S3, "SuperMac Spectrum/8 Series III video card", tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_sp8s3";
+}
+
+nubus_spec8s3_device::nubus_spec8s3_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_sp8s3";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_spec8s3_device::device_start()
+{
+ UINT32 slotspace;
+
+ // set_nubus_device makes m_slot valid
+ set_nubus_device();
+ install_declaration_rom(this, SPEC8S3_ROM_REGION);
+
+ slotspace = get_slotspace();
+
+// printf("[SPEC8S3 %p] slotspace = %x\n", this, slotspace);
+
+ m_vram = auto_alloc_array(machine(), UINT8, VRAM_SIZE);
+ m_vram32 = (UINT32 *)m_vram;
+ m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_spec8s3_device::vram_r), this), write32_delegate(FUNC(nubus_spec8s3_device::vram_w), this));
+ m_nubus->install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32_delegate(FUNC(nubus_spec8s3_device::vram_r), this), write32_delegate(FUNC(nubus_spec8s3_device::vram_w), this));
+ m_nubus->install_device(slotspace+0xd0000, slotspace+0xfffff, read32_delegate(FUNC(nubus_spec8s3_device::spec8s3_r), this), write32_delegate(FUNC(nubus_spec8s3_device::spec8s3_w), this));
+
+ m_timer = timer_alloc(0, NULL);
+ m_screen = NULL; // can we look this up now?
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void nubus_spec8s3_device::device_reset()
+{
+ m_count = 0;
+ m_clutoffs = 0;
+ m_vbl_disable = 1;
+ m_mode = 0;
+ m_vbl_pending = false;
+ m_parameter = 0;
+ memset(m_vram, 0, VRAM_SIZE);
+ memset(m_palette, 0, sizeof(m_palette));
+
+ m_palette[0] = MAKE_RGB(255, 255, 255);
+ m_palette[1] = MAKE_RGB(0, 0, 0);
+}
+
+
+void nubus_spec8s3_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+ if (!m_vbl_disable)
+ {
+ raise_slot_irq();
+ m_vbl_pending = true;
+ }
+
+ m_timer->adjust(m_screen->time_until_pos(767, 0), 0);
+}
+
+/***************************************************************************
+
+ Spectrum 24 PDQ section
+
+***************************************************************************/
+
+static SCREEN_UPDATE_RGB32( spec8s3 )
+{
+ UINT32 *scanline;
+ int x, y;
+ nubus_spec8s3_device *card = downcast<nubus_spec8s3_device *>(screen.owner());
+ UINT8 pixels, *vram;
+
+ // first time? kick off the VBL timer
+ if (!card->m_screen)
+ {
+ card->m_screen = &screen;
+ card->m_timer->adjust(card->m_screen->time_until_pos(767, 0), 0);
+ }
+ vram = card->m_vram + 0x400;
+
+ switch (card->m_mode)
+ {
+ case 0: // 1 bpp
+ for (y = 0; y < 768; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 1024/8; x++)
+ {
+ pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[pixels&0x80];
+ *scanline++ = card->m_palette[(pixels<<1)&0x80];
+ *scanline++ = card->m_palette[(pixels<<2)&0x80];
+ *scanline++ = card->m_palette[(pixels<<3)&0x80];
+ *scanline++ = card->m_palette[(pixels<<4)&0x80];
+ *scanline++ = card->m_palette[(pixels<<5)&0x80];
+ *scanline++ = card->m_palette[(pixels<<6)&0x80];
+ *scanline++ = card->m_palette[(pixels<<7)&0x80];
+ }
+ }
+ break;
+
+ case 1: // 2 bpp
+ for (y = 0; y < 768; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 1024/4; x++)
+ {
+ pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[pixels&0xc0];
+ *scanline++ = card->m_palette[(pixels<<2)&0xc0];
+ *scanline++ = card->m_palette[(pixels<<4)&0xc0];
+ *scanline++ = card->m_palette[(pixels<<6)&0xc0];
+ }
+ }
+ break;
+
+ case 2: // 4 bpp
+ for (y = 0; y < 768; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 1024/2; x++)
+ {
+ pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[pixels&0xf0];
+ *scanline++ = card->m_palette[(pixels<<4)&0xf0];
+ }
+ }
+ break;
+
+ case 3: // 8 bpp
+ for (y = 0; y < 768; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 1024; x++)
+ {
+ pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ *scanline++ = card->m_palette[pixels];
+ }
+ }
+ break;
+
+ default:
+ fatalerror("spec8s3: unknown video mode %d", card->m_mode);
+ break;
+
+ }
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_spec8s3_device::spec8s3_w )
+{
+ switch (offset)
+ {
+ case 0x385c: // IRQ enable
+ if (data & 0x10)
+ {
+ m_vbl_disable = 1;
+ lower_slot_irq();
+ m_vbl_pending = false;
+ }
+ else
+ {
+ m_vbl_disable = 0;
+ }
+ break;
+
+ case 0x385e:
+ break;
+
+ case 0x386e:
+ break;
+
+ case 0x3a00:
+ m_clutoffs = (data & 0xff) ^ 0xff;
+ break;
+
+ case 0x3a01:
+// printf("%08x to color (%08x invert)\n", data, data ^ 0xffffffff);
+ m_colors[m_count++] = (data & 0xff) ^ 0xff;
+
+ if (m_count == 3)
+ {
+ int actual_color = BITSWAP8(m_clutoffs, 0, 1, 2, 3, 4, 5, 6, 7);
+
+// printf("RAMDAC: color %d = %02x %02x %02x (PC=%x)\n", actual_color, m_colors[0], m_colors[1], m_colors[2], cpu_get_pc(&space.device()) );
+ m_palette[actual_color] = MAKE_RGB(m_colors[0], m_colors[1], m_colors[2]);
+ m_clutoffs++;
+ if (m_clutoffs > 255)
+ {
+ m_clutoffs = 0;
+ }
+ m_count = 0;
+ }
+ break;
+
+ case 0x3c00:
+ if ((m_parameter == 2) && (data != 0xffffffff))
+ {
+ data &= 0xff;
+// printf("%x to mode\n", data);
+ switch (data)
+ {
+ case 0x5f:
+ m_mode = 0;
+ break;
+
+ case 0x5e:
+ m_mode = 1;
+ break;
+
+ case 0x5d:
+ m_mode = 2;
+ break;
+
+ case 0x5c:
+ m_mode = 3;
+ break;
+ }
+ }
+ m_parameter++;
+ break;
+
+ case 0x3e02:
+ if (data == 1)
+ {
+ m_parameter = 0;
+ }
+ break;
+
+ default:
+// if (offset >= 0x3800) printf("spec8s3_w: %08x @ %x (mask %08x PC=%x)\n", data, offset, mem_mask, cpu_get_pc(&space.device()));
+ break;
+ }
+}
+
+READ32_MEMBER( nubus_spec8s3_device::spec8s3_r )
+{
+ switch (offset)
+ {
+ case 0x3826:
+ case 0x382e:
+ return 0xff;
+
+ case 0x3824:
+ case 0x382c:
+ return (0xa^0xffffffff);
+
+ case 0x385c:
+ if (m_vbl_pending)
+ {
+ return 0x8;
+ }
+ return 0;
+
+ case 0x385e:
+ return 0;
+
+ default:
+// if (offset >= 0x3800) printf("spec8s3_r: @ %x (mask %08x PC=%x)\n", offset, mem_mask, cpu_get_pc(&space.device()));
+ break;
+ }
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_spec8s3_device::vram_w )
+{
+ data ^= 0xffffffff;
+ COMBINE_DATA(&m_vram32[offset]);
+}
+
+READ32_MEMBER( nubus_spec8s3_device::vram_r )
+{
+ return m_vram32[offset] ^ 0xffffffff;
+}
diff --git a/src/mess/video/nubus_spec8.h b/src/mess/video/nubus_spec8.h
new file mode 100644
index 00000000000..e43246f39a7
--- /dev/null
+++ b/src/mess/video/nubus_spec8.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#ifndef __NUBUS_SPEC8S3_H__
+#define __NUBUS_SPEC8S3_H__
+
+#include "emu.h"
+#include "machine/nubus.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> nubus_spec8s3_device
+
+class nubus_spec8s3_device :
+ public device_t,
+ public device_nubus_card_interface
+{
+public:
+ // construction/destruction
+ nubus_spec8s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ nubus_spec8s3_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ DECLARE_READ32_MEMBER(spec8s3_r);
+ DECLARE_WRITE32_MEMBER(spec8s3_w);
+ DECLARE_READ32_MEMBER(vram_r);
+ DECLARE_WRITE32_MEMBER(vram_w);
+
+public:
+ UINT8 *m_vram;
+ UINT32 *m_vram32;
+ UINT32 m_mode, m_vbl_disable;
+ UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs;
+ screen_device *m_screen;
+ emu_timer *m_timer;
+
+private:
+ UINT32 m_7xxxxx_regs[0x100000/4];
+ int m_width, m_height, m_patofsx, m_patofsy;
+ UINT32 m_vram_addr, m_vram_src;
+ UINT8 m_fillbytes[256];
+ bool m_vbl_pending;
+ int m_parameter;
+};
+
+
+// device type definition
+extern const device_type NUBUS_SPEC8S3;
+
+#endif /* __NUBUS_SPEC8S3_H__ */
diff --git a/src/mess/video/nubus_specpdq.c b/src/mess/video/nubus_specpdq.c
new file mode 100644
index 00000000000..820e54eb098
--- /dev/null
+++ b/src/mess/video/nubus_specpdq.c
@@ -0,0 +1,490 @@
+/***************************************************************************
+
+ SuperMac Spectrum PDQ video card
+
+ Accelerated only in 256 color mode. Accleration is not yet emulated
+ properly (pattern fill works but has glitches). Use in B&W or 16 colors
+ for full functionality right now.
+
+ blitter info:
+
+ ctrl 1 = ?
+ ctrl 2 = low 3 bits of Y position in bits 3-5, low 3 bits of X position in bits 0-2
+ ctrl 3 = width
+ ctrl 4 = height
+ ctrl 5 = ?
+ ctrl 6 = VRAM offset * 4
+ ctrl 7 = command/execute (00000002 for pattern fill, 00000100 for copy)
+
+ Busy flag at Fs800000 (bit 8)
+
+ There is 256 bytes of pattern RAM arranged as 32 pixels horizontally by 8
+ vertically.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/nubus_specpdq.h"
+
+#define SPECPDQ_SCREEN_NAME "specpdq_screen"
+#define SPECPDQ_ROM_REGION "specpdq_rom"
+
+#define VRAM_SIZE (0x400000)
+
+static SCREEN_UPDATE_RGB32( specpdq );
+
+MACHINE_CONFIG_FRAGMENT( specpdq )
+ MCFG_SCREEN_ADD( SPECPDQ_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_UPDATE_STATIC(specpdq)
+ MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480)
+ MCFG_SCREEN_SIZE(1280,1024)
+ MCFG_SCREEN_VISIBLE_AREA(0, 1152-1, 0, 844-1)
+MACHINE_CONFIG_END
+
+ROM_START( specpdq )
+ ROM_REGION(0x10000, SPECPDQ_ROM_REGION, 0)
+ ROM_LOAD( "specpdq.bin", 0x000000, 0x010000, CRC(82a35f78) SHA1(9511c2df47140f4279196d3b8836b53429879dd9) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_SPECPDQ = &device_creator<nubus_specpdq_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nubus_specpdq_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( specpdq );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *nubus_specpdq_device::device_rom_region() const
+{
+ return ROM_NAME( specpdq );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nubus_specpdq_device - constructor
+//-------------------------------------------------
+
+nubus_specpdq_device::nubus_specpdq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NUBUS_SPECPDQ, "SuperMac Spectrum PDQ video card", tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_spdq";
+}
+
+nubus_specpdq_device::nubus_specpdq_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_spdq";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_specpdq_device::device_start()
+{
+ UINT32 slotspace;
+
+ // set_nubus_device makes m_slot valid
+ set_nubus_device();
+ install_declaration_rom(this, SPECPDQ_ROM_REGION);
+
+ slotspace = get_slotspace();
+
+// printf("[specpdq %p] slotspace = %x\n", this, slotspace);
+
+ m_vram = auto_alloc_array(machine(), UINT8, VRAM_SIZE);
+ m_vram32 = (UINT32 *)m_vram;
+ m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_specpdq_device::vram_r), this), write32_delegate(FUNC(nubus_specpdq_device::vram_w), this));
+ m_nubus->install_device(slotspace+0x400000, slotspace+0xfbffff, read32_delegate(FUNC(nubus_specpdq_device::specpdq_r), this), write32_delegate(FUNC(nubus_specpdq_device::specpdq_w), this));
+
+ m_timer = timer_alloc(0, NULL);
+ m_screen = NULL; // can we look this up now?
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void nubus_specpdq_device::device_reset()
+{
+ m_count = 0;
+ m_clutoffs = 0;
+ m_vbl_disable = 1;
+ m_mode = 0;
+ memset(m_vram, 0, VRAM_SIZE);
+ memset(m_palette, 0, sizeof(m_palette));
+
+ m_palette[0] = MAKE_RGB(255, 255, 255);
+ m_palette[0x80] = MAKE_RGB(0, 0, 0);
+}
+
+
+void nubus_specpdq_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+ if (!m_vbl_disable)
+ {
+ raise_slot_irq();
+ }
+
+ m_timer->adjust(m_screen->time_until_pos(843, 0), 0);
+}
+
+/***************************************************************************
+
+ Spectrum 24 PDQ section
+
+***************************************************************************/
+
+static SCREEN_UPDATE_RGB32( specpdq )
+{
+ UINT32 *scanline;
+ int x, y;
+ nubus_specpdq_device *card = downcast<nubus_specpdq_device *>(screen.owner());
+ UINT8 pixels, *vram;
+
+ // first time? kick off the VBL timer
+ if (!card->m_screen)
+ {
+ card->m_screen = &screen;
+ card->m_timer->adjust(card->m_screen->time_until_pos(843, 0), 0);
+ }
+ vram = card->m_vram + 0x9000;
+
+ switch (card->m_mode)
+ {
+ case 0: // 1 bpp
+ for (y = 0; y < 844; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 1152/8; x++)
+ {
+ pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[(pixels&0x80)];
+ *scanline++ = card->m_palette[((pixels<<1)&0x80)];
+ *scanline++ = card->m_palette[((pixels<<2)&0x80)];
+ *scanline++ = card->m_palette[((pixels<<3)&0x80)];
+ *scanline++ = card->m_palette[((pixels<<4)&0x80)];
+ *scanline++ = card->m_palette[((pixels<<5)&0x80)];
+ *scanline++ = card->m_palette[((pixels<<6)&0x80)];
+ *scanline++ = card->m_palette[((pixels<<7)&0x80)];
+ }
+ }
+ break;
+
+ case 1: // 2 bpp
+ for (y = 0; y < 844; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 1152/4; x++)
+ {
+ pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[(pixels&0xc0)];
+ *scanline++ = card->m_palette[((pixels<<2)&0xc0)];
+ *scanline++ = card->m_palette[((pixels<<4)&0xc0)];
+ *scanline++ = card->m_palette[((pixels<<6)&0xc0)];
+ }
+ }
+ break;
+
+ case 2: // 4 bpp
+ for (y = 0; y < 844; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 1152/2; x++)
+ {
+ pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[(pixels&0xf0)];
+ *scanline++ = card->m_palette[((pixels<<4)&0xf0)];
+ }
+ }
+ break;
+
+ case 3: // 8 bpp
+ for (y = 0; y < 844; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 1152; x++)
+ {
+ pixels = vram[(y * 1152) + (BYTE4_XOR_BE(x))];
+ *scanline++ = card->m_palette[pixels];
+ }
+ }
+ break;
+
+ default:
+ fatalerror("specpdq: unknown video mode %d", card->m_mode);
+ break;
+
+ }
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_specpdq_device::specpdq_w )
+{
+ if (offset >= 0xc0000 && offset < 0x100000)
+ {
+ COMBINE_DATA(&m_7xxxxx_regs[offset-0xc0000]);
+ }
+
+ switch (offset)
+ {
+ case 0xc0054: // mode 1
+// printf("%x to mode1\n", data);
+ break;
+
+ case 0xc005c: // interrupt control
+ if (!(data & 0x8000))
+ {
+ m_vbl_disable = 1;
+ }
+ else
+ {
+ m_vbl_disable = 0;
+ lower_slot_irq();
+ }
+ break;
+
+ case 0xc005e: // not sure, interrupt related?
+ break;
+
+ case 0xc007a:
+// printf("%x to mode2\n", data);
+
+ switch (data)
+ {
+ case 0xff7fffff:
+ m_mode = 0;
+ break;
+
+ case 0xfeffffff:
+ m_mode = 2;
+ break;
+
+ case 0xfedfffff:
+ m_mode = 3;
+ break;
+ }
+
+// printf("m_mode = %d\n", m_mode);
+ break;
+
+ case 0x120000: // DAC address
+// printf("%08x to DAC control (PC=%x)\n", data, cpu_get_pc(&space.device()));
+ m_clutoffs = ((data>>8)&0xff)^0xff;
+ break;
+
+ case 0x120001: // DAC data
+ m_colors[m_count++] = ((data>>8)&0xff)^0xff;
+
+ if (m_count == 3)
+ {
+// printf("RAMDAC: color %d = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], cpu_get_pc(&space.device()) );
+ palette_set_color(space.machine(), m_clutoffs, MAKE_RGB(m_colors[0], m_colors[1], m_colors[2]));
+ m_palette[m_clutoffs] = MAKE_RGB(m_colors[0], m_colors[1], m_colors[2]);
+ m_clutoffs++;
+ if (m_clutoffs > 255)
+ {
+ m_clutoffs = 0;
+ }
+ m_count = 0;
+ }
+ break;
+
+ // blitter texture? pattern? 256 pixels worth at 8bpp
+ case 0x181000:
+ case 0x181001:
+ case 0x181002:
+ case 0x181003:
+ case 0x181004:
+ case 0x181005:
+ case 0x181006:
+ case 0x181007:
+ case 0x181008:
+ case 0x181009:
+ case 0x18100a:
+ case 0x18100b:
+ case 0x18100c:
+ case 0x18100d:
+ case 0x18100e:
+ case 0x18100f:
+ case 0x181010:
+ case 0x181011:
+ case 0x181012:
+ case 0x181013:
+ case 0x181014:
+ case 0x181015:
+ case 0x181016:
+ case 0x181017:
+ case 0x181018:
+ case 0x181019:
+ case 0x18101a:
+ case 0x18101b:
+ case 0x18101c:
+ case 0x18101d:
+ case 0x18101e:
+ case 0x18101f:
+ case 0x181020:
+ case 0x181021:
+ case 0x181022:
+ case 0x181023:
+ case 0x181024:
+ case 0x181025:
+ case 0x181026:
+ case 0x181027:
+ case 0x181028:
+ case 0x181029:
+ case 0x18102a:
+ case 0x18102b:
+ case 0x18102c:
+ case 0x18102d:
+ case 0x18102e:
+ case 0x18102f:
+ case 0x181030:
+ case 0x181031:
+ case 0x181032:
+ case 0x181033:
+ case 0x181034:
+ case 0x181035:
+ case 0x181036:
+ case 0x181037:
+ case 0x181038:
+ case 0x181039:
+ case 0x18103a:
+ case 0x18103b:
+ case 0x18103c:
+ case 0x18103d:
+ case 0x18103e:
+ case 0x18103f:
+// printf("Pattern %08x @ %x\n", data ^ 0xffffffff, offset);
+ m_fillbytes[((offset&0x3f)*4)] = ((data>>24) & 0xff) ^ 0xff;
+ m_fillbytes[((offset&0x3f)*4)+1] = ((data>>16) & 0xff) ^ 0xff;
+ m_fillbytes[((offset&0x3f)*4)+2] = ((data>>8) & 0xff) ^ 0xff;
+ m_fillbytes[((offset&0x3f)*4)+3] = (data& 0xff) ^ 0xff;
+ break;
+
+ // blitter control
+ case 0x182006:
+// printf("%08x (%d) to blitter ctrl 1 (PC=%x)\n", data^0xffffffff, data^0xffffffff, cpu_get_pc(&space.device()));
+ break;
+
+ case 0x182008:
+// printf("%08x (%d) to blitter ctrl 2 (PC=%x)\n", data^0xffffffff, data^0xffffffff, cpu_get_pc(&space.device()));
+ m_patofsx = (data ^ 0xffffffff) & 7;
+ m_patofsy = ((data ^ 0xffffffff)>>3) & 7;
+ break;
+
+ case 0x18200e:
+// printf("%08x (%d) to blitter ctrl 3 (PC=%x)\n", data^0xffffffff, data^0xffffffff, cpu_get_pc(&space.device()));
+ m_width = data ^ 0xffffffff;
+ break;
+
+ case 0x18200b:
+// printf("%08x (%d) to blitter ctrl 4 (PC=%x)\n", data^0xffffffff, data^0xffffffff, cpu_get_pc(&space.device()));
+ m_height = (data ^ 0xffffffff) & 0xffff;
+ break;
+
+ case 0x18200a:
+ data ^= 0xffffffff;
+// printf("%08x to blitter ctrl 5 (PC=%x)\n", data, cpu_get_pc(&space.device()));
+ m_vram_src = data>>2;
+ break;
+
+ case 0x182009:
+ data ^= 0xffffffff;
+// printf("%08x to blitter ctrl 6 (PC=%x)\n", data, cpu_get_pc(&space.device()));
+ m_vram_addr = data>>2;
+ break;
+
+ case 0x182007:
+ data ^= 0xffffffff;
+// printf("%08x to blitter ctrl 7 (PC=%x)\n", data, cpu_get_pc(&space.device()));
+
+ // fill rectangle
+ if (data == 2)
+ {
+ int x, y;
+ UINT8 *vram = m_vram + m_vram_addr + m_patofsx; // m_vram_addr is missing the low 2 bits, we add them back here
+
+// printf("Fill rectangle with %02x %02x %02x %02x, width %d height %d\n", m_fillbytes[0], m_fillbytes[1], m_fillbytes[2], m_fillbytes[3], m_width, m_height);
+
+ for (y = 0; y < m_height; y++)
+ {
+ for (x = 0; x < m_width; x++)
+ {
+ vram[(y * 1152)+x] = m_fillbytes[((m_patofsx + x) & 0x1f)+(((m_patofsy + y) & 0x7)*32)];
+ }
+ }
+ }
+ else if ((data == 0x101) || (data == 0x100))
+ {
+ int x, y;
+ UINT8 *vram = m_vram + m_vram_addr;
+ UINT8 *vramsrc = m_vram + m_vram_src;
+
+// printf("Copy rectangle, width %d height %d src %x dst %x\n", m_width, m_height, m_vram_addr, m_vram_src);
+
+ for (y = 0; y < m_height; y++)
+ {
+ for (x = 0; x < m_width; x++)
+ {
+ vram[(y * 1152)+x] = vramsrc[(y * 1152)+x];
+ }
+ }
+ }
+ else
+ {
+ printf("Unknown blitter command %08x\n", data);
+ }
+ break;
+
+ default:
+// printf("specpdq_w: %08x @ %x (mask %08x PC=%x)\n", data^0xffffffff, offset, mem_mask, cpu_get_pc(&space.device()));
+ break;
+ }
+}
+
+READ32_MEMBER( nubus_specpdq_device::specpdq_r )
+{
+// if (offset != 0xc005c && offset != 0xc005e) printf("specpdq_r: @ %x (mask %08x PC=%x)\n", offset, mem_mask, cpu_get_pc(&space.device()));
+
+ if (offset >= 0xc0000 && offset < 0x100000)
+ {
+ return m_7xxxxx_regs[offset-0xc0000];
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_specpdq_device::vram_w )
+{
+ data ^= 0xffffffff;
+ COMBINE_DATA(&m_vram32[offset]);
+}
+
+READ32_MEMBER( nubus_specpdq_device::vram_r )
+{
+ return m_vram32[offset] ^ 0xffffffff;
+}
diff --git a/src/mess/video/nubus_specpdq.h b/src/mess/video/nubus_specpdq.h
new file mode 100644
index 00000000000..83f5f68f11f
--- /dev/null
+++ b/src/mess/video/nubus_specpdq.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#ifndef __NUBUS_SPECPDQ_H__
+#define __NUBUS_SPECPDQ_H__
+
+#include "emu.h"
+#include "machine/nubus.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> nubus_specpdq_device
+
+class nubus_specpdq_device :
+ public device_t,
+ public device_nubus_card_interface
+{
+public:
+ // construction/destruction
+ nubus_specpdq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ nubus_specpdq_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ DECLARE_READ32_MEMBER(specpdq_r);
+ DECLARE_WRITE32_MEMBER(specpdq_w);
+ DECLARE_READ32_MEMBER(vram_r);
+ DECLARE_WRITE32_MEMBER(vram_w);
+
+public:
+ UINT8 *m_vram;
+ UINT32 *m_vram32;
+ UINT32 m_mode, m_vbl_disable;
+ UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs;
+ screen_device *m_screen;
+ emu_timer *m_timer;
+
+private:
+ UINT32 m_7xxxxx_regs[0x100000/4];
+ int m_width, m_height, m_patofsx, m_patofsy;
+ UINT32 m_vram_addr, m_vram_src;
+ UINT8 m_fillbytes[256];
+};
+
+
+// device type definition
+extern const device_type NUBUS_SPECPDQ;
+
+#endif /* __NUBUS_SPECPDQ_H__ */
diff --git a/src/mess/video/nubus_vikbw.c b/src/mess/video/nubus_vikbw.c
new file mode 100644
index 00000000000..a9124f1bb08
--- /dev/null
+++ b/src/mess/video/nubus_vikbw.c
@@ -0,0 +1,178 @@
+/***************************************************************************
+
+ Viking 1024x768 fixed-resolution monochrome board
+
+ VRAM from Fs040000 to Fs0517FF
+ Read from Fs000000 enables VBL, write to Fs000000 disables VBL
+ Write to Fs080000 acks VBL
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/nubus_vikbw.h"
+
+#define VIKBW_SCREEN_NAME "vikbw_screen"
+#define VIKBW_ROM_REGION "vikbw_rom"
+
+#define VRAM_SIZE (0x18000) // 1024x768 @ 1bpp is 98,304 bytes (0x18000)
+
+static SCREEN_UPDATE_RGB32( vikbw );
+
+MACHINE_CONFIG_FRAGMENT( vikbw )
+ MCFG_SCREEN_ADD( VIKBW_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_UPDATE_STATIC(vikbw)
+ MCFG_SCREEN_SIZE(1024,768)
+ MCFG_SCREEN_VISIBLE_AREA(0, 1024-1, 0, 768-1)
+ MCFG_SCREEN_REFRESH_RATE(70)
+MACHINE_CONFIG_END
+
+ROM_START( vikbw )
+ ROM_REGION(0x2000, VIKBW_ROM_REGION, 0)
+ ROM_LOAD( "viking.bin", 0x000000, 0x002000, CRC(92cf04d1) SHA1(d08349edfc82a0bd5ea848e053e1712092308f74) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_VIKBW = &device_creator<nubus_vikbw_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nubus_vikbw_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vikbw );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *nubus_vikbw_device::device_rom_region() const
+{
+ return ROM_NAME( vikbw );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nubus_vikbw_device - constructor
+//-------------------------------------------------
+
+nubus_vikbw_device::nubus_vikbw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NUBUS_VIKBW, "Moniterm Viking video card", tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_vikbw";
+}
+
+nubus_vikbw_device::nubus_vikbw_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_vikbw";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_vikbw_device::device_start()
+{
+ UINT32 slotspace;
+
+ // set_nubus_device makes m_slot valid
+ set_nubus_device();
+ install_declaration_rom(this, VIKBW_ROM_REGION, true);
+
+ slotspace = get_slotspace();
+
+// printf("[vikbw %p] slotspace = %x\n", this, slotspace);
+
+ m_vram = auto_alloc_array(machine(), UINT8, VRAM_SIZE);
+ install_bank(slotspace+0x40000, slotspace+0x40000+VRAM_SIZE-1, 0, 0, "bank_vikbw", m_vram);
+ install_bank(slotspace+0x940000, slotspace+0x940000+VRAM_SIZE-1, 0, 0, "bank_vikbw2", m_vram);
+
+ m_nubus->install_device(slotspace, slotspace+3, read32_delegate(FUNC(nubus_vikbw_device::viking_enable_r), this), write32_delegate(FUNC(nubus_vikbw_device::viking_disable_w), this));
+ m_nubus->install_device(slotspace+0x80000, slotspace+0x80000+3, read32_delegate(FUNC(nubus_vikbw_device::viking_ack_r), this), write32_delegate(FUNC(nubus_vikbw_device::viking_ack_w), this));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void nubus_vikbw_device::device_reset()
+{
+ m_vbl_disable = 1;
+ memset(m_vram, 0, VRAM_SIZE);
+
+ m_palette[0] = MAKE_RGB(255, 255, 255);
+ m_palette[1] = MAKE_RGB(0, 0, 0);
+}
+
+/***************************************************************************
+
+ Viking 1024x768 B&W card section
+
+***************************************************************************/
+
+static SCREEN_UPDATE_RGB32( vikbw )
+{
+ UINT32 *scanline;
+ int x, y;
+ nubus_vikbw_device *card = downcast<nubus_vikbw_device *>(screen.owner());
+ UINT8 pixels;
+
+ if (!card->m_vbl_disable)
+ {
+ card->raise_slot_irq();
+ }
+
+ for (y = 0; y < 768; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 1024/8; x++)
+ {
+ pixels = card->m_vram[(y * 128) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[(pixels>>7)&1];
+ *scanline++ = card->m_palette[(pixels>>6)&1];
+ *scanline++ = card->m_palette[(pixels>>5)&1];
+ *scanline++ = card->m_palette[(pixels>>4)&1];
+ *scanline++ = card->m_palette[(pixels>>3)&1];
+ *scanline++ = card->m_palette[(pixels>>2)&1];
+ *scanline++ = card->m_palette[(pixels>>1)&1];
+ *scanline++ = card->m_palette[(pixels&1)];
+ }
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_vikbw_device::viking_ack_w )
+{
+ lower_slot_irq();
+}
+
+READ32_MEMBER( nubus_vikbw_device::viking_ack_r )
+{
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_vikbw_device::viking_disable_w )
+{
+ m_vbl_disable = 1;
+}
+
+READ32_MEMBER( nubus_vikbw_device::viking_enable_r )
+{
+ m_vbl_disable = 0;
+ return 0;
+}
+
diff --git a/src/mess/video/nubus_vikbw.h b/src/mess/video/nubus_vikbw.h
new file mode 100644
index 00000000000..f7e77146a70
--- /dev/null
+++ b/src/mess/video/nubus_vikbw.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifndef __NUBUS_VIKBW_H__
+#define __NUBUS_VIKBW_H__
+
+#include "emu.h"
+#include "machine/nubus.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> nubus_vikbw_device
+
+class nubus_vikbw_device :
+ public device_t,
+ public device_nubus_card_interface
+{
+public:
+ // construction/destruction
+ nubus_vikbw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ nubus_vikbw_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ DECLARE_READ32_MEMBER(viking_ack_r);
+ DECLARE_WRITE32_MEMBER(viking_ack_w);
+ DECLARE_READ32_MEMBER(viking_enable_r);
+ DECLARE_WRITE32_MEMBER(viking_disable_w);
+
+public:
+ UINT8 *m_vram;
+ UINT32 m_vbl_disable, m_palette[2];
+};
+
+
+// device type definition
+extern const device_type NUBUS_VIKBW;
+
+#endif /* __NUBUS_VIKBW_H__ */
+
diff --git a/src/mess/video/nubus_wsportrait.c b/src/mess/video/nubus_wsportrait.c
new file mode 100644
index 00000000000..fae910c67fe
--- /dev/null
+++ b/src/mess/video/nubus_wsportrait.c
@@ -0,0 +1,316 @@
+/***************************************************************************
+
+ Apple model 820-5037-C "Macintosh II Portrait Video Card"
+ PCB is marked "Workstation/Portrait Card"
+ 640x870, 1, 2 or 4bpp grayscale
+
+ Fs0900e0 = DAC control
+ Fs0900e4 = DAC data
+ Fs0A0000 = enable / ack VBL IRQ
+ Fs0A0004 = disable VBL IRQ
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/nubus_wsportrait.h"
+
+#define WSPORTRAIT_SCREEN_NAME "wsport_screen"
+#define WSPORTRAIT_ROM_REGION "wsport_rom"
+
+#define VRAM_SIZE (0x80000) // 512k max
+
+static SCREEN_UPDATE_RGB32( wsportrait );
+
+MACHINE_CONFIG_FRAGMENT( wsportrait )
+ MCFG_SCREEN_ADD( WSPORTRAIT_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_UPDATE_STATIC(wsportrait)
+ MCFG_SCREEN_SIZE(1024,960)
+ MCFG_SCREEN_REFRESH_RATE(75.0)
+ MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 870-1)
+MACHINE_CONFIG_END
+
+ROM_START( wsportrait )
+ ROM_REGION(0x1000, WSPORTRAIT_ROM_REGION, 0)
+ ROM_LOAD( "341-0732.bin", 0x000000, 0x001000, CRC(ddc35b78) SHA1(ce2bf2374bb994c17962dba8f3d11bc1260e2644) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_WSPORTRAIT = &device_creator<nubus_wsportrait_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nubus_wsportrait_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( wsportrait );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *nubus_wsportrait_device::device_rom_region() const
+{
+ return ROM_NAME( wsportrait );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nubus_wsportrait_device - constructor
+//-------------------------------------------------
+
+nubus_wsportrait_device::nubus_wsportrait_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NUBUS_WSPORTRAIT, "Macintosh II Portrait Video Card", tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_wspt";
+}
+
+nubus_wsportrait_device::nubus_wsportrait_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_nubus_card_interface(mconfig, *this)
+{
+ m_shortname = "nb_wspt";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_wsportrait_device::device_start()
+{
+ UINT32 slotspace;
+
+ // set_nubus_device makes m_slot valid
+ set_nubus_device();
+ install_declaration_rom(this, WSPORTRAIT_ROM_REGION, true);
+
+ slotspace = get_slotspace();
+
+ printf("[wsportrait %p] slotspace = %x\n", this, slotspace);
+
+ m_vram = auto_alloc_array(machine(), UINT8, VRAM_SIZE);
+ m_vram32 = (UINT32 *)m_vram;
+
+ m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_wsportrait_device::vram_r), this), write32_delegate(FUNC(nubus_wsportrait_device::vram_w), this));
+ m_nubus->install_device(slotspace+0x900000, slotspace+0x900000+VRAM_SIZE-1, read32_delegate(FUNC(nubus_wsportrait_device::vram_r), this), write32_delegate(FUNC(nubus_wsportrait_device::vram_w), this));
+ m_nubus->install_device(slotspace+0x80000, slotspace+0xeffff, read32_delegate(FUNC(nubus_wsportrait_device::wsportrait_r), this), write32_delegate(FUNC(nubus_wsportrait_device::wsportrait_w), this));
+
+ m_timer = timer_alloc(0, NULL);
+ m_screen = NULL; // can we look this up now?
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void nubus_wsportrait_device::device_reset()
+{
+ m_count = 0;
+ m_clutoffs = 0;
+ m_vbl_disable = 1;
+ m_mode = 0;
+ memset(m_vram, 0, VRAM_SIZE);
+ memset(m_palette, 0, sizeof(m_palette));
+}
+
+
+void nubus_wsportrait_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+ if (!m_vbl_disable)
+ {
+ raise_slot_irq();
+ }
+
+ m_timer->adjust(m_screen->time_until_pos(869, 0), 0);
+}
+
+/***************************************************************************
+
+ Workstation/Portrait emulation
+
+***************************************************************************/
+
+static SCREEN_UPDATE_RGB32( wsportrait )
+{
+ UINT32 *scanline;
+ int x, y;
+ nubus_wsportrait_device *card = downcast<nubus_wsportrait_device *>(screen.owner());
+ UINT8 pixels, *vram;
+
+ // first time? kick off the VBL timer
+ if (!card->m_screen)
+ {
+ card->m_screen = &screen;
+ card->m_timer->adjust(card->m_screen->time_until_pos(869, 0), 0);
+ }
+
+ vram = card->m_vram + 0x80;
+
+ switch (card->m_mode)
+ {
+ case 0: // 1 bpp?
+ for (y = 0; y < 870; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640/8; x++)
+ {
+ pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[((pixels>>7)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>6)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>5)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>4)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>3)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>2)&0x1)];
+ *scanline++ = card->m_palette[((pixels>>1)&0x1)];
+ *scanline++ = card->m_palette[(pixels&1)];
+ }
+ }
+ break;
+
+ case 1: // 2 bpp
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+ for (x = 0; x < 640/4; x++)
+ {
+ pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[((pixels>>6)&3)];
+ *scanline++ = card->m_palette[((pixels>>4)&3)];
+ *scanline++ = card->m_palette[((pixels>>2)&3)];
+ *scanline++ = card->m_palette[(pixels&3)];
+ }
+ }
+ break;
+
+ case 2: // 4 bpp
+ for (y = 0; y < 480; y++)
+ {
+ scanline = &bitmap.pix32(y);
+
+ for (x = 0; x < 640/2; x++)
+ {
+ pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = card->m_palette[((pixels&0xf0)>>4)];
+ *scanline++ = card->m_palette[(pixels&0xf)];
+ }
+ }
+ break;
+
+ default:
+ fatalerror("wsportrait: unknown video mode %d", card->m_mode);
+ break;
+
+ }
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_wsportrait_device::wsportrait_w )
+{
+ data ^= 0xffffffff;
+// if (offset != 0x8000) printf("wsportrait: Write %08x @ %x, mask %08x\n", data, offset, mem_mask);
+
+ switch (offset)
+ {
+ case 1: // mode control
+// printf("%08x to mode 1\n", data);
+ switch (data & 0xff000000)
+ {
+ case 0x20000000:
+ case 0x24000000:
+ m_mode = 0;
+ break;
+
+ case 0x40000000:
+ m_mode = 1;
+ break;
+
+ case 0x50000000:
+ case 0x80000000:
+ m_mode = 2;
+ break;
+ }
+ break;
+
+ case 0x4038: // DAC control
+ m_clutoffs = (data>>24)&0xff;
+ break;
+
+ case 0x4039: // DAC data - only 4 bits per component!
+ m_colors[m_count] = (data>>24) & 0x0f;
+ m_colors[m_count] |= (m_colors[m_count]<<4);
+ m_count++;
+
+ if (m_count == 3)
+ {
+// printf("RAMDAC: color %d = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], cpu_get_pc(&space.device()) );
+ m_palette[m_clutoffs] = MAKE_RGB(m_colors[2], m_colors[2], m_colors[2]);
+ m_clutoffs++;
+ if (m_clutoffs > 255)
+ {
+ m_clutoffs = 0;
+ }
+ m_count = 0;
+ }
+ break;
+
+ case 0x8000:
+ lower_slot_irq();
+ m_vbl_disable = false;
+ break;
+
+ case 0x8001:
+ m_vbl_disable = true;
+ break;
+ }
+}
+
+READ32_MEMBER( nubus_wsportrait_device::wsportrait_r )
+{
+// printf("wsportrait: Read @ %x, mask %08x\n", offset, mem_mask);
+
+ /*
+ monitor types
+
+ 0x0 = invalid
+ 0x2 = invalid
+ 0x4 = color: 640x870 1bpp, 640x480 2bpp and 4bpp
+ 0x6 = 1bpp 640x384? and sets weird mode controls
+ 0x8 = really odd (bitplaned?)
+ 0xa = invalid
+ 0xc = 640x480 grayscale
+ 0xe = same as 0x6
+ */
+
+ switch (offset)
+ {
+ case 0x4004:
+ m_toggle ^= 0x00010000;
+ return m_toggle | 0xfffc0000; // bit 0 = vbl status, bits 1-3 = monitor type
+ break;
+ }
+ return 0;
+}
+
+WRITE32_MEMBER( nubus_wsportrait_device::vram_w )
+{
+ data ^= 0xffffffff;
+ COMBINE_DATA(&m_vram32[offset]);
+}
+
+READ32_MEMBER( nubus_wsportrait_device::vram_r )
+{
+ return m_vram32[offset] ^ 0xffffffff;
+}
diff --git a/src/mess/video/nubus_wsportrait.h b/src/mess/video/nubus_wsportrait.h
new file mode 100644
index 00000000000..0b0c62e8c3b
--- /dev/null
+++ b/src/mess/video/nubus_wsportrait.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#ifndef __NUBUS_WSPORTRAIT_H__
+#define __NUBUS_WSPORTRAIT_H__
+
+#include "emu.h"
+#include "machine/nubus.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> nubus_wsportrait_device
+
+class nubus_wsportrait_device :
+ public device_t,
+ public device_nubus_card_interface
+{
+public:
+ // construction/destruction
+ nubus_wsportrait_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ nubus_wsportrait_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ DECLARE_READ32_MEMBER(wsportrait_r);
+ DECLARE_WRITE32_MEMBER(wsportrait_w);
+ DECLARE_READ32_MEMBER(vram_r);
+ DECLARE_WRITE32_MEMBER(vram_w);
+
+public:
+ UINT8 *m_vram;
+ UINT32 *m_vram32;
+ UINT32 m_mode, m_vbl_disable, m_toggle;
+ UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs;
+ screen_device *m_screen;
+ emu_timer *m_timer;
+};
+
+
+// device type definition
+extern const device_type NUBUS_WSPORTRAIT;
+
+#endif /* __NUBUS_M2HIRES_H__ */
diff --git a/src/mess/video/odyssey2.c b/src/mess/video/odyssey2.c
new file mode 100644
index 00000000000..f166ac37b60
--- /dev/null
+++ b/src/mess/video/odyssey2.c
@@ -0,0 +1,827 @@
+/***************************************************************************
+
+ video/odyssey2.c
+
+ 2012-02-04 DanBoris
+ - Changed color of background grid color 0 to match sprite color 0 (Fixes KTAA title screen)
+ - Fixed Odyssey2_video_w so that m_o2_vdc.reg[] is always updated (Fixes Blockout)
+ - Changed quad character generation so character height is always taken from 4th character (KTAA level 2)
+
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/odyssey2.h"
+
+
+#define COLLISION_SPRITE_0 0x01
+#define COLLISION_SPRITE_1 0x02
+#define COLLISION_SPRITE_2 0x04
+#define COLLISION_SPRITE_3 0x08
+#define COLLISION_VERTICAL_GRID 0x10
+#define COLLISION_HORIZ_GRID_DOTS 0x20
+#define COLLISION_EXTERNAL_UNUSED 0x40
+#define COLLISION_CHARACTERS 0x80
+
+/* character sprite colors
+ dark grey, red, green, orange, blue, violet, light grey, white
+ dark back / grid colors
+ black, dark blue, dark green, light green, red, violet, orange, light grey
+ light back / grid colors
+ black, blue, green, light green, red, violet, orange, light grey */
+
+const UINT8 odyssey2_colors[] =
+{
+ /* Background,Grid Dim */
+ 0x00,0x00,0x00,
+ 0x00,0x00,0xFF, /* Blue */
+ 0x00,0x80,0x00, /* DK Green */
+ 0xff,0x9b,0x60,
+ 0xCC,0x00,0x00, /* Red */
+ 0xa9,0x80,0xff,
+ 0x82,0xfd,0xdb,
+ 0xFF,0xFF,0xFF,
+
+ /* Background,Grid Bright */
+ 0x80,0x80,0x80,
+ 0x50,0xAE,0xFF, /* Blue */
+ 0x00,0xFF,0x00, /* Dk Green */
+ 0x82,0xfb,0xdb, /* Lt Grey */
+ 0xEC,0x02,0x60, /* Red */
+ 0xa9,0x80,0xff, /* Violet */
+ 0xff,0x9b,0x60, /* Orange */
+ 0xFF,0xFF,0xFF,
+
+ /* Character,Sprite colors */
+ 0x80,0x80,0x80, /* Dark Grey */
+ 0xFF,0x80,0x80, /* Red */
+ 0x00,0xC0,0x00, /* Green */
+ 0xff,0x9b,0x60, /* Orange */
+ 0x50,0xAE,0xFF, /* Blue */
+ 0xa9,0x80,0xff, /* Violet */
+ 0x82,0xfb,0xdb, /* Lt Grey */
+ 0xff,0xff,0xff /* White */
+};
+
+static const UINT8 o2_shape[0x40][8]={
+ { 0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00 }, // 0
+ { 0x18,0x38,0x18,0x18,0x18,0x18,0x3C,0x00 },
+ { 0x3C,0x66,0x0C,0x18,0x30,0x60,0x7E,0x00 },
+ { 0x7C,0xC6,0x06,0x3C,0x06,0xC6,0x7C,0x00 },
+ { 0xCC,0xCC,0xCC,0xFE,0x0C,0x0C,0x0C,0x00 },
+ { 0xFE,0xC0,0xC0,0x7C,0x06,0xC6,0x7C,0x00 },
+ { 0x7C,0xC6,0xC0,0xFC,0xC6,0xC6,0x7C,0x00 },
+ { 0xFE,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00 },
+ { 0x7C,0xC6,0xC6,0x7C,0xC6,0xC6,0x7C,0x00 },
+ { 0x7C,0xC6,0xC6,0x7E,0x06,0xC6,0x7C,0x00 },
+ { 0x00,0x18,0x18,0x00,0x18,0x18,0x00,0x00 },
+ { 0x18,0x7E,0x58,0x7E,0x1A,0x7E,0x18,0x00 },
+ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
+ { 0x3C,0x66,0x0C,0x18,0x18,0x00,0x18,0x00 },
+ { 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFE,0x00 },
+ { 0xFC,0xC6,0xC6,0xFC,0xC0,0xC0,0xC0,0x00 },
+ { 0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00 },
+ { 0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00 },
+ { 0xFE,0xC0,0xC0,0xF8,0xC0,0xC0,0xFE,0x00 },
+ { 0xFC,0xC6,0xC6,0xFC,0xD8,0xCC,0xC6,0x00 },
+ { 0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00 },
+ { 0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00 },
+ { 0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00 },
+ { 0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00 },
+ { 0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x76,0x00 },
+ { 0x7C,0xC6,0xC0,0x7C,0x06,0xC6,0x7C,0x00 },
+ { 0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0xFC,0x00 },
+ { 0xFE,0xC0,0xC0,0xF8,0xC0,0xC0,0xC0,0x00 },
+ { 0x7C,0xC6,0xC0,0xC0,0xCE,0xC6,0x7E,0x00 },
+ { 0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00 },
+ { 0x06,0x06,0x06,0x06,0x06,0xC6,0x7C,0x00 },
+ { 0xC6,0xCC,0xD8,0xF0,0xD8,0xCC,0xC6,0x00 },
+ { 0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00 },
+ { 0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00 },
+ { 0xC6,0xC6,0x6C,0x38,0x6C,0xC6,0xC6,0x00 },
+ { 0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00 },
+ { 0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00 },
+ { 0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00 },
+ { 0xC6,0xEE,0xFE,0xD6,0xC6,0xC6,0xC6,0x00 },
+ { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00 },
+ { 0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00 },
+ { 0x00,0x66,0x3C,0x18,0x3C,0x66,0x00,0x00 },
+ { 0x00,0x18,0x00,0x7E,0x00,0x18,0x00,0x00 },
+ { 0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00 },
+ { 0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00 },
+ { 0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00 },
+ { 0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00 },
+ { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00 },
+ { 0xCE,0xDB,0xDB,0xDB,0xDB,0xDB,0xCE,0x00 },
+ { 0x00,0x00,0x3C,0x7E,0x7E,0x7E,0x3C,0x00 },
+ { 0x1C,0x1C,0x18,0x1E,0x18,0x18,0x1C,0x00 },
+ { 0x1C,0x1C,0x18,0x1E,0x18,0x34,0x26,0x00 },
+ { 0x38,0x38,0x18,0x78,0x18,0x2C,0x64,0x00 },
+ { 0x38,0x38,0x18,0x78,0x18,0x18,0x38,0x00 },
+ { 0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00 },
+ { 0x18,0x3C,0x7E,0xFF,0xFF,0x18,0x18,0x00 },
+ { 0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF,0x00 },
+ { 0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF,0x00 },
+ { 0x38,0x38,0x12,0xFE,0xB8,0x28,0x6C,0x00 },
+ { 0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x00 },
+ { 0x00,0x00,0x0C,0x08,0x08,0x7F,0x3E,0x00 },
+ { 0x00,0x03,0x63,0xFF,0xFF,0x18,0x08,0x00 },
+ { 0x00,0x00,0x00,0x10,0x38,0xFF,0x7E,0x00 }
+};
+
+
+
+
+PALETTE_INIT( odyssey2 )
+{
+ int i;
+
+ for ( i = 0; i < 24; i++ )
+ {
+ palette_set_color_rgb( machine, i, odyssey2_colors[i*3], odyssey2_colors[i*3+1], odyssey2_colors[i*3+2] );
+ }
+}
+
+READ8_MEMBER(odyssey2_state::odyssey2_video_r)
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case 0xa1:
+ data = m_control_status;
+ m_iff = 0;
+ cputag_set_input_line(machine(), "maincpu", 0, CLEAR_LINE);
+ m_control_status &= ~ 0x08;
+ if ( machine().primary_screen->hpos() < I824X_START_ACTIVE_SCAN || machine().primary_screen->hpos() > I824X_END_ACTIVE_SCAN )
+ {
+ data |= 1;
+ }
+
+ break;
+
+ case 0xa2:
+ data = m_collision_status;
+ m_collision_status = 0;
+
+ break;
+
+ case 0xa4:
+
+ if ((m_o2_vdc.s.control & VDC_CONTROL_REG_STROBE_XY))
+ m_y_beam_pos = machine().primary_screen->vpos() - m_start_vpos;
+
+ data = m_y_beam_pos;
+
+ break;
+
+
+ case 0xa5:
+
+ if ((m_o2_vdc.s.control & VDC_CONTROL_REG_STROBE_XY))
+ {
+ m_x_beam_pos = machine().primary_screen->hpos();
+ if ( m_x_beam_pos < I824X_START_ACTIVE_SCAN )
+ {
+ m_x_beam_pos = m_x_beam_pos - I824X_START_ACTIVE_SCAN + I824X_LINE_CLOCKS;
+ }
+ else
+ {
+ m_x_beam_pos = m_x_beam_pos - I824X_START_ACTIVE_SCAN;
+ }
+ }
+
+ data = m_x_beam_pos;
+
+ break;
+
+ default:
+ data = m_o2_vdc.reg[offset];
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER(odyssey2_state::odyssey2_video_w)
+{
+ /* Update the sound */
+ if( offset >= 0xa7 && offset <= 0xaa )
+ m_sh_channel->update();
+
+ if (offset == 0xa0) {
+
+
+ if ( m_o2_vdc.s.control & VDC_CONTROL_REG_STROBE_XY
+ && !(data & VDC_CONTROL_REG_STROBE_XY))
+ {
+ /* Toggling strobe bit, tuck away values */
+ m_x_beam_pos = machine().primary_screen->hpos();
+ if ( m_x_beam_pos < I824X_START_ACTIVE_SCAN )
+ {
+ m_x_beam_pos = m_x_beam_pos - I824X_START_ACTIVE_SCAN + 228;
+ }
+ else
+ {
+ m_x_beam_pos = m_x_beam_pos - I824X_START_ACTIVE_SCAN;
+ }
+
+ m_y_beam_pos = machine().primary_screen->vpos() - m_start_vpos;
+ }
+ }
+
+ m_o2_vdc.reg[offset] = data;
+}
+
+WRITE8_MEMBER(odyssey2_state::odyssey2_lum_w)
+{
+ m_lum = data;
+}
+
+READ8_MEMBER(odyssey2_state::odyssey2_t1_r)
+{
+ if ( machine().primary_screen->vpos() > m_start_vpos && machine().primary_screen->vpos() < m_start_vblank )
+ {
+ if ( machine().primary_screen->hpos() >= I824X_START_ACTIVE_SCAN && machine().primary_screen->hpos() < I824X_END_ACTIVE_SCAN )
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static TIMER_CALLBACK( i824x_scanline_callback )
+{
+ odyssey2_state *state = machine.driver_data<odyssey2_state>();
+ UINT8 collision_map[160];
+ int vpos = machine.primary_screen->vpos();
+
+ if ( vpos < state->m_start_vpos )
+ return;
+
+ if ( vpos == state->m_start_vpos )
+ {
+ state->m_control_status &= ~0x08;
+ }
+
+ if ( vpos < state->m_start_vblank )
+ {
+ rectangle rect;
+ //static const int sprite_width[4] = { 8, 8, 8, 8 };
+ int i;
+
+ state->m_control_status &= ~ 0x01;
+
+ /* Draw a line */
+ rect.set(I824X_START_ACTIVE_SCAN, I824X_END_ACTIVE_SCAN - 1, vpos, vpos);
+ state->m_tmp_bitmap.fill(( (state->m_o2_vdc.s.color >> 3) & 0x7 ) | ( ( state->m_lum << 3 ) ^ 0x08 ), rect );
+
+ /* Clear collision map */
+ memset( collision_map, 0, sizeof( collision_map ) );
+
+ /* Display grid if enabled */
+ if ( state->m_o2_vdc.s.control & 0x08 )
+ {
+ UINT16 color = ( state->m_o2_vdc.s.color & 7 ) | ( ( state->m_o2_vdc.s.color >> 3 ) & 0x08 ) | ( ( state->m_lum << 3 ) ^ 0x08 );
+ int x_grid_offset = 8;
+ int y_grid_offset = 24;
+ int width = 16;
+ int height = 24;
+ int w = ( state->m_o2_vdc.s.control & 0x80 ) ? width : 2;
+ int j, k, y;
+
+ /* Draw horizontal part of grid */
+ for ( j = 1, y = 0; y < 9; y++, j <<= 1 )
+ {
+ if ( y_grid_offset + y * height <= ( vpos - state->m_start_vpos ) && ( vpos - state->m_start_vpos ) < y_grid_offset + y * height + 3 )
+ {
+ for ( i = 0; i < 9; i++ )
+ {
+ if ( ( state->m_o2_vdc.s.hgrid[0][i] & j ) || ( state->m_o2_vdc.s.hgrid[1][i] & ( j >> 8 ) ) )
+ {
+ for ( k = 0; k < width + 2; k++ )
+ {
+ int px = x_grid_offset + i * width + k;
+ collision_map[ px ] |= COLLISION_HORIZ_GRID_DOTS;
+ state->m_tmp_bitmap.pix16(vpos, I824X_START_ACTIVE_SCAN + px ) = color;
+ }
+ }
+ }
+ }
+ }
+
+ /* Draw vertical part of grid */
+ for( j = 1, y = 0; y < 8; y++, j <<= 1 )
+ {
+ if ( y_grid_offset + y * height <= ( vpos - state->m_start_vpos ) && ( vpos - state->m_start_vpos ) < y_grid_offset + ( y + 1 ) * height )
+ {
+ for ( i = 0; i < 10; i++ )
+ {
+ if ( state->m_o2_vdc.s.vgrid[i] & j )
+ {
+ for ( k = 0; k < w; k++ )
+ {
+ int px = x_grid_offset + i * width + k;
+
+ /* Check if we collide with an already drawn source object */
+ if ( collision_map[ px ] & state->m_o2_vdc.s.collision )
+ {
+ state->m_collision_status |= COLLISION_VERTICAL_GRID;
+ }
+ /* Check if an already drawn object would collide with us */
+ if ( COLLISION_VERTICAL_GRID & state->m_o2_vdc.s.collision && collision_map[ px ] )
+ {
+ state->m_collision_status |= collision_map[ px ];
+ }
+ collision_map[ px ] |= COLLISION_VERTICAL_GRID;
+ state->m_tmp_bitmap.pix16(vpos, I824X_START_ACTIVE_SCAN + px ) = color;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Display objects if enabled */
+ if ( state->m_o2_vdc.s.control & 0x20 )
+ {
+ /* Regular foreground objects */
+ for ( i = 0; i < ARRAY_LENGTH( state->m_o2_vdc.s.foreground ); i++ )
+ {
+ int y = state->m_o2_vdc.s.foreground[i].y;
+ int height = 8 - ( ( ( y >> 1 ) + state->m_o2_vdc.s.foreground[i].ptr ) & 7 );
+
+ if ( y <= ( vpos - state->m_start_vpos ) && ( vpos - state->m_start_vpos ) < y + height * 2 )
+ {
+ UINT16 color = 16 + ( ( state->m_o2_vdc.s.foreground[i].color & 0x0E ) >> 1 );
+ int offset = ( state->m_o2_vdc.s.foreground[i].ptr | ( ( state->m_o2_vdc.s.foreground[i].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( vpos - state->m_start_vpos - y ) >> 1 );
+ UINT8 chr = ((char*)o2_shape)[ offset & 0x1FF ];
+ int x = state->m_o2_vdc.s.foreground[i].x;
+ UINT8 m;
+
+ for ( m = 0x80; m > 0; m >>= 1, x++ )
+ {
+ if ( chr & m )
+ {
+ if ( x >= 0 && x < 160 )
+ {
+ /* Check if we collide with an already drawn source object */
+ if ( collision_map[ x ] & state->m_o2_vdc.s.collision )
+ {
+ state->m_collision_status |= COLLISION_CHARACTERS;
+ }
+ /* Check if an already drawn object would collide with us */
+ if ( COLLISION_CHARACTERS & state->m_o2_vdc.s.collision && collision_map[ x ] )
+ {
+ state->m_collision_status |= collision_map[ x ];
+ }
+ collision_map[ x ] |= COLLISION_CHARACTERS;
+ state->m_tmp_bitmap.pix16(vpos, I824X_START_ACTIVE_SCAN + x ) = color;
+ }
+ }
+ }
+ }
+ }
+
+ /* Quad objects */
+ for ( i = 0; i < ARRAY_LENGTH( state->m_o2_vdc.s.quad ); i++ )
+ {
+ int y = state->m_o2_vdc.s.quad[i].single[0].y;
+ int height = 8;
+
+ if ( y <= ( vpos - state->m_start_vpos ) && ( vpos - state->m_start_vpos ) < y + height * 2 )
+ {
+ int x = state->m_o2_vdc.s.quad[i].single[0].x;
+ int j;
+
+ // Charaecter height is always determined by the height of the 4th character
+ int char_height = 8 - ( ( ( y >> 1 ) + state->m_o2_vdc.s.quad[i].single[3].ptr ) & 7 );
+
+ for ( j = 0; j < ARRAY_LENGTH( state->m_o2_vdc.s.quad[0].single ); j++, x += 8 )
+ {
+
+
+ if ( y <= ( vpos - state->m_start_vpos ) && ( vpos - state->m_start_vpos ) < y + char_height * 2 )
+ {
+
+ UINT16 color = 16 + ( ( state->m_o2_vdc.s.quad[i].single[j].color & 0x0E ) >> 1 );
+
+
+ int offset = ( state->m_o2_vdc.s.quad[i].single[j].ptr | ( ( state->m_o2_vdc.s.quad[i].single[j].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( vpos - state->m_start_vpos - y ) >> 1 );
+
+ UINT8 chr = ((char*)o2_shape)[ offset & 0x1FF ];
+
+ UINT8 m;
+ for ( m = 0x80; m > 0; m >>= 1, x++ )
+ {
+ if ( chr & m )
+ {
+ if ( x >= 0 && x < 160 )
+ {
+ /* Check if we collide with an already drawn source object */
+ if ( collision_map[ x ] & state->m_o2_vdc.s.collision )
+ {
+ state->m_collision_status |= COLLISION_CHARACTERS;
+ }
+ /* Check if an already drawn object would collide with us */
+ if ( COLLISION_CHARACTERS & state->m_o2_vdc.s.collision && collision_map[ x ] )
+ {
+ state->m_collision_status |= collision_map[ x ];
+ }
+ collision_map[ x ] |= COLLISION_CHARACTERS;
+ state->m_tmp_bitmap.pix16(vpos, I824X_START_ACTIVE_SCAN + x ) = color;
+ }
+ }
+ }
+ }
+ else
+ {
+ x += 8;
+ }
+ }
+ }
+ }
+
+ /* Sprites */
+ for ( i = 0; i < ARRAY_LENGTH( state->m_o2_vdc.s.sprites ); i++ )
+ {
+ int y = state->m_o2_vdc.s.sprites[i].y;
+ int height = 8;
+ if ( state->m_o2_vdc.s.sprites[i].color & 4 )
+ {
+ /* Zoomed sprite */
+ //sprite_width[i] = 16;
+ if ( y <= ( vpos - state->m_start_vpos ) && ( vpos - state->m_start_vpos ) < y + height * 4 )
+ {
+ UINT16 color = 16 + ( ( state->m_o2_vdc.s.sprites[i].color >> 3 ) & 0x07 );
+ UINT8 chr = state->m_o2_vdc.s.shape[i][ ( ( vpos - state->m_start_vpos - y ) >> 2 ) ];
+ int x = state->m_o2_vdc.s.sprites[i].x;
+ UINT8 m;
+
+ for ( m = 0x01; m > 0; m <<= 1, x += 2 )
+ {
+ if ( chr & m )
+ {
+ if ( x >= 0 && x < 160 )
+ {
+ /* Check if we collide with an already drawn source object */
+ if ( collision_map[ x ] & state->m_o2_vdc.s.collision )
+ {
+ state->m_collision_status |= ( 1 << i );
+ }
+ /* Check if an already drawn object would collide with us */
+ if ( ( 1 << i ) & state->m_o2_vdc.s.collision && collision_map[ x ] )
+ {
+ state->m_collision_status |= collision_map[ x ];
+ }
+ collision_map[ x ] |= ( 1 << i );
+ state->m_tmp_bitmap.pix16(vpos, I824X_START_ACTIVE_SCAN + x ) = color;
+ }
+ if ( x >= -1 && x < 159 )
+ {
+ /* Check if we collide with an already drawn source object */
+ if ( collision_map[ x ] & state->m_o2_vdc.s.collision )
+ {
+ state->m_collision_status |= ( 1 << i );
+ }
+ /* Check if an already drawn object would collide with us */
+ if ( ( 1 << i ) & state->m_o2_vdc.s.collision && collision_map[ x ] )
+ {
+ state->m_collision_status |= collision_map[ x ];
+ }
+ collision_map[ x ] |= ( 1 << i );
+ state->m_tmp_bitmap.pix16(vpos, I824X_START_ACTIVE_SCAN + x + 1 ) = color;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Regular sprite */
+ if ( y <= ( vpos - state->m_start_vpos ) && ( vpos - state->m_start_vpos ) < y + height * 2 )
+ {
+ UINT16 color = 16 + ( ( state->m_o2_vdc.s.sprites[i].color >> 3 ) & 0x07 );
+ UINT8 chr = state->m_o2_vdc.s.shape[i][ ( ( vpos - state->m_start_vpos - y ) >> 1 ) ];
+ int x = state->m_o2_vdc.s.sprites[i].x;
+ UINT8 m;
+
+ for ( m = 0x01; m > 0; m <<= 1, x++ )
+ {
+ if ( chr & m )
+ {
+ if ( x >= 0 && x < 160 )
+ {
+ /* Check if we collide with an already drawn source object */
+ if ( collision_map[ x ] & state->m_o2_vdc.s.collision )
+ {
+ state->m_collision_status |= ( 1 << i );
+ }
+ /* Check if an already drawn object would collide with us */
+ if ( ( 1 << i ) & state->m_o2_vdc.s.collision && collision_map[ x ] )
+ {
+ state->m_collision_status |= collision_map[ x ];
+ }
+ collision_map[ x ] |= ( 1 << i );
+ state->m_tmp_bitmap.pix16(vpos, I824X_START_ACTIVE_SCAN + x ) = color;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Check for start of VBlank */
+ if ( vpos == state->m_start_vblank )
+ {
+ state->m_control_status |= 0x08;
+ if ( ! state->m_iff )
+ {
+ cputag_set_input_line(machine, "maincpu", 0, ASSERT_LINE);
+ state->m_iff = 1;
+ }
+ }
+}
+
+static TIMER_CALLBACK( i824x_hblank_callback )
+{
+ odyssey2_state *state = machine.driver_data<odyssey2_state>();
+ int vpos = machine.primary_screen->vpos();
+
+ if ( vpos < state->m_start_vpos - 1 )
+ return;
+
+ if ( vpos < state->m_start_vblank - 1 )
+ {
+ state->m_control_status |= 0x01;
+ }
+}
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+VIDEO_START( odyssey2 )
+{
+ odyssey2_state *state = machine.driver_data<odyssey2_state>();
+ screen_device *screen = machine.first_screen();
+
+ memset(state->m_o2_vdc.reg, 0, 0x100);
+
+ state->m_o2_snd_shift[0] = state->m_o2_snd_shift[1] = 0;
+ state->m_x_beam_pos = 0;
+ state->m_y_beam_pos = 0;
+ state->m_control_status = 0;
+ state->m_collision_status = 0;
+ state->m_iff = 0;
+ state->m_start_vpos = 0;
+ state->m_start_vblank = 0;
+ state->m_lum = 0;
+
+ state->m_o2_snd_shift[0] = machine.sample_rate() / 983;
+ state->m_o2_snd_shift[1] = machine.sample_rate() / 3933;
+
+ state->m_start_vpos = I824X_START_Y;
+ state->m_start_vblank = I824X_START_Y + I824X_SCREEN_HEIGHT;
+ state->m_control_status = 0;
+ state->m_iff = 0;
+
+ screen->register_screen_bitmap(state->m_tmp_bitmap);
+
+ state->m_i824x_line_timer = machine.scheduler().timer_alloc(FUNC(i824x_scanline_callback));
+ state->m_i824x_line_timer->adjust( machine.primary_screen->time_until_pos(1, I824X_START_ACTIVE_SCAN ), 0, machine.primary_screen->scan_period() );
+
+ state->m_i824x_hblank_timer = machine.scheduler().timer_alloc(FUNC(i824x_hblank_callback));
+ state->m_i824x_hblank_timer->adjust( machine.primary_screen->time_until_pos(1, I824X_END_ACTIVE_SCAN + 18 ), 0, machine.primary_screen->scan_period() );
+}
+
+/***************************************************************************
+
+ Refresh the video screen
+
+***************************************************************************/
+
+SCREEN_UPDATE_IND16( odyssey2 )
+{
+ odyssey2_state *state = screen.machine().driver_data<odyssey2_state>();
+ copybitmap( bitmap, state->m_tmp_bitmap, 0, 0, 0, 0, cliprect );
+
+ return 0;
+}
+
+static DEVICE_START( odyssey2_sound )
+{
+ odyssey2_state *state = device->machine().driver_data<odyssey2_state>();
+ state->m_sh_channel = device->machine().sound().stream_alloc(*device, 0, 1, device->clock()/(I824X_LINE_CLOCKS*4), 0, odyssey2_sh_update );
+}
+
+
+DEVICE_GET_INFO( odyssey2_sound )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(odyssey2_sound); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "P8244/P8245"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ }
+}
+
+STREAM_UPDATE( odyssey2_sh_update )
+{
+ odyssey2_state *state = device->machine().driver_data<odyssey2_state>();
+ UINT32 old_signal, signal;
+ int ii;
+ int period;
+ stream_sample_t *buffer = outputs[0];
+
+ /* Generate the signal */
+ old_signal = signal = state->m_o2_vdc.s.shift3 | (state->m_o2_vdc.s.shift2 << 8) | (state->m_o2_vdc.s.shift1 << 16);
+
+ if( state->m_o2_vdc.s.sound & 0x80 ) /* Sound is enabled */
+ {
+ for( ii = 0; ii < samples; ii++, buffer++ )
+ {
+ *buffer = 0;
+ *buffer = signal & 0x1;
+ period = (state->m_o2_vdc.s.sound & 0x20) ? 1 : 4;
+ if( ++state->m_sh_count >= period )
+ {
+ state->m_sh_count = 0;
+ signal >>= 1;
+ /* Loop sound */
+ signal |= *buffer << 23;
+ /* Check if noise should be applied */
+ if ( state->m_o2_vdc.s.sound & 0x10 )
+ {
+ /* Noise tap is on bits 0 and 5 and fed back to bits 15 (and 23!) */
+ UINT32 new_bit = ( ( old_signal ) ^ ( old_signal >> 5 ) ) & 0x01;
+ signal = ( old_signal & 0xFF0000 ) | ( ( old_signal & 0xFFFF ) >> 1 ) | ( new_bit << 15 ) | ( new_bit << 23 );
+ }
+ state->m_o2_vdc.s.shift3 = signal & 0xFF;
+ state->m_o2_vdc.s.shift2 = ( signal >> 8 ) & 0xFF;
+ state->m_o2_vdc.s.shift1 = ( signal >> 16 ) & 0xFF;
+ old_signal = signal;
+ }
+
+ /* Throw an interrupt if enabled */
+ if( state->m_o2_vdc.s.control & 0x4 )
+ {
+ cputag_set_input_line(device->machine(), "maincpu", 1, HOLD_LINE); /* Is this right? */
+ }
+
+ /* Adjust volume */
+ *buffer *= state->m_o2_vdc.s.sound & 0xf;
+ /* Pump the volume up */
+ *buffer <<= 10;
+ }
+ }
+ else
+ {
+ /* Sound disabled, so clear the buffer */
+ for( ii = 0; ii < samples; ii++, buffer++ )
+ *buffer = 0;
+ }
+}
+
+/*
+ Thomson EF9340/EF9341 extra chips in the g7400
+ */
+
+#ifdef UNUSED_FUNCTION
+INLINE UINT16 ef9341_get_c_addr( odyssey2_state *state )
+{
+ if ( ( state->m_ef9341.Y & 0x0C ) == 0x0C )
+ {
+ return 0x318 | ( ( state->m_ef9341.X & 0x38 ) << 2 ) | ( state->m_ef9341.X & 0x07 );
+ }
+ if ( state->m_ef9341.X & 0x20 )
+ {
+ return 0x300 | ( ( state->m_ef9341.Y & 0x07 ) << 5 ) | ( state->m_ef9341.Y & 0x18 ) | ( state->m_ef9341.X & 0x07 );
+ }
+ return ( state->m_ef9341.Y << 5 ) | state->m_ef9341.X;
+}
+
+INLINE void ef9341_inc_c( odyssey2_state *state )
+{
+ state->m_ef9341.X++;
+ if ( state->m_ef9341.X >= 40 )
+ {
+ state->m_ef9341.Y = ( state->m_ef9341.Y + 1 ) % 24;
+ }
+}
+
+void odyssey2_ef9341_w( running_machine &machine, int command, int b, UINT8 data )
+{
+ odyssey2_state *state = machine.driver_data<odyssey2_state>();
+ logerror("ef9341 %s write, t%s, data %02X\n", command ? "command" : "data", b ? "B" : "A", data );
+
+ if ( command )
+ {
+ if ( b )
+ {
+ state->m_ef9341.TB = data;
+ state->m_ef9341.busy = 0x80;
+ switch( state->m_ef9341.TB & 0xE0 )
+ {
+ case 0x00: /* Begin row */
+ state->m_ef9341.X = 0;
+ state->m_ef9341.Y = state->m_ef9341.TA & 0x1F;
+ break;
+ case 0x20: /* Load Y */
+ state->m_ef9341.Y = state->m_ef9341.TA & 0x1F;
+ break;
+ case 0x40: /* Load X */
+ state->m_ef9341.X = state->m_ef9341.TA & 0x3F;
+ break;
+ case 0x60: /* INC C */
+ ef9341_inc_c(state);
+ break;
+ case 0x80: /* Load M */
+ state->m_ef9341.M = state->m_ef9341.TA;
+ break;
+ case 0xA0: /* Load R */
+ state->m_ef9341.R = state->m_ef9341.TA;
+ break;
+ case 0xC0: /* Load Y0 */
+ state->m_ef9341.Y0 = state->m_ef9341.TA & 0x3F;
+ break;
+ }
+ state->m_ef9341.busy = 0;
+ }
+ else
+ {
+ state->m_ef9341.TA = data;
+ }
+ }
+ else
+ {
+ if ( b )
+ {
+ state->m_ef9341.TB = data;
+ state->m_ef9341.busy = 0x80;
+ switch ( state->m_ef9341.M & 0xE0 )
+ {
+ case 0x00: /* Write */
+ state->m_ef9341.ram[ ef9341_get_c_addr(state) ] = state->m_ef9341.TB;
+ ef9341_inc_c(state);
+ break;
+ case 0x20: /* Read */
+ logerror("ef9341 unimplemented data action %02X\n", state->m_ef9341.M & 0xE0 );
+ ef9341_inc_c(state);
+ break;
+ case 0x40: /* Write without increment */
+ case 0x60: /* Read without increment */
+ case 0x80: /* Write slice */
+ case 0xA0: /* Read slice */
+ logerror("ef9341 unimplemented data action %02X\n", state->m_ef9341.M & 0xE0 );
+ break;
+ }
+ state->m_ef9341.busy = 0;
+ }
+ else
+ {
+ state->m_ef9341.TA = data;
+ }
+ }
+}
+
+UINT8 odyssey2_ef9341_r( running_machine &machine, int command, int b )
+{
+ odyssey2_state *state = machine.driver_data<odyssey2_state>();
+ UINT8 data = 0xFF;
+
+ logerror("ef9341 %s read, t%s\n", command ? "command" : "data", b ? "B" : "A" );
+ if ( command )
+ {
+ if ( b )
+ {
+ data = 0xFF;
+ }
+ else
+ {
+ data = state->m_ef9341.busy;
+ }
+ }
+ else
+ {
+ if ( b )
+ {
+ data = state->m_ef9341.TB;
+ state->m_ef9341.busy = 0x80;
+ }
+ else
+ {
+ data = state->m_ef9341.TA;
+ }
+ }
+ return data;
+}
+#endif
+
+DEFINE_LEGACY_SOUND_DEVICE(ODYSSEY2, odyssey2_sound);
diff --git a/src/mess/video/ondra.c b/src/mess/video/ondra.c
new file mode 100644
index 00000000000..fcde0a77388
--- /dev/null
+++ b/src/mess/video/ondra.c
@@ -0,0 +1,48 @@
+/***************************************************************************
+
+ Ondra driver by Miodrag Milanovic
+
+ 08/09/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/ondra.h"
+#include "machine/ram.h"
+
+
+
+VIDEO_START( ondra )
+{
+ ondra_state *state = machine.driver_data<ondra_state>();
+ state->m_video_enable = 0;
+}
+
+SCREEN_UPDATE_IND16( ondra )
+{
+ ondra_state *state = screen.machine().driver_data<ondra_state>();
+ UINT8 code1,code2;
+ int y, x, b;
+ int Vaddr = 0x2800;
+
+ if (state->m_video_enable==1) {
+ for (x = 0; x < 40; x++)
+ {
+ for (y = 127; y >=0; y--)
+ {
+ code1 = screen.machine().device<ram_device>(RAM_TAG)->pointer()[0xd700 + Vaddr + 0x80];
+ code2 = screen.machine().device<ram_device>(RAM_TAG)->pointer()[0xd700 + Vaddr + 0x00];
+ for (b = 0; b < 8; b++)
+ {
+ bitmap.pix16(2*y, x*8+b) = ((code1 << b) & 0x80) ? 1 : 0;
+ bitmap.pix16(2*y+1, x*8+b) = ((code2 << b) & 0x80) ? 1 : 0;
+ }
+ Vaddr++;
+ }
+ Vaddr = (Vaddr - 128) - 256;
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/orao.c b/src/mess/video/orao.c
new file mode 100644
index 00000000000..70e772128df
--- /dev/null
+++ b/src/mess/video/orao.c
@@ -0,0 +1,40 @@
+/***************************************************************************
+
+ Orao video driver by Miodrag Milanovic
+
+ 01/03/2008 Updated to work with latest SVN code
+ 22/02/2008 Preliminary driver.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "includes/orao.h"
+
+
+VIDEO_START( orao )
+{
+}
+
+SCREEN_UPDATE_IND16( orao )
+{
+ orao_state *state = screen.machine().driver_data<orao_state>();
+ UINT8 code;
+ int y, x, b;
+
+ int addr = 0;
+ for (y = 0; y < 256; y++)
+ {
+ int horpos = 0;
+ for (x = 0; x < 32; x++)
+ {
+ code = state->m_video_ram[addr++];
+ for (b = 0; b < 8; b++)
+ {
+ bitmap.pix16(y, horpos++) = (code >> b) & 0x01;
+ }
+ }
+ }
+ return 0;
+}
+
+
diff --git a/src/mess/video/oric.c b/src/mess/video/oric.c
new file mode 100644
index 00000000000..def59d749e1
--- /dev/null
+++ b/src/mess/video/oric.c
@@ -0,0 +1,308 @@
+/***************************************************************************
+
+ video/oric.c
+
+ All graphic effects are supported including mid-line changes.
+ There may be some small bugs.
+
+ TODO:
+ - speed up this code a bit?
+
+***************************************************************************/
+
+#include "includes/oric.h"
+
+static TIMER_CALLBACK(oric_vh_timer_callback)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ /* update flash count */
+ state->m_vh_state.flash_count++;
+}
+
+static void oric_vh_update_flash(oric_state *state)
+{
+ /* flash active? */
+ if (BIT(state->m_vh_state.text_attributes, 2))
+ {
+ /* yes */
+
+ /* show or hide text? */
+ if (BIT(state->m_vh_state.flash_count, 4))
+ {
+ /* hide */
+ /* set foreground and background to be the same */
+ state->m_vh_state.active_foreground_colour = state->m_vh_state.background_colour;
+ state->m_vh_state.active_background_colour = state->m_vh_state.background_colour;
+ return;
+ }
+ }
+
+
+ /* show */
+ state->m_vh_state.active_foreground_colour = state->m_vh_state.foreground_colour;
+ state->m_vh_state.active_background_colour = state->m_vh_state.background_colour;
+}
+
+/* the alternate charset follows from the standard charset.
+Each charset holds 128 chars with 8 bytes for each char.
+
+The start address for the standard charset is dependant on the video mode */
+static void oric_refresh_charset(oric_state *state)
+{
+ /* alternate char set? */
+ if (BIT(state->m_vh_state.text_attributes, 0))
+ {
+ /* yes */
+ state->m_vh_state.char_data = state->m_vh_state.char_base + (128*8);
+ }
+ else
+ {
+ /* no */
+ state->m_vh_state.char_data = state->m_vh_state.char_base;
+ }
+}
+
+/* update video hardware state depending on the new attribute */
+static void oric_vh_update_attribute(running_machine &machine, UINT8 c)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ /* attribute */
+ UINT8 attribute = c & 0x03f;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ switch ((attribute>>3) & 0x03)
+ {
+ case 0:
+ {
+ /* set foreground colour 00-07 = black,red,green,yellow,blue,magenta,cyan,white */
+ state->m_vh_state.foreground_colour = attribute & 0x07;
+ oric_vh_update_flash(state);
+ }
+ break;
+
+ case 1:
+ {
+ state->m_vh_state.text_attributes = attribute & 0x07;
+
+ oric_refresh_charset(state);
+
+ /* text attributes */
+ oric_vh_update_flash(state);
+ }
+ break;
+
+ case 2:
+ {
+ /* set background colour */
+ state->m_vh_state.background_colour = attribute & 0x07;
+ oric_vh_update_flash(state);
+ }
+ break;
+
+ case 3:
+ {
+ /* set video mode */
+ state->m_vh_state.mode = attribute & 0x07;
+
+ // a different charset base is used depending on the video mode
+ // hires takes all the data from 0x0a000 through to about 0x0bf68,
+ // so the charset is moved to 0x09800 */
+ // text mode starts at 0x0bb80 and so the charset is in a different location
+ if (BIT(state->m_vh_state.mode, 2))
+ {
+ /* set screen memory base and standard charset location for this mode */
+ state->m_vh_state.read_addr = 0x0a000;
+ if (state->m_ram)
+ state->m_vh_state.char_base = state->m_ram + (offs_t)0x09800;
+ else
+ state->m_vh_state.char_base = (UINT8 *)space->get_read_ptr(0x09800);
+ }
+ else
+ {
+ /* set screen memory base and standard charset location for this mode */
+ state->m_vh_state.read_addr = 0x0bb80;
+ if (state->m_ram)
+ state->m_vh_state.char_base = state->m_ram + (offs_t)0x0b400;
+ else
+ state->m_vh_state.char_base = (UINT8 *)space->get_read_ptr(0x0b400);
+ }
+ /* changing the mode also changes the position of the standard charset and alternative charset */
+ oric_refresh_charset(state);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* render 6-pixels using foreground and background colours specified */
+/* used in hires and text mode */
+static void oric_vh_render_6pixels(bitmap_ind16 &bitmap, int x, UINT8 y, UINT8 fg, UINT8 bg, UINT8 data, bool invert_flag)
+{
+ /* invert? */
+ if (invert_flag)
+ {
+ fg ^=0x07;
+ bg ^=0x07;
+ }
+
+ bitmap.pix16(y, x++) = BIT(data, 5) ? fg : bg;
+ bitmap.pix16(y, x++) = BIT(data, 4) ? fg : bg;
+ bitmap.pix16(y, x++) = BIT(data, 3) ? fg : bg;
+ bitmap.pix16(y, x++) = BIT(data, 2) ? fg : bg;
+ bitmap.pix16(y, x++) = BIT(data, 1) ? fg : bg;
+ bitmap.pix16(y, x++) = BIT(data, 0) ? fg : bg;
+}
+
+
+
+
+
+/***************************************************************************
+ oric_vh_screenrefresh
+***************************************************************************/
+SCREEN_UPDATE_IND16( oric )
+{
+ oric_state *state = screen.machine().driver_data<oric_state>();
+ UINT8 *RAM, y;
+ offs_t byte_offset, read_addr_base;
+ bool hires_active;
+
+ RAM = state->m_ram;
+
+ /* set initial base */
+ read_addr_base = state->m_vh_state.read_addr;
+
+ /* is hires active? */
+ hires_active = BIT(state->m_vh_state.mode, 2);
+
+ for (y = 0; y < 224; y++)
+ {
+ int x = 0;
+
+ /* foreground colour white */
+ oric_vh_update_attribute(screen.machine(),7);
+ /* background colour black */
+ oric_vh_update_attribute(screen.machine(),(1<<3));
+ oric_vh_update_attribute(screen.machine(),(1<<4));
+
+ for (byte_offset=0; byte_offset<40; byte_offset++)
+ {
+ UINT8 c;
+ offs_t read_addr;
+
+ /* after line 200 all rendering is done in text mode */
+ if (y<200)
+ {
+ /* calculate fetch address based on current line and current mode */
+ if (hires_active)
+ {
+ read_addr = read_addr_base + byte_offset + (offs_t)(y*40);
+ }
+ else
+ {
+ UINT8 char_line = y>>3;
+ read_addr = read_addr_base + byte_offset + (offs_t)(char_line*40);
+ }
+ }
+ else
+ {
+ UINT8 char_line = (y-200)>>3;
+ read_addr = read_addr_base + byte_offset + (offs_t)(char_line*40);
+ }
+
+ /* fetch data */
+ c = RAM ? RAM[read_addr] : screen.machine().device("maincpu")->memory().space(AS_PROGRAM)->read_byte(read_addr);
+
+ /* if bits 6 and 5 are zero, the byte contains a serial attribute */
+ if ((c & ((1 << 6) | (1 << 5))) == 0)
+ {
+ oric_vh_update_attribute(screen.machine(), c);
+
+ /* display background colour when attribute has been found */
+ oric_vh_render_6pixels(bitmap, x, y, state->m_vh_state.active_foreground_colour, state->m_vh_state.active_background_colour, 0, (c & 0x080));
+
+ if (y < 200)
+ {
+ /* is hires active? */
+ hires_active = BIT(state->m_vh_state.mode, 2);
+ read_addr_base = state->m_vh_state.read_addr;
+ }
+ }
+ else
+ {
+ /* hires? */
+ if (hires_active)
+ {
+ UINT8 pixel_data = c & 0x03f;
+ /* plot hires pixels */
+ oric_vh_render_6pixels(bitmap,x,y,state->m_vh_state.active_foreground_colour, state->m_vh_state.active_background_colour, pixel_data, BIT(c, 7));
+ }
+ else
+ {
+ UINT8 char_index, char_data, ch_line;
+
+ char_index = (c & 0x07f);
+
+ ch_line = y & 7;
+
+ /* is double height set? */
+ if (BIT(state->m_vh_state.text_attributes, 1))
+ {
+ /* if char line is even, top half of character is displayed else bottom half */
+ UINT8 double_height_flag = BIT(y, 3);
+
+ /* calculate line to fetch */
+ ch_line = (ch_line>>1) + (double_height_flag<<2);
+ }
+
+ /* fetch pixel data for this char line */
+ char_data = state->m_vh_state.char_data[(char_index<<3) | ch_line] & 0x03f;
+
+ /* draw! */
+ oric_vh_render_6pixels(bitmap,x,y,
+ state->m_vh_state.active_foreground_colour,
+ state->m_vh_state.active_background_colour, char_data, BIT(c, 7));
+ }
+
+ }
+
+ x+=6;
+ }
+
+ /* after 200 lines have been drawn, force a change of the read address */
+ /* there are 200 lines of hires/text mode, then 24 lines of text mode */
+ /* the mode can't be changed in the last 24 lines. */
+ if (y==199)
+ {
+ /* mode */
+ read_addr_base = (offs_t)0x0bf68;
+ hires_active = 0;
+ }
+ }
+ return 0;
+}
+
+
+VIDEO_START( oric )
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ // initialise variables
+ state->m_vh_state.active_foreground_colour = 0;
+ state->m_vh_state.active_background_colour = 0;
+ state->m_vh_state.foreground_colour = 0;
+ state->m_vh_state.background_colour = 0;
+ state->m_vh_state.mode = 0;
+ state->m_vh_state.text_attributes = 0;
+ state->m_vh_state.read_addr = 0;
+ state->m_vh_state.char_data = 0;
+ state->m_vh_state.char_base = 0;
+ /* initialise flash timer */
+ state->m_vh_state.flash_count = 0;
+ machine.scheduler().timer_pulse(attotime::from_hz(50), FUNC(oric_vh_timer_callback));
+ /* mode */
+ oric_vh_update_attribute(machine,(1<<3)|(1<<4));
+}
+
diff --git a/src/mess/video/orion.c b/src/mess/video/orion.c
new file mode 100644
index 00000000000..75ccdd130cd
--- /dev/null
+++ b/src/mess/video/orion.c
@@ -0,0 +1,116 @@
+/***************************************************************************
+
+ Orion video driver by Miodrag Milanovic
+
+ 22/04/2008 Orion Pro added
+ 02/04/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/orion.h"
+#include "machine/ram.h"
+
+VIDEO_START( orion128 )
+{
+}
+
+SCREEN_UPDATE_IND16( orion128 )
+{
+ orion_state *state = screen.machine().driver_data<orion_state>();
+ UINT8 code1,code2,code3,code4,color,val;
+ int y, x,b;
+ int orionproshift = (state->m_orion128_video_mode & 0x10) ? 1 : 0;
+ int part1addr = (3-((state->m_orion128_video_page & 3) | orionproshift)) * 0x4000;
+ int part2addr = part1addr + 0x10000;
+ int video_mode = state->m_orion128_video_mode & state->m_video_mode_mask;
+ UINT8 *ram = screen.machine().device<ram_device>(RAM_TAG)->pointer();
+
+ for (x = 0; x < state->m_orion128_video_width; x++)
+ {
+ for (y = 0; y < 256; y++)
+ {
+ code1 = ram[part1addr + y + x*256];
+ code2 = ram[part2addr + y + x*256];
+ code3 = ram[part1addr + y + x*256 + 0x4000];
+ code4 = ram[part2addr + y + x*256 + 0x4000];
+ if ((video_mode==14) || (video_mode==15)) {
+ code2 = state->m_orionpro_pseudo_color;
+ }
+ color = 0;
+ for (b = 7; b >= 0; b--)
+ {
+ switch(state->m_orion128_video_mode & state->m_video_mode_mask) {
+ case 0 : color = ((code1 >> b) & 0x01) ? 10 : 0; break;
+ case 1 : color = ((code1 >> b) & 0x01) ? 17 : 16; break;
+ case 4 : val = (((code1 >> b) & 0x01) << 1) + ((code2 >> b) & 0x01);
+ switch(val) {
+ case 0 : color = 0; break; // black
+ case 1 : color = 4; break; // red
+ case 2 : color = 2; break; // green
+ case 3 : color = 1; break; // blue
+ }
+ break;
+ case 5 : val = (((code1 >> b) & 0x01) << 1) + ((code2 >> b) & 0x01);
+ switch(val) {
+ case 0 : color = 7; break; // white
+ case 1 : color = 4; break; // red
+ case 2 : color = 2; break; // green
+ case 3 : color = 1; break; // blue
+ }
+ break;
+ case 6 :
+ case 7 :
+ case 14 :
+ case 15 :
+ color = ((code1 >> b) & 0x01) ? (code2 & 0x0f) : (code2 >> 4); break;
+
+ default:
+ switch(state->m_orion128_video_mode & state->m_video_mode_mask & 20) {
+ case 16 :
+ color = (((code1 >> b) & 0x01) << 2) + (((code3 >> b) & 0x01) << 1) + ((code2 >> b) & 0x01);
+ break;
+ case 20 :
+ color = (((code1 >> b) & 0x01) << 2) + (((code3 >> b) & 0x01) << 1) + ((code2 >> b) & 0x01);
+ if ((((code4 >> b) & 0x01)==1) && (color!=0)) {
+ color += 8;
+ }
+ break;
+ }
+ }
+ bitmap.pix16(y, x*8+(7-b)) = color;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const rgb_t orion128_palette[18] = {
+ MAKE_RGB(0x00, 0x00, 0x00), // 0
+ MAKE_RGB(0x00, 0x00, 0xc0), // 1
+ MAKE_RGB(0x00, 0xc0, 0x00), // 2
+ MAKE_RGB(0x00, 0xc0, 0xc0), // 3
+ MAKE_RGB(0xc0, 0x00, 0x00), // 4
+ MAKE_RGB(0xc0, 0x00, 0xc0), // 5
+ MAKE_RGB(0xc0, 0xc0, 0x00), // 6
+ MAKE_RGB(0xc0, 0xc0, 0xc0), // 7
+ MAKE_RGB(0x80, 0x80, 0x80), // 8
+ MAKE_RGB(0x00, 0x00, 0xff), // 9
+ MAKE_RGB(0x00, 0xff, 0x00), // A
+ MAKE_RGB(0x00, 0xff, 0xff), // B
+ MAKE_RGB(0xff, 0x00, 0x00), // C
+ MAKE_RGB(0xff, 0x00, 0xff), // D
+ MAKE_RGB(0xff, 0xff, 0x00), // E
+ MAKE_RGB(0xff, 0xff, 0xff), // F
+ MAKE_RGB(0xc8, 0xb4, 0x28), // 10
+ MAKE_RGB(0x32, 0xfa, 0xfa) // 11
+};
+
+PALETTE_INIT( orion128 )
+{
+ palette_set_colors(machine, 0, orion128_palette, ARRAY_LENGTH(orion128_palette));
+}
+
+
diff --git a/src/mess/video/osi.c b/src/mess/video/osi.c
new file mode 100644
index 00000000000..e363d47b1dc
--- /dev/null
+++ b/src/mess/video/osi.c
@@ -0,0 +1,182 @@
+#include "includes/osi.h"
+
+/* Palette Initialization */
+
+static PALETTE_INIT( osi630 )
+{
+ /* black and white */
+ palette_set_color_rgb(machine, 0, 0x00, 0x00, 0x00); // black
+ palette_set_color_rgb(machine, 1, 0xff, 0xff, 0xff); // white
+
+ /* color enabled */
+ palette_set_color_rgb(machine, 2, 0xff, 0xff, 0x00); // yellow
+ palette_set_color_rgb(machine, 3, 0xff, 0x00, 0x00); // red
+ palette_set_color_rgb(machine, 4, 0x00, 0xff, 0x00); // green
+ palette_set_color_rgb(machine, 5, 0x00, 0x80, 0x00); // olive green
+ palette_set_color_rgb(machine, 6, 0x00, 0x00, 0xff); // blue
+ palette_set_color_rgb(machine, 7, 0xff, 0x00, 0xff); // purple
+ palette_set_color_rgb(machine, 8, 0x00, 0x00, 0x80); // sky blue
+ palette_set_color_rgb(machine, 9, 0x00, 0x00, 0x00); // black
+}
+
+/* Video Start */
+
+void sb2m600_state::video_start()
+{
+ UINT16 addr;
+
+ /* randomize video memory contents */
+ for (addr = 0; addr < OSI600_VIDEORAM_SIZE; addr++)
+ {
+ m_video_ram[addr] = machine().rand() & 0xff;
+ }
+
+ /* randomize color memory contents */
+ if (m_color_ram)
+ {
+ for (addr = 0; addr < OSI630_COLORRAM_SIZE; addr++)
+ {
+ m_color_ram[addr] = machine().rand() & 0x0f;
+ }
+ }
+}
+
+/* Video Update */
+
+UINT32 sb2m600_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ int y, bit, sx;
+
+ if (m_32)
+ {
+ for (y = 0; y < 256; y++)
+ {
+ UINT16 videoram_addr = (y >> 4) * 64;
+ int line = (y >> 1) & 0x07;
+ int x = 0;
+
+ for (sx = 0; sx < 64; sx++)
+ {
+ UINT8 videoram_data = m_video_ram[videoram_addr];
+ UINT16 charrom_addr = ((videoram_data << 3) | line) & 0x7ff;
+ UINT8 charrom_data = memregion("chargen")->base()[charrom_addr];
+
+ for (bit = 0; bit < 8; bit++)
+ {
+ int color = BIT(charrom_data, 7);
+
+ if (m_coloren)
+ {
+ UINT8 colorram_data = m_color_ram[videoram_addr];
+ color = (color ^ BIT(colorram_data, 0)) ? (((colorram_data >> 1) & 0x07) + 2) : 0;
+ }
+
+ bitmap.pix16(y, x++) = color;
+
+ charrom_data <<= 1;
+ }
+
+ videoram_addr++;
+ }
+ }
+ }
+ else
+ {
+ for (y = 0; y < 256; y++)
+ {
+ UINT16 videoram_addr = (y >> 3) * 32;
+ int line = y & 0x07;
+ int x = 0;
+
+ for (sx = 0; sx < 32; sx++)
+ {
+ UINT8 videoram_data = m_video_ram[videoram_addr];
+ UINT16 charrom_addr = ((videoram_data << 3) | line) & 0x7ff;
+ UINT8 charrom_data = memregion("chargen")->base()[charrom_addr];
+
+ for (bit = 0; bit < 8; bit++)
+ {
+ int color = BIT(charrom_data, 7);
+
+ if (m_coloren)
+ {
+ UINT8 colorram_data = m_color_ram[videoram_addr];
+ color = (color ^ BIT(colorram_data, 0)) ? (((colorram_data >> 1) & 0x07) + 2) : 0;
+ }
+
+ bitmap.pix16(y, x++) = color;
+ bitmap.pix16(y, x++) = color;
+
+ charrom_data <<= 1;
+ }
+
+ videoram_addr++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+UINT32 uk101_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ int y, bit, sx;
+
+ for (y = 0; y < 256; y++)
+ {
+ UINT16 videoram_addr = (y >> 4) * 64;
+ int line = (y >> 1) & 0x07;
+ int x = 0;
+
+ for (sx = 0; sx < 64; sx++)
+ {
+ UINT8 videoram_data = m_video_ram[videoram_addr++];
+ UINT16 charrom_addr = ((videoram_data << 3) | line) & 0x7ff;
+ UINT8 charrom_data = memregion("chargen")->base()[charrom_addr];
+
+ for (bit = 0; bit < 8; bit++)
+ {
+ bitmap.pix16(y, x) = BIT(charrom_data, 7);
+ x++;
+ charrom_data <<= 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Machine Drivers */
+
+MACHINE_CONFIG_FRAGMENT( osi600_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_REFRESH_RATE(X1/256/256) // 60 Hz
+ MCFG_SCREEN_UPDATE_DRIVER(sb2m600_state, screen_update)
+ MCFG_SCREEN_SIZE(64*8, 32*8)
+ MCFG_SCREEN_VISIBLE_AREA(0*8, 64*8-1, 0, 32*8-1)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(black_and_white)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( uk101_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_REFRESH_RATE(50)
+ MCFG_SCREEN_UPDATE_DRIVER(uk101_state, screen_update)
+ MCFG_SCREEN_SIZE(64*8, 16*16)
+ MCFG_SCREEN_VISIBLE_AREA(0, 64*8-1, 0, 16*16-1)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(black_and_white)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( osi630_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_REFRESH_RATE(X1/256/256) // 60 Hz
+ MCFG_SCREEN_UPDATE_DRIVER(sb2m600_state, screen_update)
+ MCFG_SCREEN_SIZE(64*8, 16*16)
+ MCFG_SCREEN_VISIBLE_AREA(0, 64*8-1, 0, 16*16-1)
+
+ MCFG_PALETTE_LENGTH(8+2)
+ MCFG_PALETTE_INIT(osi630)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/p2000m.c b/src/mess/video/p2000m.c
new file mode 100644
index 00000000000..72cc493471c
--- /dev/null
+++ b/src/mess/video/p2000m.c
@@ -0,0 +1,60 @@
+/**********************************************************************
+
+ p2000m.c
+
+ Functions to emulate video hardware of the p2000m
+
+**********************************************************************/
+
+#include "includes/p2000t.h"
+
+
+
+
+VIDEO_START( p2000m )
+{
+ p2000t_state *state = machine.driver_data<p2000t_state>();
+ state->m_frame_count = 0;
+}
+
+
+SCREEN_UPDATE_IND16( p2000m )
+{
+ p2000t_state *state = screen.machine().driver_data<p2000t_state>();
+ UINT8 *videoram = state->m_p_videoram;
+ int offs, sx, sy, code, loop;
+
+ for (offs = 0; offs < 80 * 24; offs++)
+ {
+ sy = (offs / 80) * 20;
+ sx = (offs % 80) * 12;
+
+ if ((state->m_frame_count > 25) && (videoram[offs + 2048] & 0x40))
+ code = 32;
+ else
+ {
+ code = videoram[offs];
+ if ((videoram[offs + 2048] & 0x01) && (code & 0x20))
+ {
+ code += (code & 0x40) ? 64 : 96;
+ } else {
+ code &= 0x7f;
+ }
+ if (code < 32) code = 32;
+ }
+
+ drawgfxzoom_opaque (bitmap, cliprect, screen.machine().gfx[0], code,
+ videoram[offs + 2048] & 0x08 ? 0 : 1, 0, 0, sx, sy, 0x20000, 0x20000);
+
+ if (videoram[offs] & 0x80)
+ {
+ for (loop = 0; loop < 12; loop++)
+ {
+ bitmap.pix16(sy + 18, sx + loop) = 0; /* cursor */
+ bitmap.pix16(sy + 19, sx + loop) = 0; /* cursor */
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mess/video/pc1251.c b/src/mess/video/pc1251.c
new file mode 100644
index 00000000000..fbec83e4f78
--- /dev/null
+++ b/src/mess/video/pc1251.c
@@ -0,0 +1,167 @@
+#include "emu.h"
+
+#include "includes/pocketc.h"
+#include "includes/pc1251.h"
+
+static const POCKETC_FIGURE busy={
+ "11 1 1 11 1 1",
+ "1 1 1 1 1 1 1",
+ "11 1 1 1 1 1",
+ "1 1 1 1 1 1",
+ "11 1 11 1e"
+}, def={
+ "11 111 111",
+ "1 1 1 1",
+ "1 1 111 11",
+ "1 1 1 1",
+ "11 111 1e"
+}, shift={
+ " 11 1 1 1 111 111",
+ "1 1 1 1 1 1",
+ " 1 111 1 11 1",
+ " 1 1 1 1 1 1",
+ "11 1 1 1 1 1e"
+}, hyp={
+ "1 1 1 1 11",
+ "1 1 1 1 1 1",
+ "111 1 1 11",
+ "1 1 1 1",
+ "1 1 1 1e"
+}, de={
+ "11 111",
+ "1 1 1",
+ "1 1 111",
+ "1 1 1",
+ "11 111e"
+}, g={
+ " 11",
+ "1",
+ "1 1",
+ "1 1",
+ " 11e"
+}, rad={
+ "11 1 11",
+ "1 1 1 1 1 1",
+ "11 111 1 1",
+ "1 1 1 1 1 1",
+ "1 1 1 1 11e"
+}, braces={
+ " 1 1",
+ "1 1",
+ "1 1",
+ "1 1",
+ " 1 1e"
+}, m={
+ "1 1",
+ "11 11",
+ "1 1 1",
+ "1 1",
+ "1 1e"
+}, e={
+ "111",
+ "1",
+ "111",
+ "1",
+ "111e"
+}, run={
+ "11 1 1 1 1",
+ "1 1 1 1 11 1",
+ "11 1 1 1 11",
+ "1 1 1 1 1 1",
+ "1 1 1 1 1e"
+}, pro={
+ "11 11 1 ",
+ "1 1 1 1 1 1",
+ "11 11 1 1",
+ "1 1 1 1 1",
+ "1 1 1 1e"
+}, japan={
+ " 1 1 11 1 1 1",
+ " 1 1 1 1 1 1 1 11 1",
+ " 1 111 11 111 1 11",
+ "1 1 1 1 1 1 1 1 1",
+ " 1 1 1 1 1 1 1 1e"
+}, sml={
+ " 11 1 1 1",
+ "1 111 1",
+ " 1 1 1 1",
+ " 1 1 1 1",
+ "11 1 1 111e"
+}, rsv={
+ "11 11 1 1",
+ "1 1 1 1 1",
+ "11 1 1 1",
+ "1 1 1 1 1",
+ "1 1 11 1e"
+};
+
+ READ8_HANDLER(pc1251_lcd_read)
+{
+ pc1251_state *state = space->machine().driver_data<pc1251_state>();
+ int data;
+ data = state->m_reg[offset&0xff];
+ logerror("pc1251 read %.3x %.2x\n",offset,data);
+ return data;
+}
+
+WRITE8_HANDLER(pc1251_lcd_write)
+{
+ pc1251_state *state = space->machine().driver_data<pc1251_state>();
+ logerror("pc1251 write %.3x %.2x\n",offset,data);
+ state->m_reg[offset&0xff] = data;
+}
+
+#define DOWN 62
+#define RIGHT 68
+
+SCREEN_UPDATE_IND16( pc1251 )
+{
+ pc1251_state *state = screen.machine().driver_data<pc1251_state>();
+ int x, y, i, j;
+ int color[2];
+ running_machine &machine = screen.machine();
+
+ bitmap.fill(11, cliprect);
+
+ /* HJB: we cannot initialize array with values from other arrays, thus... */
+ color[0] = 7; //pocketc_colortable[PC1251_CONTRAST][0];
+ color[1] = 8; //pocketc_colortable[PC1251_CONTRAST][1];
+
+ for (x=RIGHT,y=DOWN, i=0; i<60; x+=3)
+ {
+ for (j=0; j<5; j++, i++, x+=3)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],
+ PC1251_CONTRAST,0,0,
+ x,y);
+ }
+ for (i=0x7b; i>=0x40; x+=3)
+ {
+ for (j=0; j<5; j++, i--, x+=3)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],
+ PC1251_CONTRAST,0,0,
+ x,y);
+ }
+
+ pocketc_draw_special(bitmap, RIGHT+134, DOWN-10, de,
+ state->m_reg[0x3c] & 0x08 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, RIGHT+142, DOWN-10, g,
+ state->m_reg[0x3c] & 0x04 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, RIGHT+146, DOWN-10, rad,
+ state->m_reg[0x3d] & 0x04 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, RIGHT+18, DOWN-10, def,
+ state->m_reg[0x3c] & 0x01 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, RIGHT, DOWN-10, shift,
+ state->m_reg[0x3d] & 0x02 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, RIGHT+38, DOWN-10, pro,
+ state->m_reg[0x3e] & 0x01 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, RIGHT+53, DOWN-10, run,
+ state->m_reg[0x3e] & 0x02 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, RIGHT+68, DOWN-10, rsv,
+ state->m_reg[0x3e] & 0x04 ? color[1] : color[0]);
+
+ /* 0x3c 1 def?, 4 g, 8 de
+ 0x3d 2 shift, 4 rad, 8 error
+ 0x3e 1 pro?, 2 run?, 4rsv?*/
+ return 0;
+}
+
diff --git a/src/mess/video/pc1350.c b/src/mess/video/pc1350.c
new file mode 100644
index 00000000000..dae4669ee1f
--- /dev/null
+++ b/src/mess/video/pc1350.c
@@ -0,0 +1,170 @@
+#include "emu.h"
+
+#include "includes/pocketc.h"
+#include "includes/pc1350.h"
+
+static const POCKETC_FIGURE busy={
+ "11 1 1 11 1 1",
+ "1 1 1 1 1 1 1",
+ "11 1 1 1 1 1",
+ "1 1 1 1 1 1",
+ "11 1 11 1e"
+}, def={
+ "11 111 111",
+ "1 1 1 1",
+ "1 1 111 11",
+ "1 1 1 1",
+ "11 111 1e"
+}, shift={
+ " 11 1 1 1 111 111",
+ "1 1 1 1 1 1",
+ " 1 111 1 11 1",
+ " 1 1 1 1 1 1",
+ "11 1 1 1 1 1e"
+}, hyp={
+ "1 1 1 1 11",
+ "1 1 1 1 1 1",
+ "111 1 1 11",
+ "1 1 1 1",
+ "1 1 1 1e"
+}, de={
+ "11 111",
+ "1 1 1",
+ "1 1 111",
+ "1 1 1",
+ "11 111e"
+}, g={
+ " 11",
+ "1",
+ "1 1",
+ "1 1",
+ " 11e"
+}, rad={
+ "11 1 11",
+ "1 1 1 1 1 1",
+ "11 111 1 1",
+ "1 1 1 1 1 1",
+ "1 1 1 1 11e"
+}, braces={
+ " 1 1",
+ "1 1",
+ "1 1",
+ "1 1",
+ " 1 1e"
+}, m={
+ "1 1",
+ "11 11",
+ "1 1 1",
+ "1 1",
+ "1 1e"
+}, e={
+ "111",
+ "1",
+ "111",
+ "1",
+ "111e"
+}, run={
+ "11 1 1 1 1",
+ "1 1 1 1 11 1",
+ "11 1 1 1 11",
+ "1 1 1 1 1 1",
+ "1 1 1 1 1e"
+}, pro={
+ "11 11 1 ",
+ "1 1 1 1 1 1",
+ "11 11 1 1",
+ "1 1 1 1 1",
+ "1 1 1 1e"
+}, japan={
+ " 1 1 11 1 1 1",
+ " 1 1 1 1 1 1 1 11 1",
+ " 1 111 11 111 1 11",
+ "1 1 1 1 1 1 1 1 1",
+ " 1 1 1 1 1 1 1 1e"
+}, sml={
+ " 11 1 1 1",
+ "1 111 1",
+ " 1 1 1 1",
+ " 1 1 1 1",
+ "11 1 1 111e"
+}, rsv={
+ "11 11 1 1",
+ "1 1 1 1 1",
+ "11 1 1 1",
+ "1 1 1 1 1",
+ "1 1 11 1e"
+};
+
+ READ8_HANDLER(pc1350_lcd_read)
+{
+ pc1350_state *state = space->machine().driver_data<pc1350_state>();
+ int data;
+ data = state->m_reg[offset&0xfff];
+ logerror("pc1350 read %.3x %.2x\n",offset,data);
+ return data;
+}
+
+WRITE8_HANDLER(pc1350_lcd_write)
+{
+ pc1350_state *state = space->machine().driver_data<pc1350_state>();
+ logerror("pc1350 write %.3x %.2x\n",offset,data);
+ state->m_reg[offset&0xfff] = data;
+}
+
+int pc1350_keyboard_line_r(running_machine &machine)
+{
+ pc1350_state *state = machine.driver_data<pc1350_state>();
+ return state->m_reg[0xe00];
+}
+
+/* pc1350
+ 24x4 5x8 no space between chars
+ 7000 .. 701d, 7200..721d, 7400 ..741d, 7600 ..761d, 7800 .. 781d
+ 7040 .. 705d, 7240..725d, 7440 ..745d, 7640 ..765d, 7840 .. 785d
+ 701e .. 703b, 721e..723b, 741e ..743b, 761e ..763b, 781e .. 783b
+ 705e .. 707b, 725e..727b, 745e ..747b, 765e ..767b, 785e .. 787b
+ 783c: 0 SHIFT 1 DEF 4 RUN 5 PRO 6 JAPAN 7 SML */
+static const int pc1350_addr[4]={ 0, 0x40, 0x1e, 0x5e };
+
+#define DOWN 45
+#define RIGHT 76
+
+SCREEN_UPDATE_IND16( pc1350 )
+{
+ pc1350_state *state = screen.machine().driver_data<pc1350_state>(); /* The contrast colours need some work done - select contrast level 7 for now */
+ int x, y=DOWN, i, j, k=0, b;
+ int color[4];
+ running_machine &machine = screen.machine();
+
+ bitmap.fill(11, cliprect);
+
+ /* HJB: we cannot initialize array with values from other arrays, thus... */
+ color[0] = pocketc_colortable[PC1350_CONTRAST][0];
+ color[1] = pocketc_colortable[PC1350_CONTRAST][1];
+ color[2] = 8;
+ color[3] = 7;
+
+ for (k=0, y=DOWN; k<4; y+=16, k++)
+ for (x=RIGHT, i=pc1350_addr[k]; i<0xa00; i+=0x200)
+ for (j=0; j<=0x1d; j++, x+=2)
+ for (b = 0; b < 8; b++)
+ bitmap.plot_box(x, y + b * 2, 2, 2, color[(state->m_reg[j+i] >> b) & 1]);
+
+
+ /* 783c: 0 SHIFT 1 DEF 4 RUN 5 PRO 6 JAPAN 7 SML */
+ /* I don't know how they really look like in the lcd */
+ pocketc_draw_special(bitmap, RIGHT-30, DOWN+45, shift,
+ state->m_reg[0x83c] & 0x01 ? color[2] : color[3]);
+ pocketc_draw_special(bitmap, RIGHT-30, DOWN+55, def,
+ state->m_reg[0x83c] & 0x02 ? color[2] : color[3]);
+ pocketc_draw_special(bitmap, RIGHT-30, DOWN+5, run,
+ state->m_reg[0x83c] & 0x10 ? color[2] : color[3]);
+ pocketc_draw_special(bitmap, RIGHT-30, DOWN+15, pro,
+ state->m_reg[0x83c] & 0x20 ? color[2] : color[3]);
+ pocketc_draw_special(bitmap, RIGHT-30, DOWN+25, japan,
+ state->m_reg[0x83c] & 0x40 ? color[2] : color[3]);
+ pocketc_draw_special(bitmap, RIGHT-30, DOWN+35, sml,
+ state->m_reg[0x83c] & 0x80 ? color[2] : color[3]);
+
+ return 0;
+}
diff --git a/src/mess/video/pc1401.c b/src/mess/video/pc1401.c
new file mode 100644
index 00000000000..2c628bc7bd3
--- /dev/null
+++ b/src/mess/video/pc1401.c
@@ -0,0 +1,218 @@
+#include "emu.h"
+
+#include "includes/pocketc.h"
+#include "includes/pc1401.h"
+
+/* pc140x
+ 16 5x7 with space between char
+ 6000 .. 6027, 6067.. 6040
+ 603c: 3 STAT
+ 603d: 0 BUSY, 1 DEF, 2 SHIFT, 3 HYP, 4 PRO, 5 RUN, 6 CAL
+ 607c: 0 E, 1 M, 2 (), 3 RAD, 4 G, 5 DE, 6 PRINT */
+
+/* pc1421
+ 16 5x7 with space between char
+ 6000 .. 6027, 6067.. 6040
+ 603c: 3 RUN
+ 603d: 0 BUSY, 1 DEF, 2 SHIFT, 3 BGN, 4 STAT, 5 FIN, 6 PRINT
+ 607c: 0 E, 1 M, 2 BAL, 3 INT, 4 PRN, 5 Sum-Sign, 6 PRO */
+
+ READ8_HANDLER(pc1401_lcd_read)
+{
+ pc1401_state *state = space->machine().driver_data<pc1401_state>();
+ offset&=0xff;
+ return state->m_reg[offset];
+}
+
+WRITE8_HANDLER(pc1401_lcd_write)
+{
+ pc1401_state *state = space->machine().driver_data<pc1401_state>();
+ offset&=0xff;
+ state->m_reg[offset]=data;
+}
+
+static const POCKETC_FIGURE line={ /* simple line */
+ "11111",
+ "11111",
+ "11111e"
+};
+static const POCKETC_FIGURE busy={
+ "11 1 1 11 1 1",
+ "1 1 1 1 1 1 1",
+ "11 1 1 1 1 1",
+ "1 1 1 1 1 1",
+ "11 1 11 1e"
+}, def={
+ "11 111 111",
+ "1 1 1 1",
+ "1 1 111 11",
+ "1 1 1 1",
+ "11 111 1e"
+}, shift={
+ " 11 1 1 1 111 111",
+ "1 1 1 1 1 1",
+ " 1 111 1 11 1",
+ " 1 1 1 1 1 1",
+ "11 1 1 1 1 1e"
+}, hyp={
+ "1 1 1 1 11",
+ "1 1 1 1 1 1",
+ "111 1 1 11",
+ "1 1 1 1",
+ "1 1 1 1e"
+}, de={
+ "11 111",
+ "1 1 1",
+ "1 1 111",
+ "1 1 1",
+ "11 111e"
+}, g={
+ " 11",
+ "1",
+ "1 1",
+ "1 1",
+ " 11e"
+}, rad={
+ "11 1 11",
+ "1 1 1 1 1 1",
+ "11 111 1 1",
+ "1 1 1 1 1 1",
+ "1 1 1 1 11e"
+}, braces={
+ " 1 1",
+ "1 1",
+ "1 1",
+ "1 1",
+ " 1 1e"
+}, m={
+ "1 1",
+ "11 11",
+ "1 1 1",
+ "1 1",
+ "1 1e"
+}, e={
+ "111",
+ "1",
+ "111",
+ "1",
+ "111e"
+}, run={
+ "11 1 1 1 1",
+ "1 1 1 1 11 1",
+ "11 1 1 1 11",
+ "1 1 1 1 1 1",
+ "1 1 1 1 1e"
+}, pro={
+ "11 11 1 ",
+ "1 1 1 1 1 1",
+ "11 11 1 1",
+ "1 1 1 1 1",
+ "1 1 1 1e"
+}, japan={
+ " 1 1 11 1 1 1",
+ " 1 1 1 1 1 1 1 11 1",
+ " 1 111 11 111 1 11",
+ "1 1 1 1 1 1 1 1 1",
+ " 1 1 1 1 1 1 1 1e"
+}, sml={
+ " 11 1 1 1",
+ "1 111 1",
+ " 1 1 1 1",
+ " 1 1 1 1",
+ "11 1 1 111e"
+}, rsv={
+ "11 11 1 1",
+ "1 1 1 1 1",
+ "11 1 1 1",
+ "1 1 1 1 1",
+ "1 1 11 1e"
+};
+
+#define DOWN 57
+#define RIGHT 114
+
+SCREEN_UPDATE_IND16( pc1401 )
+{
+ pc1401_state *state = screen.machine().driver_data<pc1401_state>();
+ running_machine &machine = screen.machine();
+ int x, y, i, j;
+ int color[2];
+
+ bitmap.fill(11, cliprect);
+
+#if 0
+ /* HJB: we cannot initialize array with values from other arrays, thus... */
+ color[0] = pocketc_colortable[CONTRAST][0];
+ color[1] = pocketc_colortable[CONTRAST][1];
+#endif
+ /* Above can be unreadable or misleading at certain contrast settings, this is better */
+ color[0] = 7;
+ color[1] = 8;
+
+ if (state->m_portc&1)
+ {
+ for (x=RIGHT,y=DOWN,i=0; i<0x28;x+=2)
+ {
+ for (j=0; j<5;j++,i++,x+=2)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],CONTRAST,0,0,x,y);
+ }
+ for (i=0x67; i>=0x40;x+=2)
+ {
+ for (j=0; j<5;j++,i--,x+=2)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],CONTRAST,0,0,x,y);
+ }
+ }
+
+ pocketc_draw_special(bitmap, RIGHT+149, DOWN+24, line,
+ state->m_reg[0x3c] & 0x08 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT, DOWN-10, busy,
+ state->m_reg[0x3d] & 0x01 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+18, DOWN-10, def,
+ state->m_reg[0x3d] & 0x02 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+43, DOWN-10,shift,
+ state->m_reg[0x3d] & 0x04 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+63, DOWN-10,hyp,
+ state->m_reg[0x3d] & 0x08 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+38, DOWN+24,line,
+ state->m_reg[0x3d] & 0x10 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+23, DOWN+24,line,
+ state->m_reg[0x3d] & 0x20 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+8, DOWN+24,line,
+ state->m_reg[0x3d] & 0x40 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+183, DOWN-10,e,
+ state->m_reg[0x7c] & 0x01 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+176, DOWN-10,m,
+ state->m_reg[0x7c] & 0x02 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+168, DOWN-10,braces,
+ state->m_reg[0x7c] & 0x04 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+138, DOWN-10,rad,
+ state->m_reg[0x7c] & 0x08 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+134, DOWN-10,g,
+ state->m_reg[0x7c] & 0x10 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+126, DOWN-10,de,
+ state->m_reg[0x7c] & 0x20 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, RIGHT+165, DOWN+24,line,
+ state->m_reg[0x7c] & 0x40 ? color[1] : color[0]);
+
+/*
+ 603c: 3 STAT
+ 603d: 0 BUSY, 1 DEF, 2 SHIFT, 3 HYP, 4 PRO, 5 RUN, 6 CAL
+ 607c: 0 E, 1 M, 2 (), 3 RAD, 4 G, 5 DE, 6 PRINT
+*/
+ return 0;
+}
+
diff --git a/src/mess/video/pc1403.c b/src/mess/video/pc1403.c
new file mode 100644
index 00000000000..1bf67e46b62
--- /dev/null
+++ b/src/mess/video/pc1403.c
@@ -0,0 +1,264 @@
+/*****************************************************************************
+ *
+ * pc1403.c
+ * portable sharp pc1403 video emulator interface
+ * (sharp pocket computers)
+ *
+ * Copyright (c) 2001 Peter Trauner, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * History of changes:
+ * 21.07.2001 Several changes listed below were made by Mario Konegger
+ * (konegger@itp.tu-graz.ac.at)
+ * Placed the grafical symbols onto the right place and added
+ * some symbols, so the display is correct rebuit.
+ * Added a strange behaviour of the display concerning the on/off
+ * state and the BUSY-symbol, which I found out with experiments
+ * with my own pc1403.
+ *****************************************************************************/
+
+#include "emu.h"
+
+#include "includes/pocketc.h"
+#include "includes/pc1403.h"
+
+
+VIDEO_START( pc1403 )
+{
+ pc1403_state *state = machine.driver_data<pc1403_state>();
+ if (strcmp(machine.system().name, "pc1403h") == 0)
+ {
+ state->m_DOWN = 69;
+ state->m_RIGHT = 155;
+ }
+ else
+ {
+ state->m_DOWN = 67;
+ state->m_RIGHT = 152;
+ }
+}
+
+
+READ8_HANDLER(pc1403_lcd_read)
+{
+ pc1403_state *state = space->machine().driver_data<pc1403_state>();
+ return state->m_reg[offset];
+}
+
+WRITE8_HANDLER(pc1403_lcd_write)
+{
+ pc1403_state *state = space->machine().driver_data<pc1403_state>();
+ state->m_reg[offset]=data;
+}
+
+static const POCKETC_FIGURE line={ /* simple line */
+ "11111",
+ "11111",
+ "11111e"
+};
+static const POCKETC_FIGURE busy={
+ "11 1 1 11 1 1",
+ "1 1 1 1 1 1 1",
+ "11 1 1 1 1 1",
+ "1 1 1 1 1 1",
+ "11 1 11 1e"
+}, def={
+ "11 111 111",
+ "1 1 1 1",
+ "1 1 111 11",
+ "1 1 1 1",
+ "11 111 1e"
+}, shift={
+ " 11 1 1 1 111 111",
+ "1 1 1 1 1 1",
+ " 1 111 1 11 1",
+ " 1 1 1 1 1 1",
+ "11 1 1 1 1 1e"
+}, hyp={
+ "1 1 1 1 11",
+ "1 1 1 1 1 1",
+ "111 1 1 11",
+ "1 1 1 1",
+ "1 1 1 1e"
+}, de={
+ "11 111",
+ "1 1 1",
+ "1 1 111",
+ "1 1 1",
+ "11 111e"
+}, g={
+ " 11",
+ "1",
+ "1 1",
+ "1 1",
+ " 11e"
+}, rad={
+ "11 1 11",
+ "1 1 1 1 1 1",
+ "11 111 1 1",
+ "1 1 1 1 1 1",
+ "1 1 1 1 11e"
+}, braces={
+ " 1 1",
+ "1 1",
+ "1 1",
+ "1 1",
+ " 1 1e"
+}, m={
+ "1 1",
+ "11 11",
+ "1 1 1",
+ "1 1",
+ "1 1e"
+}, e={
+ "111",
+ "1",
+ "111",
+ "1",
+ "111e"
+}, kana={ // katakana charset
+ " 1 1 ",
+ " 11111 111",
+ " 1 1 1 ",
+ " 1 1 1 ",
+ "1 1 1e"
+}, shoo={ // minor
+ " 1 ",
+ " 1 1 1 ",
+ "1 1 1",
+ " 1 ",
+ " 1e"
+}, sml={
+ " 11 1 1 1",
+ "1 111 1",
+ " 1 1 1 1",
+ " 1 1 1 1",
+ "11 1 1 111e"
+};
+
+SCREEN_UPDATE_IND16( pc1403 )
+{
+ pc1403_state *state = screen.machine().driver_data<pc1403_state>();
+ running_machine &machine = screen.machine();
+ int x, y, i, j;
+ int color[3];
+
+ bitmap.fill(11, cliprect);
+
+ /* HJB: we cannot initialize array with values from other arrays, thus... */
+ color[0] = 7; // pocketc_colortable[CONTRAST][0];
+ color[2] = 8; // pocketc_colortable[CONTRAST][1];
+ color[1] = (state->m_portc & 1) ? color[2] : color[0];
+
+ if (state->m_portc & 1)
+ {
+ for (x=state->m_RIGHT, y=state->m_DOWN, i=0; i<6*5; x+=2) {
+ for (j=0; j<5; j++, i++, x+=2)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],CONTRAST,0,0,
+ x,y);
+ }
+ for (i=9*5; i<12*5; x+=2)
+ {
+ for (j=0; j<5; j++, i++, x+=2)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],CONTRAST,0,0,
+ x,y);
+ }
+ for (i=6*5; i<9*5; x+=2)
+ {
+ for (j=0; j<5; j++, i++, x+=2)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],CONTRAST,0,0,
+ x,y);
+ }
+ for (i=0x7b-3*5; i>0x7b-6*5; x+=2)
+ {
+ for (j=0; j<5; j++, i--, x+=2)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],CONTRAST,0,0,
+ x,y);
+ }
+ for (i=0x7b; i>0x7b-3*5; x+=2)
+ {
+ for (j=0; j<5; j++, i--, x+=2)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],CONTRAST,0,0,
+ x,y);
+ }
+ for (i=0x7b-6*5; i>0x7b-12*5; x+=2)
+ {
+ for (j=0; j<5; j++, i--, x+=2)
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], state->m_reg[i],CONTRAST,0,0,
+ x,y);
+ }
+ }
+ /* if display is off, busy is always visible? it seems to behave like that. */
+ /* But if computer is off, busy is hidden. */
+ if(!(state->m_portc&8))
+ {
+ if (state->m_portc&1)
+ pocketc_draw_special(bitmap, state->m_RIGHT, state->m_DOWN-13, busy,
+ state->m_reg[0x3d] & 1 ? color[2] : color[0]);
+
+ else pocketc_draw_special(bitmap, state->m_RIGHT, state->m_DOWN-13, busy, color[2]);
+ }
+ else
+ pocketc_draw_special(bitmap, state->m_RIGHT, state->m_DOWN-13, busy, color[0]);
+
+ pocketc_draw_special(bitmap, state->m_RIGHT+18, state->m_DOWN-13, def,
+ state->m_reg[0x3d] & 0x02 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+43, state->m_DOWN-13, shift,
+ state->m_reg[0x3d] & 0x04 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+63, state->m_DOWN-13, hyp,
+ state->m_reg[0x3d] & 0x08 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, state->m_RIGHT+155, state->m_DOWN-13, kana,
+ state->m_reg[0x3c] & 0x01 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+167, state->m_DOWN-13, shoo,
+ state->m_reg[0x3c] & 0x02 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+178, state->m_DOWN-13, sml,
+ state->m_reg[0x3c] & 0x04 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, state->m_RIGHT+191, state->m_DOWN-13, de,
+ state->m_reg[0x7c] & 0x20 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+199, state->m_DOWN-13, g,
+ state->m_reg[0x7c] & 0x10 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+203, state->m_DOWN-13, rad,
+ state->m_reg[0x7c] & 0x08 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, state->m_RIGHT+266, state->m_DOWN-13, braces,
+ state->m_reg[0x7c] & 0x04 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+274, state->m_DOWN-13, m,
+ state->m_reg[0x7c] & 0x02 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+281, state->m_DOWN-13, e,
+ state->m_reg[0x7c] & 0x01 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, state->m_RIGHT+10, state->m_DOWN+27, line /* empty */,
+ state->m_reg[0x3c] & 0x40 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+31, state->m_DOWN+27, line /*calc*/,
+ state->m_reg[0x3d] & 0x40 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+52, state->m_DOWN+27, line/*run*/,
+ state->m_reg[0x3d] & 0x20 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+73, state->m_DOWN+27, line/*prog*/,
+ state->m_reg[0x3d] & 0x10 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+94, state->m_DOWN+27, line /* empty */,
+ state->m_reg[0x3c] & 0x20 ? color[1] : color[0]);
+
+ pocketc_draw_special(bitmap, state->m_RIGHT+232, state->m_DOWN+27, line/*matrix*/,
+ state->m_reg[0x3c] & 0x10 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+253, state->m_DOWN+27, line/*stat*/,
+ state->m_reg[0x3c] & 0x08 ? color[1] : color[0]);
+ pocketc_draw_special(bitmap, state->m_RIGHT+274, state->m_DOWN+27, line/*print*/,
+ state->m_reg[0x7c] & 0x40 ? color[1] : color[0]);
+
+ return 0;
+}
+
+
diff --git a/src/mess/video/pc1512.c b/src/mess/video/pc1512.c
new file mode 100644
index 00000000000..07aaa83c529
--- /dev/null
+++ b/src/mess/video/pc1512.c
@@ -0,0 +1,646 @@
+#include "includes/pc1512.h"
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+static const int PALETTE_0[] = { 0, 3, 5, 7 };
+static const int PALETTE_1[] = { 0, 2, 4, 6 };
+static const int PALETTE_2[] = { 0, 3, 4, 7 };
+
+
+enum
+{
+ ALPHA_40 = 0,
+ ALPHA_80,
+ GRAPHICS_1,
+ GRAPHICS_2
+};
+
+
+#define MODE_ALPHA_80 0x01
+#define MODE_GRAPHICS 0x02
+#define MODE_PALETTE_2 0x04
+#define MODE_ENABLE_VIDEO 0x08
+#define MODE_GRAPHICS_2 0x10
+#define MODE_BLINK 0x20
+
+
+#define COLOR_INTENSITY 0x10
+#define COLOR_PALETTE_1 0x20
+
+
+#define VFP_HIRES 22
+#define HFP_HIRES 112
+#define VFP_LORES 22
+#define HFP_LORES 16
+
+
+
+//**************************************************************************
+// PALETTE
+//**************************************************************************
+
+//-------------------------------------------------
+// PALETTE_INIT( pc1512 )
+//-------------------------------------------------
+
+static PALETTE_INIT( pc1512 )
+{
+ palette_set_color_rgb(machine, 0, 0x00, 0x00, 0x00);
+ palette_set_color_rgb(machine, 1, 0x00, 0x00, 0xaa);
+ palette_set_color_rgb(machine, 2, 0x00, 0xaa, 0x00);
+ palette_set_color_rgb(machine, 3, 0x00, 0xaa, 0xaa);
+ palette_set_color_rgb(machine, 4, 0xaa, 0x00, 0x00);
+ palette_set_color_rgb(machine, 5, 0xaa, 0x00, 0xaa);
+ palette_set_color_rgb(machine, 6, 0xaa, 0x55, 0x00);
+ palette_set_color_rgb(machine, 7, 0xaa, 0xaa, 0xaa);
+ palette_set_color_rgb(machine, 8, 0x55, 0x55, 0x55);
+ palette_set_color_rgb(machine, 9, 0x55, 0x55, 0xff);
+ palette_set_color_rgb(machine, 10, 0x55, 0xff, 0x55);
+ palette_set_color_rgb(machine, 11, 0x55, 0xff, 0xff);
+ palette_set_color_rgb(machine, 12, 0xff, 0x55, 0x55);
+ palette_set_color_rgb(machine, 13, 0xff, 0x55, 0xff);
+ palette_set_color_rgb(machine, 14, 0xff, 0xff, 0x55);
+ palette_set_color_rgb(machine, 15, 0xff, 0xff, 0xff);
+}
+
+
+
+//**************************************************************************
+// VIDEO RAM ACCESS
+//**************************************************************************
+
+//-------------------------------------------------
+// video_ram_r -
+//-------------------------------------------------
+
+READ8_MEMBER( pc1512_state::video_ram_r )
+{
+ UINT8 data = 0;
+
+ switch (get_display_mode(m_vdu_mode))
+ {
+ case ALPHA_40:
+ case ALPHA_80:
+ data = m_video_ram[offset];
+ break;
+
+ case GRAPHICS_1:
+ data = m_video_ram[(offset << 2) | 3];
+ break;
+
+ case GRAPHICS_2:
+ data = m_video_ram[(offset << 2) | (m_vdu_rdsel ^ 0x03)];
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// video_ram_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( pc1512_state::video_ram_w )
+{
+ switch (get_display_mode(m_vdu_mode))
+ {
+ case ALPHA_40:
+ case ALPHA_80:
+ m_video_ram[offset] = data;
+ break;
+
+ case GRAPHICS_1:
+ m_video_ram[(offset << 2) | 3] = data;
+ m_video_ram[(offset << 2) | 2] = data;
+ m_video_ram[(offset << 2) | 1] = data;
+ m_video_ram[(offset << 2) | 0] = data;
+ break;
+
+ case GRAPHICS_2:
+ if (BIT(m_vdu_plane, 0)) m_video_ram[(offset << 2) | 3] = data;
+ if (BIT(m_vdu_plane, 1)) m_video_ram[(offset << 2) | 2] = data;
+ if (BIT(m_vdu_plane, 2)) m_video_ram[(offset << 2) | 1] = data;
+ if (BIT(m_vdu_plane, 3)) m_video_ram[(offset << 2) | 0] = data;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// vdu_r -
+//-------------------------------------------------
+
+READ8_MEMBER( pc1512_state::vdu_r )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case 1: case 3: case 5: case 7:
+ data = m_vdu->register_r(space, 0);
+ break;
+
+ case 0xa: // VDU Status
+ /*
+
+ bit description
+
+ 0 Toggle Bit
+ 1 Light-pen latch select
+ 2 Light-pen switch off
+ 3 Frame Flyback Time
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ // toggle bit
+ data |= m_toggle;
+ m_toggle = !m_toggle;
+
+ // light pen latch
+ data |= m_lpen << 1;
+
+ // light pen switch
+ data |= 0x04;
+
+ // vertical sync
+ int flyback = 0;
+
+ if (machine().primary_screen->vpos() < VFP_LORES - 16) flyback = 1;
+ if (machine().primary_screen->vpos() > VFP_LORES + 200) flyback = 1;
+
+ data |= flyback << 3;
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// vdu_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( pc1512_state::vdu_w )
+{
+ switch (offset)
+ {
+ case 0: case 2: case 4: case 6:
+ m_vdu->address_w(space, 0, data);
+ break;
+
+ case 1: case 3: case 5: case 7:
+ m_vdu->register_w(space, 0, data);
+ break;
+
+ case 8: // VDU Mode Control
+ /*
+
+ bit description
+
+ 0 Select Alpha 80 Char mode (de-select 40 Char mode)
+ 1 Select Graphics modes (de-select Alpha modes)
+ 2 Select Palette 2 (de-select palettes 0,1)
+ 3 Enable Video Display
+ 4 Select Graphics Mode 2 (de-select graphics mode 1)
+ 5 Enable Blinking Chars (disable intensified backgrounds)
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("VDU Mode Control %02x\n", data);
+
+ if ((get_display_mode(m_vdu_mode) != GRAPHICS_2) && (get_display_mode(data) == GRAPHICS_2))
+ {
+ m_vdu_plane = 0x0f;
+ m_vdu_border = 0;
+ }
+
+ if (get_display_mode(data) != GRAPHICS_2)
+ {
+ m_vdu_rdsel = 0;
+ }
+
+ if (get_display_mode(m_vdu_mode) != get_display_mode(data))
+ {
+ switch (get_display_mode(data))
+ {
+ case ALPHA_40:
+ case GRAPHICS_1:
+ m_vdu->set_hpixels_per_column(8);
+ m_vdu->set_clock(XTAL_28_63636MHz/32);
+ break;
+
+ case ALPHA_80:
+ m_vdu->set_hpixels_per_column(8);
+ m_vdu->set_clock(XTAL_28_63636MHz/16);
+ break;
+
+ case GRAPHICS_2:
+ m_vdu->set_hpixels_per_column(16);
+ m_vdu->set_clock(XTAL_28_63636MHz/32);
+ break;
+ }
+ }
+
+ m_vdu_mode = data;
+ break;
+
+ case 9: // VDU Colour Select
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("VDU Colour Select %02x\n", data);
+
+ m_vdu_color = data;
+ break;
+
+ case 0xb: // Clear Light Pen Latch
+ if (LOG) logerror("VDU Clear Light Pen Latch\n");
+
+ m_lpen = 0;
+ break;
+
+ case 0xc: // Set Light Pen Latch
+ if (LOG) logerror("VDU Set Light Pen Latch\n");
+
+ if (!m_lpen)
+ {
+ m_vdu->assert_light_pen_input();
+ }
+
+ m_lpen = 1;
+ break;
+
+ case 0xd: // VDU Colour Plane Write
+ /*
+
+ bit description
+
+ 0 Allow CPU write to Blue Plane
+ 1 Allow CPU write to Green Plane
+ 2 Allow CPU write to Red Plane
+ 3 Allow CPU write to Intensity Plane
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("VDU Colour Plane Write %01x\n", data & 0x0f);
+
+ if (get_display_mode(m_vdu_mode) == GRAPHICS_2)
+ {
+ m_vdu_plane = data;
+ }
+ break;
+
+ case 0xe: // VDU Colour Plane Read
+ /*
+
+ bit description
+
+ 0 Read Select bit 0 (RDSEL0)
+ 1 Read Select bit 1 (RDSEL1)
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("VDU Colour Plane Read %u\n", data & 0x03);
+
+ if (get_display_mode(m_vdu_mode) == GRAPHICS_2)
+ {
+ m_vdu_rdsel = data & 0x03;
+ }
+ break;
+
+ case 0xf: // VDU Graphics Mode 2 Border
+ /*
+
+ bit description
+
+ 0 Border Blue
+ 1 Border Green
+ 2 Border Red
+ 3 Border Intensity
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("VDU Graphics Mode 2 Border %u\n", data & 0x0f);
+
+ m_vdu_border = data;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// mc6845_interface crtc_intf
+//-------------------------------------------------
+
+int pc1512_state::get_display_mode(UINT8 mode)
+{
+ if (mode & MODE_GRAPHICS)
+ {
+ if (mode & MODE_GRAPHICS_2)
+ {
+ return GRAPHICS_2;
+ }
+ else
+ {
+ return GRAPHICS_1;
+ }
+ }
+ else
+ {
+ if (mode & MODE_ALPHA_80)
+ {
+ return ALPHA_80;
+ }
+ else
+ {
+ return ALPHA_40;
+ }
+ }
+}
+
+offs_t pc1512_state::get_char_rom_offset()
+{
+ return ((ioport("LK")->read() >> 5) & 0x03) << 11;
+}
+
+void pc1512_state::draw_alpha(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+{
+ offs_t char_rom_offset = get_char_rom_offset();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y + VFP_HIRES, HFP_HIRES);
+
+ if (get_display_mode(m_vdu_mode) == ALPHA_40)
+ p = &bitmap.pix32(y + VFP_LORES, HFP_LORES);
+
+ if (y > 199) return;
+
+ for (int column = 0; column < x_count; column++)
+ {
+ UINT8 code = m_video_ram[(ma + column) << 1];
+ UINT8 attr = m_video_ram[((ma + column) << 1) + 1];
+ int fg = attr & 0x0f;
+ int bg = attr >> 4;
+
+ if (m_vdu_mode & MODE_BLINK)
+ {
+ bg &= 0x07;
+
+ if (BIT(attr, 7) && !m_blink)
+ {
+ fg = bg;
+ }
+ }
+
+ offs_t addr = char_rom_offset | (code << 3) | (ra & 0x07);
+ UINT8 data = m_char_rom[addr & 0x1fff];
+
+ if ((column == cursor_x) && m_cursor)
+ {
+ data = 0xff;
+ }
+
+ for (int bit = 0; bit < 8; bit++)
+ {
+ int color = BIT(data, 7) ? fg : bg;
+
+ *p = palette[color]; p++;
+
+ data <<= 1;
+ }
+ }
+}
+
+int pc1512_state::get_color(UINT8 data)
+{
+ if (data == 0) return m_vdu_color & 0x0f;
+
+ int color = PALETTE_0[data & 0x03];
+
+ if (m_vdu_color & COLOR_PALETTE_1)
+ {
+ color = PALETTE_1[data & 0x03];
+ }
+ else if (m_vdu_mode & MODE_PALETTE_2)
+ {
+ color = PALETTE_2[data & 0x03];
+ }
+
+ if (m_vdu_color & COLOR_INTENSITY)
+ {
+ color += 8;
+ }
+
+ return color;
+};
+
+void pc1512_state::draw_graphics_1(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+{
+ if (y > 199) return;
+
+ UINT32 *p = &bitmap.pix32(y + VFP_LORES, HFP_LORES);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ for (int column = 0; column < x_count; column++)
+ {
+ offs_t offset = ((ra & 0x01) << 15) | ((ma + column) << 3);
+
+ UINT16 b = (m_video_ram[offset | 3] << 8) | m_video_ram[offset | 7];
+
+ for (int x = 0; x < 8; x++)
+ {
+ *p = palette[get_color((BIT(b, 15) << 1) | BIT(b, 14))]; p++;
+ b <<= 2;
+ }
+ }
+}
+
+void pc1512_state::draw_graphics_2(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+{
+ if (y > 199) return;
+
+ UINT32 *p = &bitmap.pix32(y + VFP_HIRES, HFP_HIRES);
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ for (int column = 0; column < x_count; column++)
+ {
+ offs_t offset = ((ra & 0x01) << 15) | ((ma + column) << 3);
+
+ UINT16 i = BIT(m_vdu_color, 3) ? ((m_video_ram[offset | 0] << 8) | m_video_ram[offset | 4]) : 0;
+ UINT16 r = BIT(m_vdu_color, 2) ? ((m_video_ram[offset | 1] << 8) | m_video_ram[offset | 5]) : 0;
+ UINT16 g = BIT(m_vdu_color, 1) ? ((m_video_ram[offset | 2] << 8) | m_video_ram[offset | 6]) : 0;
+ UINT16 b = BIT(m_vdu_color, 0) ? ((m_video_ram[offset | 3] << 8) | m_video_ram[offset | 7]) : 0;
+
+ for (int x = 0; x < 16; x++)
+ {
+ *p = palette[(BIT(i, 15) << 3) | (BIT(r, 15) << 2) | (BIT(g, 15) << 1) | BIT(b, 15)]; p++;
+ i <<= 1; r <<= 1; g <<= 1; b <<= 1;
+ }
+ }
+}
+
+static MC6845_UPDATE_ROW( pc1512_update_row )
+{
+ pc1512_state *state = device->machine().driver_data<pc1512_state>();
+
+ switch (state->get_display_mode(state->m_vdu_mode))
+ {
+ case ALPHA_40:
+ case ALPHA_80:
+ state->draw_alpha(device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param);
+ break;
+
+ case GRAPHICS_1:
+ state->draw_graphics_1(device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param);
+ break;
+
+ case GRAPHICS_2:
+ state->draw_graphics_2(device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param);
+ break;
+ }
+}
+
+static const mc6845_interface crtc_intf =
+{
+ SCREEN_TAG,
+ 8,
+ NULL,
+ pc1512_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ NULL
+};
+
+
+//-------------------------------------------------
+// VIDEO_START( pc1512 )
+//-------------------------------------------------
+
+void pc1512_state::video_start()
+{
+ // find memory regions
+ m_char_rom = memregion(AMS40041_TAG)->base();
+
+ // allocate memory
+ m_video_ram = auto_alloc_array(machine(), UINT8, 0x10000);
+}
+
+
+//-------------------------------------------------
+// SCREEN_UPDATE_RGB32( pc1512 )
+//-------------------------------------------------
+
+UINT32 pc1512_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ if (m_vdu_mode & MODE_ENABLE_VIDEO)
+ {
+ m_blink_ctr++;
+
+ if (m_blink_ctr == 0x08)
+ {
+ m_cursor = !m_cursor;
+ }
+ else if (m_blink_ctr == 0x10)
+ {
+ m_cursor = !m_cursor;
+ m_blink = !m_blink;
+ m_blink_ctr = 0;
+ }
+
+ switch (get_display_mode(m_vdu_mode))
+ {
+ case ALPHA_40:
+ case GRAPHICS_1:
+ screen.set_visible_area(0, 359, 0, 245);
+ break;
+
+ case ALPHA_80:
+ case GRAPHICS_2:
+ screen.set_visible_area(0, 831, 0, 245);
+ break;
+ }
+
+ switch (get_display_mode(m_vdu_mode))
+ {
+ case ALPHA_40:
+ case ALPHA_80:
+ case GRAPHICS_1:
+ bitmap.fill(palette[m_vdu_color & 0x0f], cliprect);
+ break;
+
+ case GRAPHICS_2:
+ bitmap.fill(palette[m_vdu_border & 0x0f], cliprect);
+ break;
+ }
+
+ m_vdu->screen_update(screen, bitmap, cliprect);
+ }
+ else
+ {
+ bitmap.fill(palette[0], cliprect);
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG( pc1512 )
+//-------------------------------------------------
+
+MACHINE_CONFIG_FRAGMENT( pc1512_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(pc1512_state, screen_update)
+ MCFG_SCREEN_SIZE(80*8, 24*8)
+ MCFG_SCREEN_VISIBLE_AREA(0, 80*8-1, 0, 24*8-1)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_REFRESH_RATE(50)
+
+ MCFG_PALETTE_LENGTH(16)
+ MCFG_PALETTE_INIT(pc1512)
+
+ MCFG_MC6845_ADD(AMS40041_TAG, AMS40041, XTAL_28_63636MHz/32, crtc_intf)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/pc1640.c b/src/mess/video/pc1640.c
new file mode 100644
index 00000000000..a768c401bd5
--- /dev/null
+++ b/src/mess/video/pc1640.c
@@ -0,0 +1,401 @@
+/*
+
+ TODO:
+
+ - EGA
+ - CGA
+ - Plantronics
+ - Hercules
+ - MDA
+
+*/
+
+#include "includes/pc1512.h"
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+
+//**************************************************************************
+// VIDEO RAM ACCESS
+//**************************************************************************
+
+//-------------------------------------------------
+// video_ram_r -
+//-------------------------------------------------
+
+READ8_MEMBER( pc1640_state::video_ram_r )
+{
+ UINT8 data = 0;
+
+ if (BIT(m_egc_ctrl, 1))
+ {
+ data = m_video_ram[offset];
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// video_ram_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( pc1640_state::video_ram_w )
+{
+ if (BIT(m_egc_ctrl, 1))
+ {
+ m_video_ram[offset] = data;
+ }
+}
+
+
+//-------------------------------------------------
+// iga_r -
+//-------------------------------------------------
+
+READ8_MEMBER( pc1640_state::iga_r )
+{
+ UINT8 data = 0;
+
+ //logerror("IGA read %03x\n", offset+0x3b0);
+
+ switch (offset)
+ {
+ case 0x01:
+ data = m_vdu->register_r(space, 0);
+ break;
+
+ case 0x05: // Mono CRT Controller Data
+ if (!BIT(m_egc_ctrl, 0))
+ {
+ data = m_vdu->register_r(space, 0);
+ }
+ break;
+
+ case 0x08: // Mono Extended Mode Control Protection Register
+ if (!BIT(m_egc_ctrl, 0))
+ {
+ m_emcrp++;
+ }
+ break;
+
+ case 0x0a: // Mono Status Register
+ /*
+
+ bit description
+
+ 0 Display Enable
+ 1 Light Pen Strobe
+ 2 Light Pen Switch (-LPSW)
+ 3 Mono Video
+ 4 Color Diagnostic (MUX)
+ 5 Color Diagnostic (MUX)
+ 6 EGA Mode
+ 7 -VSYNC
+
+ */
+
+ if (!BIT(m_egc_ctrl, 0))
+ {
+ data |= m_vdu->de_r();
+ data |= m_lpen << 1;
+ data |= 0x04;
+ data |= !m_vdu->vsync_r() << 7;
+ }
+ break;
+
+ case 0x12: // EGC Status Register
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3
+ 4 Switch Sense
+ 5
+ 6
+ 7 VSYNC Interrupt Active
+
+ */
+
+ // switch sense
+ data |= BIT(ioport("SW")->read(), ((m_egc_ctrl >> 2) & 0x03) ^ 0x03);
+ break;
+
+ case 0x15: // Sequencer Data Register
+ break;
+
+ case 0x25: // Color CRT Controller Data
+ if (BIT(m_egc_ctrl, 0))
+ {
+ data = m_vdu->register_r(space, 0);
+ }
+ break;
+
+ case 0x28: // Color Extended Mode Control Protection Register
+ if (BIT(m_egc_ctrl, 0))
+ {
+ m_emcrp++;
+ }
+ break;
+
+ case 0x2a: // Color Status Register
+ /*
+
+ bit description
+
+ 0 Display Enable
+ 1 Light Pen Strobe
+ 2 Light Pen Switch (-LPSW)
+ 3 -VSYNC
+ 4 Color Diagnostic (MUX)
+ 5 Color Diagnostic (MUX)
+ 6 EGA Mode
+ 7 1
+
+ */
+
+ if (BIT(m_egc_ctrl, 0))
+ {
+ data |= m_vdu->de_r();
+ data |= m_lpen << 1;
+ data |= 0x04;
+ data |= !m_vdu->vsync_r() << 3;
+ data |= 0x80;
+ }
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// iga_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( pc1640_state::iga_w )
+{
+ //logerror("IGA write %03x:%02x\n", offset+0x3b0, data);
+
+ switch (offset)
+ {
+ case 0x00:
+ m_vdu->address_w(space, 0, data);
+ break;
+
+ case 0x01:
+ m_vdu->register_w(space, 0, data);
+ break;
+
+ case 0x04: // Mono CRT Controller Address
+ if (!BIT(m_egc_ctrl, 0))
+ {
+ m_vdu->address_w(space, 0, data);
+ }
+ break;
+
+ case 0x05: // Mono CRT Controller Data
+ if (!BIT(m_egc_ctrl, 0))
+ {
+ }
+ break;
+
+ case 0x08: // HMGA Mode Control Register
+ break;
+
+ case 0x0b: // Mono Extended Mode Control Register
+ /*
+
+ bit description
+
+ 0 Enable Color Simulation Modes
+ 1 Enable 132 Character Mode
+ 2 Disable Blanking
+ 3 Enable Alternate Character Sets on plane 3
+ 4 Lock CRTC Timing Registers
+ 5 Disable Palette and Overscan Registers
+ 6 Enable Special Modes
+ 7 Vsync Polarity, Border Blanking
+
+ */
+
+ if (!BIT(m_egc_ctrl, 0) && (m_emcrp > 1))
+ {
+ m_emcrp = 0;
+ m_emcr = data;
+ }
+ break;
+
+ case 0x0f: // Hercules Mode Register
+ break;
+
+ case 0x10: // EGA Mode Control Register
+ break;
+
+ case 0x12: // EGC Control Register
+ /*
+
+ bit description
+
+ 0 CRTC 3BX/3DX I/O Address Select
+ 1 Display RAM Enable
+ 2 Clock Rate Select / Switch Sense Select bit 0
+ 3 Clock Rate Select / Switch Sense Select bit 1
+ 4 External Video Enable
+ 5 Alternate (64K) Text page Select
+ 6 HSYNC Polarity
+ 7 VSYNC Polarity
+
+ */
+
+ m_egc_ctrl = data;
+ break;
+
+ case 0x14: // Sequencer Address Register
+ m_sar = data;
+ break;
+
+ case 0x15: // Sequencer Data Register
+ m_sdr[m_sar & 0x07] = data;
+ break;
+
+ case 0x1e: // Graphics Controller Address
+ m_gcar = data;
+ break;
+
+ case 0x1f: // Graphics Controller Data
+ m_gcdr[m_gcar & 0x0f] = data;
+ break;
+
+ case 0x24: // Color CRT Controller Address
+ if (BIT(m_egc_ctrl, 0))
+ {
+ m_vdu->address_w(space, 0, data);
+ }
+ break;
+
+ case 0x25: // Color CRT Controller Data
+ if (BIT(m_egc_ctrl, 0))
+ {
+ m_vdu->register_w(space, 0, data);
+ }
+ break;
+
+ case 0x28: // CGA Mode Control Register
+ break;
+
+ case 0x2b: // Color Extended Mode Control Register
+ /*
+
+ bit description
+
+ 0 Enable Color Simulation Modes
+ 1 Enable 132 Character Mode
+ 2 Disable Blanking
+ 3 Enable Alternate Character Sets on plane 3
+ 4 Lock CRTC Timing Registers
+ 5 Disable Palette and Overscan Registers
+ 6 Enable Special Modes
+ 7 Vsync Polarity, Border Blanking
+
+ */
+
+ if (BIT(m_egc_ctrl, 0) && (m_emcrp > 1))
+ {
+ m_emcrp = 0;
+ m_emcr = data;
+ }
+ break;
+
+ case 0x2d: // Plantronics Mode Register
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3
+ 4 Enable Extended color palette 2
+ 5 Enable Extended color palette 1
+ 6 Color Plane 0/1 Position
+ 7
+
+ */
+
+ m_plr = data;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// mc6845_interface crtc_intf
+//-------------------------------------------------
+
+static MC6845_UPDATE_ROW( pc1640_update_row )
+{
+}
+
+static const mc6845_interface crtc_intf =
+{
+ SCREEN_TAG,
+ 8,
+ NULL,
+ pc1640_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ NULL
+};
+
+
+//-------------------------------------------------
+// VIDEO_START( pc1640 )
+//-------------------------------------------------
+
+void pc1640_state::video_start()
+{
+ // allocate memory
+ m_video_ram = auto_alloc_array(machine(), UINT8, 0x20000);
+}
+
+
+//-------------------------------------------------
+// SCREEN_UPDATE( pc1640 )
+//-------------------------------------------------
+
+UINT32 pc1640_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ return false;
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG( pc1640 )
+//-------------------------------------------------
+
+MACHINE_CONFIG_FRAGMENT( pc1640_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(pc1640_state, screen_update)
+ MCFG_SCREEN_SIZE(80*8, 25*8)
+ MCFG_SCREEN_VISIBLE_AREA(0, 80*8-1, 0, 25*8-1)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_REFRESH_RATE(60)
+
+ MCFG_PALETTE_LENGTH(64)
+
+ MCFG_MC6845_ADD(AMS40041_TAG, AMS40041, XTAL_28_63636MHz/32, crtc_intf)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/pc4.c b/src/mess/video/pc4.c
new file mode 100644
index 00000000000..1f2a5e0981f
--- /dev/null
+++ b/src/mess/video/pc4.c
@@ -0,0 +1,194 @@
+/***************************************************************************
+
+ VTech Laser PC4 LCD controller emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/pc4.h"
+
+void pc4_state::set_busy_flag(UINT16 usec)
+{
+ m_busy_flag = 1;
+ m_busy_timer->adjust( attotime::from_usec( usec ) );
+}
+
+UINT32 pc4_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(0, cliprect);
+
+ if (m_display_on)
+ for (int l=0; l<4; l++)
+ for (int i=0; i<40; i++)
+ {
+ UINT16 char_pos = l*40 + i;
+
+ for (int y=0; y<8; y++)
+ for (int x=0; x<5; x++)
+ if (m_ddram[char_pos] <= 0x10)
+ {
+ //draw CGRAM characters
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(m_cgram[(m_ddram[char_pos]&0x07)*8+y], 4-x);
+ }
+ else
+ {
+ //draw CGROM characters
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(machine().root_device().memregion("charset")->base()[m_ddram[char_pos]*8+y], 4-x);
+
+ }
+
+ // if is the correct position draw cursor and blink
+ if (char_pos == m_cursor_pos)
+ {
+ //draw the cursor
+ if (m_cursor_on)
+ for (int x=0; x<5; x++)
+ bitmap.pix16(l*9 + 7, i * 6 + x) = 1;
+
+ if (!m_blink && m_blink_on)
+ for (int y=0; y<7; y++)
+ for (int x=0; x<5; x++)
+ bitmap.pix16(l*9 + y, i * 6 + x) = 1;
+ }
+ }
+
+ return 0;
+
+}
+
+void pc4_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case BUSY_TIMER:
+ m_busy_flag = 0;
+ break;
+
+ case BLINKING_TIMER:
+ m_blink = !m_blink;
+ break;
+ }
+}
+
+WRITE8_MEMBER(pc4_state::lcd_control_w)
+{
+ if (BIT(data, 7))
+ {
+ m_ac_mode = 0;
+ m_cursor_pos = m_ac = data & 0x7f;
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 6))
+ {
+ m_ac_mode = 1;
+ m_ac = data & 0x3f;
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 5))
+ {
+ m_cursor_on = BIT(data, 3);
+
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 4))
+ {
+ UINT8 direct = (BIT(data, 2)) ? +1 : -1;
+
+ if (BIT(data, 3))
+ m_disp_shift += direct;
+ else
+ {
+ m_ac += direct;
+ m_cursor_pos += direct;
+ }
+
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 3))
+ {
+ m_display_on = BIT(data, 2);
+ //m_cursor_on = BIT(data, 1);
+ m_blink_on = BIT(data, 0);
+
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 2))
+ {
+ m_direction = (BIT(data, 1)) ? +1 : -1;
+ m_shift_on = BIT(data, 0);
+ set_busy_flag(37);
+ }
+ else if (BIT(data, 1))
+ {
+ m_ac = 0;
+ m_cursor_pos = 0;
+ m_ac_mode = 0;
+ m_direction = 1;
+ m_disp_shift = 0;
+ set_busy_flag(520);
+ }
+ else if (BIT(data, 0))
+ {
+ m_ac = 0;
+ m_cursor_pos = 0;
+ m_ac_mode = 0;
+ m_direction = 1;
+ m_disp_shift = 0;
+ memset(m_ddram, 0x20, sizeof(m_ddram));
+ set_busy_flag(520);
+ }
+}
+
+
+READ8_MEMBER(pc4_state::lcd_control_r)
+{
+ return m_busy_flag<<7 || m_ac&0x7f;
+}
+
+void pc4_state::update_ac(void)
+{
+ int new_ac = m_ac + m_direction;
+ m_ac = (new_ac < 0) ? 0 : ((new_ac >= 0xa0) ? 0xa0 : new_ac);
+
+ if (m_ac_mode == 0)
+ {
+ m_cursor_pos = m_ac;
+ // display is shifted only after a write
+ if (m_shift_on && m_data_bus_flag == 1) m_disp_shift += m_direction;
+ }
+
+ m_data_bus_flag = 0;
+}
+
+WRITE8_MEMBER( pc4_state::lcd_offset_w )
+{
+ m_cursor_pos = m_ac = (data%0xa0);
+}
+
+
+WRITE8_MEMBER(pc4_state::lcd_data_w)
+{
+ if (m_ac_mode == 0)
+ m_ddram[m_ac] = data;
+ else
+ m_cgram[m_ac] = data;
+
+ update_ac();
+ set_busy_flag(41);
+}
+
+READ8_MEMBER(pc4_state::lcd_data_r)
+{
+ UINT8 data;
+
+ if (m_ac_mode == 0)
+ data = m_ddram[m_ac];
+ else
+ data = m_cgram[m_ac];
+
+ m_data_bus_flag = 2;
+ update_ac();
+ set_busy_flag(41);
+
+ return data;
+}
diff --git a/src/mess/video/pc8401a.c b/src/mess/video/pc8401a.c
new file mode 100644
index 00000000000..85e7d886fe0
--- /dev/null
+++ b/src/mess/video/pc8401a.c
@@ -0,0 +1,114 @@
+#include "includes/pc8401a.h"
+#include "pc8500.lh"
+
+/* PC-8401A */
+
+static PALETTE_INIT( pc8401a )
+{
+ palette_set_color(machine, 0, MAKE_RGB(39, 108, 51));
+ palette_set_color(machine, 1, MAKE_RGB(16, 37, 84));
+}
+
+void pc8401a_state::video_start()
+{
+}
+
+/* PC-8500 */
+
+void pc8500_state::video_start()
+{
+}
+
+UINT32 pc8500_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+// m_lcdc->screen_update(screen, bitmap, cliprect);
+
+ /*
+ if (strcmp(screen.tag(), SCREEN_TAG) == 0)
+ {
+ sed1330_update(m_lcdc, &bitmap, cliprect);
+ }
+ else
+ {
+ m_crtc->update(bitmap, cliprect);
+ }
+ */
+
+ return 0;
+}
+
+/* SED1330 Interface */
+
+static ADDRESS_MAP_START( pc8401a_lcdc, AS_0, 8, pc8401a_state )
+ ADDRESS_MAP_GLOBAL_MASK(0x1fff)
+ AM_RANGE(0x0000, 0x1fff) AM_RAM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pc8500_lcdc, AS_0, 8, pc8401a_state )
+ ADDRESS_MAP_GLOBAL_MASK(0x3fff)
+ AM_RANGE(0x0000, 0x3fff) AM_RAM
+ADDRESS_MAP_END
+
+/* MC6845 Interface */
+
+static MC6845_UPDATE_ROW( pc8441a_update_row )
+{
+}
+
+static const mc6845_interface pc8441a_mc6845_interface =
+{
+ CRT_SCREEN_TAG,
+ 6,
+ NULL,
+ pc8441a_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ NULL
+};
+
+/* Machine Drivers */
+
+MACHINE_CONFIG_FRAGMENT( pc8401a_video )
+// MCFG_DEFAULT_LAYOUT(layout_pc8401a)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(pc8401a)
+
+ /* LCD */
+ MCFG_SCREEN_ADD(SCREEN_TAG, LCD)
+ MCFG_SCREEN_REFRESH_RATE(44)
+ MCFG_SCREEN_UPDATE_DEVICE(SED1330_TAG, sed1330_device, screen_update)
+ MCFG_SCREEN_SIZE(480, 128)
+ MCFG_SCREEN_VISIBLE_AREA(0, 480-1, 0, 128-1)
+
+ MCFG_SED1330_ADD(SED1330_TAG, 0, SCREEN_TAG, pc8401a_lcdc)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( pc8500_video )
+ MCFG_DEFAULT_LAYOUT(layout_pc8500)
+
+ MCFG_PALETTE_LENGTH(2+8)
+ MCFG_PALETTE_INIT(pc8401a)
+
+ /* LCD */
+ MCFG_SCREEN_ADD(SCREEN_TAG, LCD)
+ MCFG_SCREEN_REFRESH_RATE(44)
+ MCFG_SCREEN_UPDATE_DEVICE(SED1330_TAG, sed1330_device, screen_update)
+ MCFG_SCREEN_SIZE(480, 208)
+ MCFG_SCREEN_VISIBLE_AREA(0, 480-1, 0, 200-1)
+
+ MCFG_SED1330_ADD(SED1330_TAG, 0, SCREEN_TAG, pc8500_lcdc)
+
+ /* PC-8441A CRT */
+ MCFG_SCREEN_ADD(CRT_SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(pc8500_state, screen_update)
+ MCFG_SCREEN_SIZE(80*8, 24*8)
+ MCFG_SCREEN_VISIBLE_AREA(0, 80*8-1, 0, 24*8-1)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_REFRESH_RATE(50)
+
+ MCFG_MC6845_ADD(MC6845_TAG, MC6845, 400000, pc8441a_mc6845_interface)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/pc_aga.c b/src/mess/video/pc_aga.c
new file mode 100644
index 00000000000..413d33165cb
--- /dev/null
+++ b/src/mess/video/pc_aga.c
@@ -0,0 +1,879 @@
+/*****************************************************************************
+ *
+ * video/pc_aga.c
+ *
+ ****************************************************************************/
+
+#include "emu.h"
+#include "video/pc_aga.h"
+#include "video/pc_cga.h"
+#include "includes/amstr_pc.h"
+#include "video/mc6845.h"
+#include "video/cgapal.h"
+
+
+#define CGA_MONITOR (space->machine().root_device().ioport("VIDEO")->read() & 0x1C)
+#define CGA_MONITOR_RGB 0x00 /* Colour RGB */
+#define CGA_MONITOR_MONO 0x04 /* Greyscale RGB */
+#define CGA_MONITOR_COMPOSITE 0x08 /* Colour composite */
+#define CGA_MONITOR_TELEVISION 0x0C /* Television */
+#define CGA_MONITOR_LCD 0x10 /* LCD, eg PPC512 */
+
+
+static VIDEO_START( pc_aga );
+static PALETTE_INIT( pc_aga );
+static MC6845_UPDATE_ROW( aga_update_row );
+static WRITE_LINE_DEVICE_HANDLER( aga_hsync_changed );
+static WRITE_LINE_DEVICE_HANDLER( aga_vsync_changed );
+static VIDEO_START( pc200 );
+
+
+static const mc6845_interface mc6845_aga_intf = {
+ AGA_SCREEN_NAME, /* screen number */
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ aga_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_chaged */
+ DEVCB_NULL, /* on_cur_chaged */
+ DEVCB_LINE(aga_hsync_changed), /* on_hsync_changed */
+ DEVCB_LINE(aga_vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+
+static struct {
+ AGA_MODE mode;
+ UINT8 mda_mode_control;
+ UINT8 mda_status;
+ UINT8 *mda_chr_gen;
+
+ UINT8 cga_mode_control;
+ UINT8 cga_color_select;
+ UINT8 cga_status;
+ UINT8 *cga_chr_gen;
+
+ UINT8 pc_framecnt;
+
+ mc6845_update_row_func update_row;
+ UINT8 cga_palette_lut_2bpp[4];
+ UINT8 vsync;
+ UINT8 hsync;
+
+ UINT8 *videoram;
+} aga;
+
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_aga )
+ MCFG_SCREEN_ADD( AGA_SCREEN_NAME, RASTER )
+ MCFG_SCREEN_RAW_PARAMS( XTAL_14_31818MHz,912,0,640,262,0,200 )
+ MCFG_SCREEN_UPDATE_DEVICE( AGA_MC6845_NAME, mc6845_device, screen_update )
+
+ MCFG_PALETTE_LENGTH( CGA_PALETTE_SETS * 16 )
+ MCFG_PALETTE_INIT( pc_aga )
+
+ MCFG_MC6845_ADD( AGA_MC6845_NAME, MC6845, XTAL_14_31818MHz/8, mc6845_aga_intf )
+
+ MCFG_VIDEO_START( pc_aga )
+MACHINE_CONFIG_END
+
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_pc200 )
+ MCFG_FRAGMENT_ADD( pcvideo_aga )
+ MCFG_VIDEO_START( pc200 )
+MACHINE_CONFIG_END
+
+
+/* Initialise the cga palette */
+PALETTE_INIT( pc_aga )
+{
+ int i;
+ for(i = 0; i < CGA_PALETTE_SETS * 16; i++)
+ palette_set_color_rgb(machine, i, cga_palette[i][0], cga_palette[i][1], cga_palette[i][2]);
+}
+
+
+static MC6845_UPDATE_ROW( aga_update_row ) {
+ if ( aga.update_row ) {
+ aga.update_row( device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param );
+ }
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( aga_hsync_changed ) {
+ aga.hsync = state ? 1 : 0;
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( aga_vsync_changed ) {
+ aga.vsync = state ? 8 : 0;
+ if ( state ) {
+ aga.pc_framecnt++;
+ }
+}
+
+
+/*************************************
+ *
+ * row update functions
+ *
+ *************************************/
+
+/* colors need fixing in the mda_text_* functions ! */
+static MC6845_UPDATE_ROW( mda_text_inten_update_row ) {
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 *videoram = aga.videoram;
+ UINT32 *p = &bitmap.pix32(y);
+ UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
+ int i;
+
+ if ( y == 0 ) logerror("mda_text_inten_update_row\n");
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset + 1 ];
+ UINT8 data = aga.mda_chr_gen[ chr_base + chr * 8 ];
+ UINT8 fg = ( attr & 0x08 ) ? 3 : 2;
+ UINT8 bg = 0;
+
+ if ( ( attr & ~0x88 ) == 0 ) {
+ data = 0x00;
+ }
+
+ switch( attr ) {
+ case 0x70:
+ bg = 2;
+ fg = 0;
+ break;
+ case 0x78:
+ bg = 2;
+ fg = 1;
+ break;
+ case 0xF0:
+ bg = 3;
+ fg = 0;
+ break;
+ case 0xF8:
+ bg = 3;
+ fg = 1;
+ break;
+ }
+
+ if ( i == cursor_x || ( attr & 0x07 ) == 0x01 ) {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ if ( ( chr & 0xE0 ) == 0xC0 ) {
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ } else {
+ *p = palette[bg]; p++;
+ }
+ }
+}
+
+
+static MC6845_UPDATE_ROW( mda_text_blink_update_row ) {
+ UINT8 *videoram = aga.videoram;
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
+ int i;
+
+ if ( y == 0 ) logerror("mda_text_blink_update_row\n");
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset + 1 ];
+ UINT8 data = aga.mda_chr_gen[ chr_base + chr * 8 ];
+ UINT8 fg = ( attr & 0x08 ) ? 3 : 2;
+ UINT8 bg = 0;
+
+ if ( ( attr & ~0x88 ) == 0 ) {
+ data = 0x00;
+ }
+
+ switch( attr ) {
+ case 0x70:
+ case 0xF0:
+ bg = 2;
+ fg = 0;
+ break;
+ case 0x78:
+ case 0xF8:
+ bg = 2;
+ fg = 1;
+ break;
+ }
+
+ if ( i == cursor_x ) {
+ data = 0xFF;
+ } else {
+ if ( ( attr & 0x07 ) == 0x01 ) {
+ data = 0xFF;
+ }
+ if ( ( attr & 0x80 ) && ( aga.pc_framecnt & 0x40 ) ) {
+ data = 0x00;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ if ( ( chr & 0xE0 ) == 0xC0 ) {
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ } else {
+ *p = palette[bg]; p++;
+ }
+ }
+}
+
+
+static MC6845_UPDATE_ROW( cga_text_inten_update_row ) {
+ UINT8 *videoram = aga.videoram;
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+
+ if ( y == 0 ) logerror("cga_text_inten_update_row\n");
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = aga.cga_chr_gen[ chr * 16 + ra ];
+ UINT16 fg = attr & 0x0F;
+ UINT16 bg = ( attr >> 4 ) & 0x07;
+
+ if ( i == cursor_x ) {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+static MC6845_UPDATE_ROW( cga_text_inten_alt_update_row ) {
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 *videoram = aga.videoram;
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+
+ if ( y == 0 ) logerror("cga_text_inten_alt_update_row\n");
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = aga.cga_chr_gen[ chr * 16 + ra ];
+ UINT16 fg = attr & 0x0F;
+
+ if ( i == cursor_x ) {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x40 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x20 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x10 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x08 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x04 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x02 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+ }
+}
+
+static MC6845_UPDATE_ROW( cga_text_blink_update_row ) {
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 *videoram = aga.videoram;
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = aga.cga_chr_gen[ chr * 16 + ra ];
+ UINT16 fg = attr & 0x0F;
+ UINT16 bg = (attr >> 4) & 0x07;
+
+ if ( i == cursor_x ) {
+ data = 0xFF;
+ } else {
+ if ( ( attr & 0x80 ) && ( aga.pc_framecnt & 0x10 ) ) {
+ data = 0x00;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+static MC6845_UPDATE_ROW( cga_text_blink_alt_update_row ) {
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 *videoram = aga.videoram;
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+
+ if ( y == 0 ) logerror("cga_text_blink_alt_update_row\n");
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = aga.cga_chr_gen[ chr * 16 + ra ];
+ UINT16 fg = attr & 0x07;
+ UINT16 bg = 0;
+
+ if ( i == cursor_x ) {
+ data = 0xFF;
+ } else {
+ if ( ( attr & 0x80 ) && ( aga.pc_framecnt & 0x10 ) ) {
+ data = 0x00;
+ bg = ( attr >> 4 ) & 0x07;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+static MC6845_UPDATE_ROW( cga_gfx_4bppl_update_row ) {
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 *videoram = aga.videoram;
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+
+ if ( y == 0 ) logerror("cga_gfx_4bppl_update_row\n");
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+
+ data = videoram[ offset + 1 ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ }
+}
+
+static MC6845_UPDATE_ROW( cga_gfx_4bpph_update_row ) {
+ UINT8 *videoram = aga.videoram;
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+
+ if ( y == 0 ) logerror("cga_gfx_4bpph_update_row\n");
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+
+ data = videoram[ offset + 1 ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ }
+}
+
+static MC6845_UPDATE_ROW( cga_gfx_2bpp_update_row ) {
+ UINT8 *videoram = aga.videoram;
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+
+// if ( y == 0 ) logerror("cga_gfx_2bpp_update_row\n");
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[aga.cga_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++;
+ *p = palette[aga.cga_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++;
+ *p = palette[aga.cga_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++;
+ *p = palette[aga.cga_palette_lut_2bpp[ data & 0x03 ]]; p++;
+
+ data = videoram[ offset+1 ];
+
+ *p = palette[aga.cga_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++;
+ *p = palette[aga.cga_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++;
+ *p = palette[aga.cga_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++;
+ *p = palette[aga.cga_palette_lut_2bpp[ data & 0x03 ]]; p++;
+ }
+}
+
+static MC6845_UPDATE_ROW( cga_gfx_1bpp_update_row ) {
+ UINT8 *videoram = aga.videoram;
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT8 fg = aga.cga_color_select & 0x0F;
+ int i;
+
+ if ( y == 0 ) logerror("cga_gfx_1bpp_update_row\n");
+ for ( i = 0; i < x_count; i++ ) {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[( data & 0x80 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x40 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x20 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x10 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x08 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x04 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x02 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+
+ data = videoram[ offset + 1 ];
+
+ *p = palette[( data & 0x80 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x40 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x20 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x10 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x08 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x04 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x02 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+ }
+}
+
+/*************************************
+ *
+ * AGA MDA/CGA read/write handlers
+ *
+ *************************************/
+
+static READ8_HANDLER ( pc_aga_mda_r )
+{
+ UINT8 data = 0xFF;
+
+ if ( aga.mode == AGA_MONO ) {
+ mc6845_device *mc6845 = space->machine().device<mc6845_device>(AGA_MC6845_NAME);
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+ case 1: case 3: case 5: case 7:
+ data = mc6845->register_r(*space, offset);
+ break;
+ case 10:
+ data = (space->machine().root_device().ioport("IN0")->read() & 0x80 ) | 0x08 | aga.mda_status;
+ aga.mda_status ^= 0x01;
+ break;
+ /* 12, 13, 14 are the LPT1 ports */
+ }
+ }
+ return data;
+}
+
+static WRITE8_HANDLER ( pc_aga_mda_w )
+{
+ if ( aga.mode == AGA_MONO ) {
+ mc6845_device *mc6845 = space->machine().device<mc6845_device>(AGA_MC6845_NAME);
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ mc6845->address_w( *space, offset, data );
+ break;
+ case 1: case 3: case 5: case 7:
+ mc6845->register_w( *space, offset, data );
+ break;
+ case 8:
+ aga.mda_mode_control = data;
+
+ switch( aga.mda_mode_control & 0x2a ) {
+ case 0x08:
+ aga.update_row = mda_text_inten_update_row;
+ break;
+ case 0x28:
+ aga.update_row = mda_text_blink_update_row;
+ break;
+ default:
+ aga.update_row = NULL;
+ }
+ break;
+ }
+ }
+}
+
+
+static READ8_HANDLER ( pc_aga_cga_r )
+{
+ UINT8 data = 0xFF;
+
+ if ( aga.mode == AGA_COLOR ) {
+ mc6845_device *mc6845 = space->machine().device<mc6845_device>(AGA_MC6845_NAME);
+ switch( offset ) {
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+ case 1: case 3: case 5: case 7:
+ data = mc6845->register_r( *space, offset);
+ break;
+ case 10:
+ data = aga.vsync | ( ( data & 0x40 ) >> 4 ) | aga.hsync;
+ break;
+ }
+ }
+ return data;
+}
+
+
+static void pc_aga_set_palette_luts(void) {
+ /* Setup 2bpp palette lookup table */
+ if ( aga.cga_mode_control & 0x10 ) {
+ aga.cga_palette_lut_2bpp[0] = 0;
+ } else {
+ aga.cga_palette_lut_2bpp[0] = aga.cga_color_select & 0x0F;
+ }
+ if ( aga.cga_mode_control & 0x04 ) {
+ aga.cga_palette_lut_2bpp[1] = ( ( aga.cga_color_select & 0x10 ) >> 1 ) | 3;
+ aga.cga_palette_lut_2bpp[2] = ( ( aga.cga_color_select & 0x10 ) >> 1 ) | 4;
+ aga.cga_palette_lut_2bpp[3] = ( ( aga.cga_color_select & 0x10 ) >> 1 ) | 7;
+ } else {
+ if ( aga.cga_color_select & 0x20 ) {
+ aga.cga_palette_lut_2bpp[1] = ( ( aga.cga_color_select & 0x10 ) >> 1 ) | 3;
+ aga.cga_palette_lut_2bpp[2] = ( ( aga.cga_color_select & 0x10 ) >> 1 ) | 5;
+ aga.cga_palette_lut_2bpp[3] = ( ( aga.cga_color_select & 0x10 ) >> 1 ) | 7;
+ } else {
+ aga.cga_palette_lut_2bpp[1] = ( ( aga.cga_color_select & 0x10 ) >> 1 ) | 2;
+ aga.cga_palette_lut_2bpp[2] = ( ( aga.cga_color_select & 0x10 ) >> 1 ) | 4;
+ aga.cga_palette_lut_2bpp[3] = ( ( aga.cga_color_select & 0x10 ) >> 1 ) | 6;
+ }
+ }
+ //logerror("2bpp lut set to %d,%d,%d,%d\n", aga.cga_palette_lut_2bpp[0], aga.cga_palette_lut_2bpp[1], aga.cga_palette_lut_2bpp[2], aga.cga_palette_lut_2bpp[3]);
+}
+
+
+static WRITE8_HANDLER ( pc_aga_cga_w )
+{
+ if ( aga.mode == AGA_COLOR ) {
+ mc6845_device *mc6845 = space->machine().device<mc6845_device>(AGA_MC6845_NAME);
+
+ switch(offset) {
+ case 0: case 2: case 4: case 6:
+ mc6845->address_w( *space, offset, data );
+ break;
+ case 1: case 3: case 5: case 7:
+ mc6845->register_w( *space, offset, data );
+ break;
+ case 8:
+ aga.cga_mode_control = data;
+
+ //logerror("mode set to %02X\n", aga.cga_mode_control & 0x3F );
+ switch ( aga.cga_mode_control & 0x3F ) {
+ case 0x08: case 0x09: case 0x0C: case 0x0D:
+ mc6845->set_hpixels_per_column( 8 );
+ aga.update_row = cga_text_inten_update_row;
+ break;
+ case 0x0A: case 0x0B: case 0x2A: case 0x2B:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( CGA_MONITOR == CGA_MONITOR_COMPOSITE ) {
+ aga.update_row = cga_gfx_4bppl_update_row;
+ } else {
+ aga.update_row = cga_gfx_2bpp_update_row;
+ }
+ break;
+ case 0x0E: case 0x0F: case 0x2E: case 0x2F:
+ mc6845->set_hpixels_per_column( 8 );
+ aga.update_row = cga_gfx_2bpp_update_row;
+ break;
+ case 0x18: case 0x19: case 0x1C: case 0x1D:
+ mc6845->set_hpixels_per_column( 8 );
+ aga.update_row = cga_text_inten_alt_update_row;
+ break;
+ case 0x1A: case 0x1B: case 0x3A: case 0x3B:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( CGA_MONITOR == CGA_MONITOR_COMPOSITE ) {
+ aga.update_row = cga_gfx_4bpph_update_row;
+ } else {
+ aga.update_row = cga_gfx_1bpp_update_row;
+ }
+ break;
+ case 0x1E: case 0x1F: case 0x3E: case 0x3F:
+ mc6845->set_hpixels_per_column( 16 );
+ aga.update_row = cga_gfx_1bpp_update_row;
+ break;
+ case 0x28: case 0x29: case 0x2C: case 0x2D:
+ mc6845->set_hpixels_per_column( 8 );
+ aga.update_row = cga_text_blink_update_row;
+ break;
+ case 0x38: case 0x39: case 0x3C: case 0x3D:
+ mc6845->set_hpixels_per_column( 8 );
+ aga.update_row = cga_text_blink_alt_update_row;
+ break;
+ default:
+ aga.update_row = NULL;
+ break;
+ }
+
+ pc_aga_set_palette_luts();
+ break;
+ case 9:
+ aga.cga_color_select = data;
+ pc_aga_set_palette_luts();
+ break;
+ }
+ }
+}
+
+/*************************************/
+
+void pc_aga_set_mode(running_machine &machine, AGA_MODE mode)
+{
+ mc6845_device *mc6845 = machine.device<mc6845_device>(AGA_MC6845_NAME);
+
+ aga.mode = mode;
+
+ switch (aga.mode) {
+ case AGA_COLOR:
+ mc6845->set_clock( XTAL_14_31818MHz/8 );
+ break;
+ case AGA_MONO:
+ mc6845->set_clock( 16257000/9 );
+ break;
+ case AGA_OFF:
+ break;
+ }
+}
+
+
+VIDEO_START( pc_aga )
+{
+ address_space *space = machine.firstcpu->memory().space(AS_PROGRAM);
+ address_space *spaceio = machine.firstcpu->memory().space(AS_IO);
+ int buswidth = machine.firstcpu->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ space->install_legacy_readwrite_handler(0xb0000, 0xbffff, FUNC(pc200_videoram_r), FUNC(pc200_videoram_w) );
+ spaceio->install_legacy_readwrite_handler(0x3b0, 0x3bf, FUNC(pc_aga_mda_r), FUNC(pc_aga_mda_w) );
+ spaceio->install_legacy_readwrite_handler(0x3d0, 0x3df, FUNC(pc_aga_cga_r), FUNC(pc_aga_cga_w) );
+ break;
+
+ case 16:
+ space->install_legacy_readwrite_handler(0xb0000, 0xbffff, FUNC(pc200_videoram_r), FUNC(pc200_videoram_w), 0xffff );
+ spaceio->install_legacy_readwrite_handler(0x3b0, 0x3bf, FUNC(pc_aga_mda_r), FUNC(pc_aga_mda_w), 0xffff );
+ spaceio->install_legacy_readwrite_handler(0x3d0, 0x3df, FUNC(pc_aga_cga_r), FUNC(pc_aga_cga_w), 0xffff );
+ break;
+
+ default:
+ fatalerror("AGA: Bus width %d not supported", buswidth);
+ break;
+ }
+
+ memset( &aga, 0, sizeof( aga ) );
+ aga.mode = AGA_COLOR;
+ aga.mda_chr_gen = machine.root_device().memregion("gfx1")->base() + 0x1000;
+ aga.cga_chr_gen = machine.root_device().memregion("gfx1")->base();
+ aga.videoram = auto_alloc_array(machine, UINT8, 0x10000);
+}
+
+VIDEO_START( pc200 )
+{
+ address_space *space = machine.firstcpu->memory().space(AS_PROGRAM);
+ address_space *spaceio = machine.firstcpu->memory().space(AS_IO);
+ int buswidth = machine.firstcpu->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ space->install_legacy_readwrite_handler(0xb0000, 0xbffff, FUNC(pc_aga_videoram_r), FUNC(pc_aga_videoram_w) );
+ spaceio->install_legacy_readwrite_handler(0x3b0, 0x3bf, FUNC(pc_aga_mda_r), FUNC(pc_aga_mda_w) );
+ spaceio->install_legacy_readwrite_handler(0x3d0, 0x3df, FUNC(pc200_cga_r), FUNC(pc200_cga_w) );
+ break;
+
+ case 16:
+ space->install_legacy_readwrite_handler(0xb0000, 0xbffff, FUNC(pc_aga_videoram_r), FUNC(pc_aga_videoram_w), 0xffff );
+ spaceio->install_legacy_readwrite_handler(0x3b0, 0x3bf, FUNC(pc_aga_mda_r), FUNC(pc_aga_mda_w), 0xffff );
+ spaceio->install_legacy_readwrite_handler(0x3d0, 0x3df, FUNC(pc200_cga_r), FUNC(pc200_cga_w), 0xffff );
+ break;
+
+ default:
+ fatalerror("AGA: Bus width %d not supported", buswidth);
+ break;
+ }
+ memset( &aga, 0, sizeof( aga ) );
+
+ aga.mode = AGA_COLOR;
+ aga.mda_chr_gen = machine.root_device().memregion("gfx1")->base();
+ aga.cga_chr_gen = machine.root_device().memregion("gfx1")->base() + 0x1000;
+ aga.videoram = auto_alloc_array(machine, UINT8, 0x10000);
+}
+
+
+WRITE8_HANDLER ( pc_aga_videoram_w )
+{
+ switch (aga.mode) {
+ case AGA_COLOR:
+ if (offset>=0x8000)
+ aga.videoram[offset-0x8000]=data;
+ break;
+ case AGA_MONO:
+ aga.videoram[offset]=data;
+ break;
+ case AGA_OFF: break;
+ }
+}
+
+ READ8_HANDLER( pc_aga_videoram_r )
+{
+ UINT8 *videoram = aga.videoram;
+ switch (aga.mode) {
+ case AGA_COLOR:
+ if (offset>=0x8000) return videoram[offset-0x8000];
+ return 0;
+ case AGA_MONO:
+ return videoram[offset];
+ case AGA_OFF: break;
+ }
+ return 0;
+}
+
+READ8_HANDLER( pc200_videoram_r )
+{
+ UINT8 *videoram = aga.videoram;
+ switch (aga.mode)
+ {
+ default:
+ if (offset>=0x8000) return videoram[offset-0x8000];
+ return 0;
+ case AGA_MONO:
+ return videoram[offset];
+ }
+ return 0;
+}
+
+WRITE8_HANDLER ( pc200_videoram_w )
+{
+ switch (aga.mode)
+ {
+ default:
+ if (offset>=0x8000)
+ aga.videoram[offset-0x8000]=data;
+ break;
+ case AGA_MONO:
+ aga.videoram[offset]=data;
+ break;
+ }
+}
+
+static struct {
+ UINT8 port8, portd, porte;
+} pc200= { 0 };
+
+// in reality it is of course only 1 graphics adapter,
+// but now cga and mda are splitted in mess
+WRITE8_HANDLER( pc200_cga_w )
+{
+ pc_aga_cga_w(space, offset,data);
+ switch(offset) {
+ case 4:
+ pc200.portd |= 0x20;
+ break;
+ case 8:
+ pc200.port8 = data;
+ pc200.portd |= 0x80;
+ break;
+ case 0xe:
+ pc200.portd = 0x1f;
+ if (data & 0x80)
+ pc200.portd |= 0x40;
+
+/* The bottom 3 bits of this port are:
+ * Bit 2: Disable AGA
+ * Bit 1: Select MDA
+ * Bit 0: Select external display (monitor) rather than internal display
+ * (TV for PC200; LCD for PPC512) */
+ if ((pc200.porte & 7) != (data & 7))
+ {
+ if (data & 4)
+ pc_aga_set_mode(space->machine(), AGA_OFF);
+ else if (data & 2)
+ pc_aga_set_mode(space->machine(), AGA_MONO);
+ else
+ pc_aga_set_mode(space->machine(), AGA_COLOR);
+ }
+ pc200.porte = data;
+ break;
+
+ default:
+ break;
+ }
+}
+
+READ8_HANDLER ( pc200_cga_r )
+{
+ UINT8 result = 0xff;
+
+ switch(offset) {
+ case 8:
+ result = pc200.port8;
+ break;
+
+ case 0xd:
+ // after writing 0x80 to 0x3de, bits 7..5 of 0x3dd from the 2nd read must be 0
+ result=pc200.portd;
+ pc200.portd&=0x1f;
+ break;
+
+ case 0xe:
+ // 0x20 low cga
+ // 0x10 low special
+ result = space->machine().root_device().ioport("DSW0")->read() & 0x38;
+ break;
+
+ default:
+ result = pc_aga_cga_r(space, offset);
+ break;
+ }
+ return result;
+}
diff --git a/src/mess/video/pc_aga.h b/src/mess/video/pc_aga.h
new file mode 100644
index 00000000000..24c8856f669
--- /dev/null
+++ b/src/mess/video/pc_aga.h
@@ -0,0 +1,43 @@
+/*
+ pc cga/mda combi adapters
+
+ one type hardware switchable between cga and mda/hercules
+ another type software switchable between cga and mda/hercules
+
+ some support additional modes like
+ commodore pc10 320x200 in 16 colors
+
+
+ // aga
+ // 256 8x8 thick chars
+ // 256 8x8 thin chars
+ // 256 9x14 in 8x16 chars, line 3 is connected to a10
+ ROM_LOAD("aga.chr", 0x00000, 0x02000, CRC(aca81498))
+ // hercules font of above
+ ROM_LOAD("hercules.chr", 0x00000, 0x1000, CRC(7e8c9d76))
+
+*/
+
+#define AGA_SCREEN_NAME "screen"
+#define AGA_MC6845_NAME "mc6845_aga"
+
+MACHINE_CONFIG_EXTERN( pcvideo_aga );
+MACHINE_CONFIG_EXTERN( pcvideo_pc200 );
+
+
+typedef enum AGA_MODE { AGA_OFF, AGA_COLOR, AGA_MONO } AGA_MODE;
+void pc_aga_set_mode(running_machine &machine, AGA_MODE mode);
+
+READ8_HANDLER( pc_aga_videoram_r );
+WRITE8_HANDLER( pc_aga_videoram_w );
+
+READ8_HANDLER( pc200_videoram_r );
+WRITE8_HANDLER( pc200_videoram_w );
+READ16_HANDLER( pc200_videoram16le_r );
+WRITE16_HANDLER( pc200_videoram16le_w );
+
+READ8_HANDLER( pc200_cga_r );
+WRITE8_HANDLER( pc200_cga_w );
+READ16_HANDLER( pc200_cga16le_r );
+WRITE16_HANDLER( pc200_cga16le_w );
+
diff --git a/src/mess/video/pc_t1t.c b/src/mess/video/pc_t1t.c
new file mode 100644
index 00000000000..06bc703290f
--- /dev/null
+++ b/src/mess/video/pc_t1t.c
@@ -0,0 +1,975 @@
+/***************************************************************************
+
+ IBM PC junior
+ Tandy 1000 Graphics Adapter (T1T) section
+
+ Note that in the IBM PC Junior world, the term 'vga' is not the 'vga' that
+ most people think of
+
+***************************************************************************/
+
+#include "emu.h"
+#include "pc_t1t.h"
+#include "video/mc6845.h"
+#include "machine/pic8259.h"
+#include "machine/ram.h"
+
+/***************************************************************************
+
+ Static declarations
+
+***************************************************************************/
+
+static PALETTE_INIT( pcjr );
+static VIDEO_START( pc_t1t );
+static VIDEO_START( pc_pcjr );
+static MC6845_UPDATE_ROW( t1000_update_row );
+static WRITE_LINE_DEVICE_HANDLER( t1000_de_changed );
+static WRITE_LINE_DEVICE_HANDLER( t1000_vsync_changed );
+static WRITE_LINE_DEVICE_HANDLER( pcjr_vsync_changed );
+
+
+static const mc6845_interface mc6845_t1000_intf = {
+ T1000_SCREEN_NAME, /* screen number */
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ t1000_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_LINE(t1000_de_changed), /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_NULL, /* on_hsync_changed */
+ DEVCB_LINE(t1000_vsync_changed), /* on_vsync_changed */
+ NULL,
+};
+
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_t1000 )
+ MCFG_SCREEN_ADD(T1000_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_14_31818MHz,912,0,640,262,0,200)
+ MCFG_SCREEN_UPDATE_DEVICE( T1000_MC6845_NAME, mc6845_device, screen_update )
+
+ MCFG_PALETTE_LENGTH( 32 )
+ MCFG_PALETTE_INIT(pcjr)
+
+ MCFG_MC6845_ADD(T1000_MC6845_NAME, MC6845, XTAL_14_31818MHz/8, mc6845_t1000_intf)
+
+ MCFG_VIDEO_START(pc_t1t)
+MACHINE_CONFIG_END
+
+
+static const mc6845_interface mc6845_pcjr_intf = {
+ T1000_SCREEN_NAME, /* screen number */
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ t1000_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_LINE(t1000_de_changed), /* on_de_chaged */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_NULL, /* on_hsync_changed */
+ DEVCB_LINE(pcjr_vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_pcjr )
+ MCFG_SCREEN_ADD(T1000_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_14_31818MHz,912,0,640,262,0,200)
+ MCFG_SCREEN_UPDATE_DEVICE( T1000_MC6845_NAME, mc6845_device, screen_update )
+
+ MCFG_PALETTE_LENGTH( 32 )
+ MCFG_PALETTE_INIT(pcjr)
+
+ MCFG_MC6845_ADD(T1000_MC6845_NAME, MC6845, XTAL_14_31818MHz/16, mc6845_pcjr_intf)
+
+ MCFG_VIDEO_START(pc_pcjr)
+MACHINE_CONFIG_END
+
+
+/***************************************************************************
+
+ Methods
+
+***************************************************************************/
+
+/* Initialise the cga palette */
+static PALETTE_INIT( pcjr )
+{
+ const static unsigned char tga_palette[16][3] =
+ {
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xaa }, { 0x00, 0xaa, 0x00 }, { 0x00, 0xaa, 0xaa },
+ { 0xaa, 0x00, 0x00 }, { 0xaa, 0x00, 0xaa }, { 0xaa, 0x55, 0x00 }, { 0xaa, 0xaa, 0xaa },
+ { 0x55, 0x55, 0x55 }, { 0x55, 0x55, 0xff }, { 0x55, 0xff, 0x55 }, { 0x55, 0xff, 0xff },
+ { 0xff, 0x55, 0x55 }, { 0xff, 0x55, 0xff }, { 0xff, 0xff, 0x55 }, { 0xff, 0xff, 0xff }
+ };
+ int i;
+
+ /* colors */
+ for(i = 0; i < 16; i++)
+ palette_set_color_rgb(machine, i, tga_palette[i][0], tga_palette[i][1], tga_palette[i][2]);
+
+ /* b/w mode shades */
+ for(i = 0; i < 16; i++)
+ palette_set_color_rgb( machine, 16+i, ( i << 4 ) | i, ( i << 4 ) | i, ( i << 4 ) | i );
+}
+
+
+static struct
+{
+ UINT8 mode_control, color_select;
+ UINT8 status;
+
+ // used in tandy1000hx; used in pcjr???
+ struct {
+ UINT8 index;
+ UINT8 data[0x20];
+ /* see vgadoc
+ 0 mode control 1
+ 1 palette mask
+ 2 border color
+ 3 mode control 2
+ 4 reset
+ 0x10-0x1f palette registers
+ */
+ } reg;
+
+ UINT8 bank;
+
+ int pc_framecnt;
+
+ UINT8 *displayram;
+ UINT8 *t1_displayram;
+
+ UINT8 *chr_gen;
+ UINT8 chr_size;
+
+ UINT8 address_data_ff;
+
+ mc6845_update_row_func update_row;
+ UINT8 display_enable;
+ UINT8 vsync;
+ UINT8 palette_base;
+} pcjr = { 0 };
+
+
+static MC6845_UPDATE_ROW( t1000_text_inten_update_row )
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+
+ if ( y == 0 ) logerror("t1000_text_inten_update_row\n");
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = pcjr.displayram[ offset ];
+ UINT8 attr = pcjr.displayram[ offset +1 ];
+ UINT8 data = pcjr.chr_gen[ chr * pcjr.chr_size + ra ];
+ UINT16 fg = pcjr.palette_base + ( attr & 0x0F );
+ UINT16 bg = pcjr.palette_base + ( ( attr >> 4 ) & 0x07 );
+
+ if ( i == cursor_x && ( pcjr.pc_framecnt & 0x08 ) )
+ {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+
+static MC6845_UPDATE_ROW( t1000_text_blink_update_row )
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ int i;
+
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = pcjr.displayram[ offset ];
+ UINT8 attr = pcjr.displayram[ offset +1 ];
+ UINT8 data = pcjr.chr_gen[ chr * pcjr.chr_size + ra ];
+ UINT16 fg = pcjr.palette_base + ( attr & 0x0F );
+ UINT16 bg = pcjr.palette_base + ( ( attr >> 4 ) & 0x07 );
+
+ if ( i == cursor_x )
+ {
+ if ( pcjr.pc_framecnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ if ( ( attr & 0x80 ) && ( pcjr.pc_framecnt & 0x10 ) )
+ {
+ data = 0x00;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+
+static MC6845_UPDATE_ROW( t1000_gfx_4bpp_update_row )
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT8 *vid = pcjr.displayram + ( ra << 13 );
+ int i;
+
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x1fff;
+ UINT8 data = vid[ offset ];
+
+ *p = palette[pcjr.palette_base + pcjr.reg.data[0x10 + ( data >> 4 )]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[0x10 + ( data >> 4 )]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[0x10 + ( data & 0x0F )]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[0x10 + ( data & 0x0F )]]; p++;
+
+ data = vid[ offset + 1 ];
+
+ *p = palette[pcjr.palette_base + pcjr.reg.data[0x10 + ( data >> 4 )]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[0x10 + ( data >> 4 )]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[0x10 + ( data & 0x0F )]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[0x10 + ( data & 0x0F )]]; p++;
+ }
+}
+
+
+static MC6845_UPDATE_ROW( t1000_gfx_2bpp_update_row )
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT8 *vid = pcjr.displayram + ( ra << 13 );
+ int i;
+
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x1fff;
+ UINT8 data = vid[ offset ];
+
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( data >> 6 ) & 0x03 ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( data >> 4 ) & 0x03 ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( data >> 2 ) & 0x03 ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( data & 0x03 ) ]]; p++;
+
+ data = vid[ offset+1 ];
+
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( data >> 6 ) & 0x03 ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( data >> 4 ) & 0x03 ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( data >> 2 ) & 0x03 ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( data & 0x03 ) ]]; p++;
+ }
+}
+
+
+static MC6845_UPDATE_ROW( pcjr_gfx_2bpp_high_update_row )
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT8 *vid = pcjr.displayram + ( ra << 13 );
+ int i;
+
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x1fff;
+ UINT8 data0 = vid[ offset ];
+ UINT8 data1 = vid[ offset + 1 ];
+
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( ( data0 & 0x80 ) >> 7 ) | ( ( data1 & 0x80 ) >> 6 ) ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( ( data0 & 0x40 ) >> 6 ) | ( ( data1 & 0x40 ) >> 5 ) ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( ( data0 & 0x20 ) >> 5 ) | ( ( data1 & 0x20 ) >> 4 ) ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( ( data0 & 0x10 ) >> 4 ) | ( ( data1 & 0x10 ) >> 3 ) ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( ( data0 & 0x08 ) >> 3 ) | ( ( data1 & 0x08 ) >> 2 ) ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( ( data0 & 0x04 ) >> 2 ) | ( ( data1 & 0x04 ) >> 1 ) ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( ( data0 & 0x02 ) >> 1 ) | ( ( data1 & 0x02 ) ) ) ]]; p++;
+ *p = palette[pcjr.palette_base + pcjr.reg.data[ 0x10 + ( ( ( data0 & 0x01 ) ) | ( ( data1 & 0x01 ) << 1 ) ) ]]; p++;
+ }
+}
+
+
+static MC6845_UPDATE_ROW( t1000_gfx_2bpp_tga_update_row )
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT8 *vid = pcjr.displayram + ( ra << 13 );
+ int i;
+
+ if ( y == 0 ) logerror("t1000_gfx_2bpp_tga_update_row\n");
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x1fff;
+ UINT8 data = vid[ offset ];
+ UINT16 data2 = ( vid[ offset + 1 ] ) << 1;
+
+ *p = palette[pcjr.reg.data[ 0x10 + ( ( ( data2 & 0x100 ) | ( data & 0x80 ) ) >> 7 ) ]]; p++;
+ *p = palette[pcjr.reg.data[ 0x10 + ( ( ( data2 & 0x80 ) | ( data & 0x40 ) ) >> 6 ) ]]; p++;
+ *p = palette[pcjr.reg.data[ 0x10 + ( ( ( data2 & 0x40 ) | ( data & 0x20 ) ) >> 5 ) ]]; p++;
+ *p = palette[pcjr.reg.data[ 0x10 + ( ( ( data2 & 0x20 ) | ( data & 0x10 ) ) >> 4 ) ]]; p++;
+
+ *p = palette[pcjr.reg.data[ 0x10 + ( ( ( data2 & 0x10 ) | ( data & 0x08 ) ) >> 3 ) ]]; p++;
+ *p = palette[pcjr.reg.data[ 0x10 + ( ( ( data2 & 0x08 ) | ( data & 0x04 ) ) >> 2 ) ]]; p++;
+ *p = palette[pcjr.reg.data[ 0x10 + ( ( ( data2 & 0x04 ) | ( data & 0x02 ) ) >> 1 ) ]]; p++;
+ *p = palette[pcjr.reg.data[ 0x10 + ( ( data2 & 0x02 ) | ( data & 0x01 ) ) ]]; p++;
+ }
+}
+
+
+static MC6845_UPDATE_ROW( t1000_gfx_1bpp_update_row )
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT32 *p = &bitmap.pix32(y);
+ UINT8 *vid = pcjr.displayram + ( ra << 13 );
+ UINT8 fg = pcjr.palette_base + pcjr.reg.data[0x11];
+ UINT8 bg = pcjr.palette_base + pcjr.reg.data[0x10];
+ int i;
+
+ if ( y == 0 ) logerror("t1000_gfx_1bpp_update_row\n");
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x1fff;
+ UINT8 data = vid[ offset ];
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+
+ data = vid[ offset + 1 ];
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ }
+}
+
+
+static MC6845_UPDATE_ROW( t1000_update_row )
+{
+ if ( pcjr.update_row )
+ {
+ pcjr.update_row( device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param );
+ }
+}
+
+
+READ8_HANDLER ( pc_t1t_videoram_r )
+{
+ UINT8 *videoram = pcjr.t1_displayram;
+ int data = 0xff;
+ if( videoram )
+ data = videoram[offset];
+ return data;
+}
+
+WRITE8_HANDLER ( pc_t1t_videoram_w )
+{
+ UINT8 *videoram = pcjr.t1_displayram;
+ if( videoram )
+ videoram[offset] = data;
+}
+
+static void pc_t1t_mode_switch( void )
+{
+ switch( pcjr.mode_control & 0x3B )
+ {
+ case 0x08: case 0x09:
+ pcjr.update_row = t1000_text_inten_update_row;
+ break;
+ case 0x28: case 0x29:
+ pcjr.update_row = t1000_text_blink_update_row;
+ break;
+ case 0x0A: case 0x0B: case 0x2A: case 0x2B:
+ switch( pcjr.bank & 0xc0 )
+ {
+ case 0x00:
+ case 0x40:
+ //logerror("t1t_gfx_2bpp - 1\n");
+ pcjr.update_row = t1000_gfx_2bpp_update_row;
+ if ( pcjr.color_select )
+ {
+ pcjr.reg.data[0x10] = 0x00;
+ pcjr.reg.data[0x11] = 0x0B;
+ pcjr.reg.data[0x12] = 0x0D;
+ pcjr.reg.data[0x13] = 0x0F;
+ }
+ else
+ {
+ pcjr.reg.data[0x10] = 0x00;
+ pcjr.reg.data[0x11] = 0x0A;
+ pcjr.reg.data[0x12] = 0x0C;
+ pcjr.reg.data[0x13] = 0x0E;
+ }
+ break;
+ case 0x80:
+ case 0xc0:
+ //logerror("t1t_gfx_4bpp\n");
+ pcjr.update_row = t1000_gfx_4bpp_update_row;
+ break;
+ }
+ break;
+ case 0x18: case 0x19: case 0x1A: case 0x1B:
+ case 0x38: case 0x39: case 0x3A: case 0x3B:
+ switch( pcjr.bank & 0xc0 )
+ {
+ case 0x00:
+ case 0x40:
+ //logerror("t1t_gfx_1bpp\n");
+ pcjr.update_row = t1000_gfx_1bpp_update_row;
+ break;
+ case 0x80:
+ case 0xc0:
+ //logerror("t1t_gfx_2bpp - 2\n");
+ pcjr.update_row = t1000_gfx_2bpp_tga_update_row;
+ break;
+ }
+ break;
+ default:
+ pcjr.update_row = NULL;
+ break;
+ }
+}
+
+
+/* mode control 1 ( pcjr.reg.data[0] ) */
+/* bit0 - 0 = low bandwidth, 1 = high bandwidth */
+/* bit1 - 0 = alpha, 1 = graphics */
+/* bit2 - 0 = color, 1 = b/w */
+/* bit3 - 0 = video disable, 1 = video enable */
+/* bit4 - 1 = 16 color graphics */
+/* mode control 2 ( pcjr.reg.data[3] ) */
+/* bit1 - 1 = enable blink */
+/* bit3 - 1 = 2 color graphics */
+
+static void pc_pcjr_mode_switch( running_machine &machine )
+{
+ mc6845_device *mc6845 = machine.device<mc6845_device>(T1000_MC6845_NAME);
+
+ switch( pcjr.reg.data[0] & 0x1A )
+ {
+ case 0x08: /* 01x0x */
+ if ( pcjr.reg.data[3] & 0x02 )
+ {
+ pcjr.update_row = t1000_text_blink_update_row;
+ }
+ else
+ {
+ pcjr.update_row = t1000_text_inten_update_row;
+ }
+ break;
+ case 0x0A: /* 01x1x */
+ /* By default use medium resolution mode */
+ pcjr.update_row = t1000_gfx_2bpp_update_row;
+
+ /* Check for high resolution mode */
+ if ( ( pcjr.bank & 0xc0 ) == 0xc0 )
+ pcjr.update_row = pcjr_gfx_2bpp_high_update_row;
+
+ /* Check for 640x200 b/w 2 shades mode */
+ if ( ( pcjr.reg.data[0] & 0x04 ) && ( pcjr.reg.data[3] & 0x08 ) )
+ {
+ pcjr.update_row = t1000_gfx_1bpp_update_row;
+ }
+ break;
+ case 0x18: /* 11x0x - invalid?? */
+ pcjr.update_row = NULL;
+ break;
+ case 0x1A: /* 11x1x */
+ pcjr.update_row = t1000_gfx_4bpp_update_row;
+ break;
+ default:
+ pcjr.update_row = NULL;
+ break;
+ }
+
+ /* Determine mc6845 input clock */
+ if ( pcjr.reg.data[0] & 0x01 )
+ {
+ mc6845->set_clock( XTAL_14_31818MHz/8 );
+ }
+ else
+ {
+ mc6845->set_clock( XTAL_14_31818MHz/16 );
+ }
+
+ /* color or b/w? */
+ pcjr.palette_base = ( pcjr.reg.data[0] & 0x04 ) ? 16 : 0;
+}
+
+
+/*
+ * 3d8 rW T1T mode control register (see #P138)
+ */
+static void pc_t1t_mode_control_w(int data)
+{
+ pcjr.mode_control = data;
+
+ pc_t1t_mode_switch();
+}
+
+static int pc_t1t_mode_control_r(void)
+{
+ int data = pcjr.mode_control;
+ return data;
+}
+
+/*
+ * 3d9 ?W color select register on color adapter
+ */
+static void pc_t1t_color_select_w(int data)
+{
+ if (pcjr.color_select == data)
+ return;
+ pcjr.color_select = data;
+}
+
+static int pc_t1t_color_select_r(void)
+{
+ int data = pcjr.color_select;
+ return data;
+}
+
+/* Bitfields for T1T status register:
+ * Bit(s) Description (Table P179)
+ * 7-6 not used
+ * 5-4 color EGA, color ET4000: diagnose video display feedback, select
+ * from color plane enable
+ * 4 holds current dot being displayed
+ * 3 in vertical retrace
+ * 2 (CGA,color EGA) light pen switch is off
+ * (MCGA,color ET4000) reserved (0)
+ * 1 (CGA,color EGA) positive edge from light pen has set trigger
+ * (MCGA,color ET4000) reserved (0)
+ * 0 display enabled
+ * =0 do not use memory
+ * =1 memory access without interfering with display
+ * (Genoa SuperEGA) horizontal or vertical retrace
+ */
+static int pc_t1t_status_r(void)
+{
+ int data = pcjr.vsync | pcjr.status | pcjr.display_enable;
+ /* HACK HACK HACK */
+ data |= ( pcjr.display_enable ? 0x10 : 0x00 );
+ /* end HACK */
+ return data;
+}
+
+/*
+ * 3db -W light pen strobe reset (on any value)
+ */
+static void pc_t1t_lightpen_strobe_w(int data)
+{
+// pc_port[0x3db] = data;
+}
+
+
+/*
+ * 3da -W (mono EGA/mono VGA) feature control register
+ * (see PORT 03DAh-W for details; VGA, see PORT 03CAh-R)
+ */
+static void pc_t1t_vga_index_w(int data)
+{
+ pcjr.reg.index = data;
+}
+
+static void pc_t1t_vga_data_w(int data)
+{
+ pcjr.reg.data[pcjr.reg.index] = data;
+
+ switch (pcjr.reg.index)
+ {
+ case 0x00: /* mode control 1 */
+ break;
+ case 0x01: /* palette mask (bits 3-0) */
+ break;
+ case 0x02: /* border color (bits 3-0) */
+ break;
+ case 0x03: /* mode control 2 */
+ break;
+ case 0x04: /* reset register */
+ break;
+ /* palette array */
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ pcjr.reg.data[pcjr.reg.index] = data & 0x0F;
+ break;
+ }
+}
+
+
+static void pc_pcjr_vga_data_w(running_machine &machine, int data)
+{
+ pcjr.reg.data[pcjr.reg.index] = data;
+
+ switch (pcjr.reg.index)
+ {
+ case 0x00: /* mode control 1 */
+ /* bit0 - 0 = low bandwidth, 1 = high bandwidth */
+ /* bit1 - 0 = alpha, 1 = graphics */
+ /* bit2 - 0 = color, 1 = b/w */
+ /* bit3 - 0 = video disable, 1 = video enable */
+ /* bit4 - 1 = 16 color graphics */
+ pc_pcjr_mode_switch(machine);
+ break;
+ case 0x01: /* palette mask (bits 3-0) */
+ break;
+ case 0x02: /* border color (bits 3-0) */
+ break;
+ case 0x03: /* mode control 2 */
+ /* bit1 - 1 = enable blink */
+ /* bit3 - 1 = 2 color graphics */
+ pc_pcjr_mode_switch(machine);
+ break;
+ case 0x04: /* reset register */
+ break;
+ /* palette array */
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ pcjr.reg.data[pcjr.reg.index] = data & 0x0F;
+ break;
+ }
+}
+
+
+static int pc_t1t_vga_data_r(void)
+{
+ int data = pcjr.reg.data[pcjr.reg.index];
+
+ switch (pcjr.reg.index)
+ {
+ case 0x00: /* mode control 1 */
+ break;
+ case 0x01: /* palette mask (bits 3-0) */
+ break;
+ case 0x02: /* border color (bits 3-0) */
+ break;
+ case 0x03: /* mode control 2 */
+ break;
+ case 0x04: /* reset register */
+ break;
+ /* palette array */
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ break;
+ }
+ return data;
+}
+
+/*
+ * 3df RW display bank, access bank, mode
+ * bit 0-2 Identifies the page of main memory being displayed in units of 16K.
+ * 0: 0K, 1: 16K...7: 112K. In 32K modes (bits 6-7 = 2) only 0,2,4 and
+ * 6 are valid, as the next page will also be used.
+ * 3-5 Identifies the page of main memory that can be read/written at B8000h
+ * in units of 16K. 0: 0K, 1: 16K...7: 112K. In 32K modes (bits 6-7 = 2)
+ * only 0,2,4 and 6 are valid, as the next page will also be used.
+ * 6-7 Display mode. 0: Text, 1: 16K graphics mode (4,5,6,8)
+ * 2: 32K graphics mode (9,Ah)
+ */
+static void pc_t1t_bank_w(running_machine &machine, int data)
+{
+ if (pcjr.bank != data)
+ {
+ UINT8 *ram = machine.root_device().memregion("maincpu")->base();
+ int dram, vram;
+ pcjr.bank = data;
+ /* it seems the video ram is mapped to the last 128K of main memory */
+#if 1
+ if ((data&0xc0)==0xc0) /* needed for lemmings */
+ {
+ dram = 0x80000 + ((data & 0x06) << 14);
+ vram = 0x80000 + ((data & 0x30) << (14-3));
+ }
+ else
+ {
+ dram = 0x80000 + ((data & 0x07) << 14);
+ vram = 0x80000 + ((data & 0x38) << (14-3));
+ }
+#else
+ dram = (data & 0x07) << 14;
+ vram = (data & 0x38) << (14-3);
+#endif
+ pcjr.t1_displayram = &ram[vram];
+ pcjr.displayram = &ram[dram];
+ pc_t1t_mode_switch();
+ }
+}
+
+
+static void pc_pcjr_bank_w(running_machine &machine, int data)
+{
+ if (pcjr.bank != data)
+ {
+ int dram, vram;
+ pcjr.bank = data;
+ /* it seems the video ram is mapped to the last 128K of main memory */
+ if ((data&0xc0)==0xc0) /* needed for lemmings */
+ {
+ dram = ((data & 0x06) << 14);
+ vram = ((data & 0x30) << (14-3));
+ }
+ else
+ {
+ dram = ((data & 0x07) << 14);
+ vram = ((data & 0x38) << (14-3));
+ }
+ machine.root_device().membank( "bank14" )->set_base( machine.device<ram_device>(RAM_TAG)->pointer() + vram );
+ pcjr.displayram = machine.device<ram_device>(RAM_TAG)->pointer() + dram;
+ pc_pcjr_mode_switch(machine);
+ }
+}
+
+
+static int pc_t1t_bank_r(void)
+{
+ return pcjr.bank;
+}
+
+/*************************************************************************
+ *
+ * T1T
+ * Tandy 1000 / PCjr
+ *
+ *************************************************************************/
+
+WRITE8_HANDLER ( pc_T1T_w )
+{
+ mc6845_device *mc6845;
+
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ mc6845 = space->machine().device<mc6845_device>(T1000_MC6845_NAME);
+ mc6845->address_w( *space, offset, data );
+ break;
+ case 1: case 3: case 5: case 7:
+ mc6845 = space->machine().device<mc6845_device>(T1000_MC6845_NAME);
+ mc6845->register_w( *space, offset, data );
+ break;
+ case 8:
+ pc_t1t_mode_control_w(data);
+ break;
+ case 9:
+ pc_t1t_color_select_w(data);
+ break;
+ case 10:
+ pc_t1t_vga_index_w(data);
+ break;
+ case 11:
+ pc_t1t_lightpen_strobe_w(data);
+ break;
+ case 12:
+ break;
+ case 13:
+ break;
+ case 14:
+ pc_t1t_vga_data_w(data);
+ break;
+ case 15:
+ pc_t1t_bank_w(space->machine(), data);
+ break;
+ }
+}
+
+
+WRITE8_HANDLER( pc_pcjr_w )
+{
+ mc6845_device *mc6845;
+
+ switch( offset )
+ {
+ case 0: case 4:
+ mc6845 = space->machine().device<mc6845_device>(T1000_MC6845_NAME);
+ mc6845->address_w( *space, offset, data );
+ break;
+ case 1: case 5:
+ mc6845 = space->machine().device<mc6845_device>(T1000_MC6845_NAME);
+ mc6845->register_w( *space, offset, data );
+ break;
+ case 10:
+ if ( pcjr.address_data_ff & 0x01 )
+ {
+ pc_pcjr_vga_data_w( space->machine(), data );
+ }
+ else
+ {
+ pc_t1t_vga_index_w( data );
+ }
+ pcjr.address_data_ff ^= 0x01;
+ break;
+ case 11:
+ pc_t1t_lightpen_strobe_w(data);
+ break;
+ case 12:
+ break;
+ case 15:
+ pc_pcjr_bank_w(space->machine(), data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+ READ8_HANDLER ( pc_T1T_r )
+{
+ mc6845_device *mc6845;
+ int data = 0xff;
+
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+
+ case 1: case 3: case 5: case 7:
+ mc6845 = space->machine().device<mc6845_device>(T1000_MC6845_NAME);
+ data = mc6845->register_r( *space, offset );
+ break;
+
+ case 8:
+ data = pc_t1t_mode_control_r();
+ break;
+
+ case 9:
+ data = pc_t1t_color_select_r();
+ break;
+
+ case 10:
+ pcjr.address_data_ff = 0;
+ data = pc_t1t_status_r();
+ break;
+
+ case 11:
+ /* -W lightpen strobe reset */
+ break;
+
+ case 12:
+ case 13:
+ break;
+
+ case 14:
+ data = pc_t1t_vga_data_r();
+ break;
+
+ case 15:
+ data = pc_t1t_bank_r();
+ break;
+ }
+ return data;
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( t1000_de_changed )
+{
+ pcjr.display_enable = state ? 1 : 0;
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( t1000_vsync_changed )
+{
+ pcjr.vsync = state ? 8 : 0;
+ if ( state )
+ {
+ pcjr.pc_framecnt++;
+ }
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( pcjr_vsync_changed )
+{
+ pcjr.vsync = state ? 8 : 0;
+ if ( state )
+ {
+ pcjr.pc_framecnt++;
+ }
+ pic8259_ir5_w(device->machine().device("pic8259"), state);
+}
+
+static VIDEO_START( pc_t1t )
+{
+ int buswidth;
+ address_space *space = machine.firstcpu->memory().space(AS_PROGRAM);
+ address_space *spaceio = machine.firstcpu->memory().space(AS_IO);
+
+ pcjr.chr_gen = machine.root_device().memregion("gfx1")->base();
+ pcjr.update_row = NULL;
+ pcjr.bank = 0;
+ pcjr.chr_size = 16;
+
+ buswidth = machine.firstcpu->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ space->install_legacy_readwrite_handler(0xb8000, 0xbffff, FUNC(pc_t1t_videoram_r), FUNC(pc_t1t_videoram_w) );
+ spaceio->install_legacy_readwrite_handler(0x3d0, 0x3df, FUNC(pc_T1T_r),FUNC(pc_T1T_w) );
+ break;
+
+ case 16:
+ space->install_legacy_readwrite_handler(0xb8000, 0xbffff, FUNC(pc_t1t_videoram_r), FUNC(pc_t1t_videoram_w), 0xffff );
+ spaceio->install_legacy_readwrite_handler(0x3d0, 0x3df, FUNC(pc_T1T_r),FUNC(pc_T1T_w), 0xffff );
+ break;
+
+ default:
+ fatalerror("T1T: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+
+static VIDEO_START( pc_pcjr )
+{
+ int buswidth;
+ address_space *spaceio = machine.firstcpu->memory().space(AS_IO);
+
+ pcjr.chr_gen = machine.root_device().memregion("gfx1")->base();
+ pcjr.update_row = NULL;
+ pcjr.bank = 0;
+ pcjr.mode_control = 0x08;
+ pcjr.chr_size = 8;
+
+ buswidth = machine.firstcpu->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ spaceio->install_legacy_readwrite_handler(0x3d0, 0x3df, FUNC(pc_T1T_r),FUNC(pc_pcjr_w) );
+ break;
+
+ default:
+ fatalerror("PCJR: Bus width %d not supported", buswidth);
+ break;
+ }
+}
diff --git a/src/mess/video/pc_t1t.h b/src/mess/video/pc_t1t.h
new file mode 100644
index 00000000000..f6472d562d8
--- /dev/null
+++ b/src/mess/video/pc_t1t.h
@@ -0,0 +1,10 @@
+#ifndef PC_T1T_H
+#define PC_T1T_H
+
+#define T1000_SCREEN_NAME "screen"
+#define T1000_MC6845_NAME "mc6845_t1000"
+
+MACHINE_CONFIG_EXTERN( pcvideo_t1000 );
+MACHINE_CONFIG_EXTERN( pcvideo_pcjr );
+
+#endif /* PC_T1T_H */
diff --git a/src/mess/video/pcw.c b/src/mess/video/pcw.c
new file mode 100644
index 00000000000..5c1b511422a
--- /dev/null
+++ b/src/mess/video/pcw.c
@@ -0,0 +1,188 @@
+/***************************************************************************
+
+ pcw.c
+
+ Functions to emulate the video hardware of the Amstrad PCW.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/pcw.h"
+#include "machine/ram.h"
+
+INLINE void pcw_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = (UINT16)color;
+}
+
+/***************************************************************************
+ Start the video hardware emulation.
+***************************************************************************/
+
+VIDEO_START( pcw )
+{
+ pcw_state *state = machine.driver_data<pcw_state>();
+ rectangle rect(0, PCW_PRINTER_WIDTH - 1, 0, PCW_PRINTER_HEIGHT - 1);
+
+ state->m_prn_output = auto_bitmap_ind16_alloc(machine,PCW_PRINTER_WIDTH,PCW_PRINTER_HEIGHT);
+ state->m_prn_output->fill(1, rect);
+}
+
+/* two colours */
+static const unsigned short pcw_colour_table[PCW_NUM_COLOURS] =
+{
+ 0, 1
+};
+
+/* black/white */
+static const rgb_t pcw_palette[PCW_NUM_COLOURS] =
+{
+ MAKE_RGB(0x000, 0x000, 0x000),
+ MAKE_RGB(0x0ff, 0x0ff, 0x0ff)
+};
+
+
+/* Initialise the palette */
+PALETTE_INIT( pcw )
+{
+ palette_set_colors(machine, 0, pcw_palette, ARRAY_LENGTH(pcw_palette));
+}
+
+/***************************************************************************
+ Draw the game screen in the given bitmap_ind16.
+ Do NOT call osd_update_display() from this function,
+ it will be called by the main emulation engine.
+***************************************************************************/
+SCREEN_UPDATE_IND16( pcw )
+{
+ pcw_state *state = screen.machine().driver_data<pcw_state>();
+ int x,y,b;
+ unsigned short roller_ram_offs;
+ unsigned char *roller_ram_ptr;
+ int pen0,pen1;
+
+ pen0 = 0;
+ pen1 = 1;
+
+ /* invert? */
+ if (state->m_vdu_video_control_register & (1<<7))
+ {
+ /* yes */
+ pen1^=1;
+ pen0^=1;
+ }
+
+ /* video enable? */
+ if ((state->m_vdu_video_control_register & (1<<6))!=0)
+ {
+ /* render top border */
+ rectangle rect(0, PCW_SCREEN_WIDTH, 0, PCW_BORDER_HEIGHT);
+ bitmap.fill(pen0, rect);
+
+ /* render bottom border */
+ rect.set(0, PCW_SCREEN_WIDTH, PCW_BORDER_HEIGHT + PCW_DISPLAY_HEIGHT, PCW_BORDER_HEIGHT + PCW_DISPLAY_HEIGHT + PCW_BORDER_HEIGHT);
+ bitmap.fill(pen0, rect);
+
+ /* offset to start in table */
+ roller_ram_offs = (state->m_roller_ram_offset<<1);
+
+ for (y=0; y<256; y++)
+ {
+ int by;
+ unsigned short line_data;
+ unsigned char *line_ptr;
+
+ x = PCW_BORDER_WIDTH;
+
+ roller_ram_ptr = screen.machine().device<ram_device>(RAM_TAG)->pointer() + state->m_roller_ram_addr + roller_ram_offs;
+
+ /* get line address */
+ /* b16-14 control which bank the line is to be found in, b13-3 the address in the bank (in 16-byte units), and b2-0 the offset. Thus a roller RAM address bbbxxxxxxxxxxxyyy indicates bank bbb, address 00xxxxxxxxxxx0yyy. */
+ line_data = ((unsigned char *)roller_ram_ptr)[0] | (((unsigned char *)roller_ram_ptr)[1]<<8);
+
+ /* calculate address of pixel data */
+ line_ptr = screen.machine().device<ram_device>(RAM_TAG)->pointer() + ((line_data & 0x0e000)<<1) + ((line_data & 0x01ff8)<<1) + (line_data & 0x07);
+
+ for (by=0; by<90; by++)
+ {
+ unsigned char byte;
+
+ byte = line_ptr[0];
+
+ for (b=0; b<8; b++)
+ {
+ if (byte & 0x080)
+ {
+ pcw_plot_pixel(bitmap,x+b, y+PCW_BORDER_HEIGHT, pen1);
+ }
+ else
+ {
+ pcw_plot_pixel(bitmap,x+b, y+PCW_BORDER_HEIGHT, pen0);
+
+ }
+ byte = byte<<1;
+ }
+
+ x = x + 8;
+
+
+ line_ptr = line_ptr+8;
+ }
+
+ /* update offset, wrap within 512 byte range */
+ roller_ram_offs+=2;
+ roller_ram_offs&=511;
+
+ }
+
+ /* render border */
+ /* 8 pixels either side of display */
+ for (y=0; y<256; y++)
+ {
+ pcw_plot_pixel(bitmap, 0, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, 1, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, 2, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, 3, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, 4, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, 5, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, 6, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, 7, y+PCW_BORDER_HEIGHT, pen0);
+
+ pcw_plot_pixel(bitmap, PCW_BORDER_WIDTH+PCW_DISPLAY_WIDTH+0, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, PCW_BORDER_WIDTH+PCW_DISPLAY_WIDTH+1, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, PCW_BORDER_WIDTH+PCW_DISPLAY_WIDTH+2, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, PCW_BORDER_WIDTH+PCW_DISPLAY_WIDTH+3, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, PCW_BORDER_WIDTH+PCW_DISPLAY_WIDTH+4, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, PCW_BORDER_WIDTH+PCW_DISPLAY_WIDTH+5, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, PCW_BORDER_WIDTH+PCW_DISPLAY_WIDTH+6, y+PCW_BORDER_HEIGHT, pen0);
+ pcw_plot_pixel(bitmap, PCW_BORDER_WIDTH+PCW_DISPLAY_WIDTH+7, y+PCW_BORDER_HEIGHT, pen0);
+ }
+ }
+ else
+ {
+ /* not video - render whole lot in pen 0 */
+ rectangle rect(0, PCW_SCREEN_WIDTH, 0, PCW_SCREEN_HEIGHT);
+ bitmap.fill(pen0, rect);
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( pcw_printer )
+{
+ pcw_state *state = screen.machine().driver_data<pcw_state>();
+
+ // printer output
+ INT32 feed;
+ rectangle rect(0, PCW_PRINTER_WIDTH - 1, 0, PCW_PRINTER_HEIGHT - 1);
+ feed = -(state->m_paper_feed / 2);
+ copyscrollbitmap(bitmap,*state->m_prn_output,0,NULL,1,&feed,rect);
+ bitmap.pix16(PCW_PRINTER_HEIGHT-1, state->m_printer_headpos) = 0;
+ bitmap.pix16(PCW_PRINTER_HEIGHT-2, state->m_printer_headpos) = 0;
+ bitmap.pix16(PCW_PRINTER_HEIGHT-3, state->m_printer_headpos) = 0;
+ bitmap.pix16(PCW_PRINTER_HEIGHT-1, state->m_printer_headpos-1) = 0;
+ bitmap.pix16(PCW_PRINTER_HEIGHT-2, state->m_printer_headpos-1) = 0;
+ bitmap.pix16(PCW_PRINTER_HEIGHT-1, state->m_printer_headpos+1) = 0;
+ bitmap.pix16(PCW_PRINTER_HEIGHT-2, state->m_printer_headpos+1) = 0;
+ return 0;
+}
+
diff --git a/src/mess/video/pcw16.c b/src/mess/video/pcw16.c
new file mode 100644
index 00000000000..16fffc34b5a
--- /dev/null
+++ b/src/mess/video/pcw16.c
@@ -0,0 +1,265 @@
+#include "emu.h"
+#include "includes/pcw16.h"
+#include "machine/ram.h"
+
+
+/* 16 colours, + 1 for border */
+static const unsigned short pcw16_colour_table[PCW16_NUM_COLOURS] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31
+};
+
+static const rgb_t pcw16_palette[PCW16_NUM_COLOURS] =
+{
+ MAKE_RGB(0x080, 0x080, 0x080), /* light grey */
+ MAKE_RGB(0x080, 0x080, 0x080), /* light grey */
+ MAKE_RGB(0x000, 0x080, 0x080), /* magenta */
+ MAKE_RGB(0x000, 0x080, 0x080), /* magenta */
+ MAKE_RGB(0x080, 0x080, 0x080), /* light grey */
+ MAKE_RGB(0x080, 0x080, 0x080), /* light grey */
+ MAKE_RGB(0x0ff, 0x080, 0x080), /* pastel green */
+ MAKE_RGB(0x0ff, 0x080, 0x080), /* pastel green */
+ MAKE_RGB(0x000, 0x000, 0x080), /* blue */
+ MAKE_RGB(0x000, 0x000, 0x000), /* black */
+ MAKE_RGB(0x000, 0x080, 0x0ff), /* mauve */
+ MAKE_RGB(0x000, 0x000, 0x0ff), /* bright blue */
+ MAKE_RGB(0x000, 0x080, 0x000), /* red */
+ MAKE_RGB(0x000, 0x0ff, 0x000), /* bright red */
+ MAKE_RGB(0x000, 0x0ff, 0x080), /* purple */
+ MAKE_RGB(0x000, 0x0ff, 0x0ff), /* bright magenta */
+ MAKE_RGB(0x0ff, 0x000, 0x080), /* sea green */
+ MAKE_RGB(0x0ff, 0x000, 0x0ff), /* bright green */
+ MAKE_RGB(0x0ff, 0x080, 0x0ff), /* pastel cyan */
+ MAKE_RGB(0x0ff, 0x000, 0x0ff), /* bright cyan */
+ MAKE_RGB(0x0ff, 0x080, 0x000), /* lime green */
+ MAKE_RGB(0x0ff, 0x0ff, 0x000), /* bright yellow */
+ MAKE_RGB(0x0ff, 0x0ff, 0x080), /* pastel yellow */
+ MAKE_RGB(0x0ff, 0x0ff, 0x0ff), /* bright white */
+ MAKE_RGB(0x080, 0x000, 0x080), /* cyan */
+ MAKE_RGB(0x080, 0x000, 0x000), /* green */
+ MAKE_RGB(0x080, 0x080, 0x0ff), /* pastel blue */
+ MAKE_RGB(0x080, 0x000, 0x0ff), /* sky blue */
+ MAKE_RGB(0x080, 0x080, 0x000), /* yellow */
+ MAKE_RGB(0x080, 0x0ff, 0x000), /* orange */
+ MAKE_RGB(0x080, 0x0ff, 0x080), /* pink */
+ MAKE_RGB(0x080, 0x0ff, 0x0ff), /* pastel magenta */
+};
+
+
+INLINE void pcw16_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = (UINT16)color;
+}
+
+/* Initialise the palette */
+PALETTE_INIT( pcw16 )
+{
+ palette_set_colors(machine, 0, pcw16_palette, ARRAY_LENGTH(pcw16_palette));
+}
+
+VIDEO_START( pcw16 )
+{
+}
+
+/* 640, 1 bit per pixel */
+static void pcw16_vh_decode_mode0(pcw16_state *state, bitmap_ind16 &bitmap, int x, int y, unsigned char byte)
+{
+ int b;
+ int local_byte;
+ int cols[2];
+ int px;
+
+ local_byte = byte;
+
+ cols[0] = state->m_colour_palette[0];
+ cols[1] = state->m_colour_palette[1];
+
+ px = x;
+ for (b=0; b<8; b++)
+ {
+ pcw16_plot_pixel(bitmap, px, y, cols[(local_byte>>7) & 0x01]);
+ px++;
+
+ local_byte = local_byte<<1;
+ }
+}
+
+/* 320, 2 bits per pixel */
+static void pcw16_vh_decode_mode1(pcw16_state *state, bitmap_ind16 &bitmap, int x, int y, unsigned char byte)
+{
+ int b;
+ int px;
+ int local_byte;
+ int cols[4];
+
+ for (b=0; b<3; b++)
+ {
+ cols[b] = state->m_colour_palette[b];
+ }
+
+ local_byte = byte;
+
+ px = x;
+ for (b=0; b<4; b++)
+ {
+ int col;
+
+ col = cols[((local_byte>>6) & 0x03)];
+
+ pcw16_plot_pixel(bitmap, px, y, col);
+ px++;
+ pcw16_plot_pixel(bitmap, px, y, col);
+ px++;
+
+ local_byte = local_byte<<2;
+ }
+}
+
+/* 160, 4 bits per pixel */
+static void pcw16_vh_decode_mode2(pcw16_state *state, bitmap_ind16 &bitmap, int x, int y, unsigned char byte)
+{
+ int px;
+ int b;
+ int local_byte;
+ int cols[2];
+
+ cols[0] = state->m_colour_palette[0];
+ cols[1] = state->m_colour_palette[1];
+ local_byte = byte;
+
+ px = x;
+ for (b=0; b<2; b++)
+ {
+ int col;
+
+ col = cols[((local_byte>>4)&0x0f)];
+
+ pcw16_plot_pixel(bitmap, px, y, col);
+ px++;
+ pcw16_plot_pixel(bitmap, px, y, col);
+ px++;
+ pcw16_plot_pixel(bitmap, px, y, col);
+ px++;
+ pcw16_plot_pixel(bitmap, px, y, col);
+ px++;
+
+ local_byte = local_byte<<4;
+ }
+}
+
+/***************************************************************************
+ Draw the game screen in the given bitmap_ind16.
+ Do NOT call osd_update_display() from this function,
+ it will be called by the main emulation engine.
+***************************************************************************/
+SCREEN_UPDATE_IND16( pcw16 )
+{
+ pcw16_state *state = screen.machine().driver_data<pcw16_state>();
+ UINT8 *ram = screen.machine().device<ram_device>(RAM_TAG)->pointer();
+ unsigned char *pScanLine = (unsigned char *)ram + 0x0fc00; //0x03c00; //0x020FC00;
+
+ int y;
+ int x;
+
+ int border_colour;
+
+ border_colour = state->m_video_control & 31;
+
+ /* reverse video? */
+ if (state->m_video_control & (1<<7))
+ {
+ /* colour 0 and colour 1 need to be inverted? - what happens in mode 1 and 2 - ignored? or is bit 1 toggled,
+ or is whole lot toggled? */
+
+ /* force border to be colour 1 */
+ border_colour = state->m_colour_palette[1];
+ }
+
+ if ((state->m_video_control & (1<<6))==0)
+ {
+ /* blank */
+ rectangle rect(0, PCW16_SCREEN_WIDTH, 0, PCW16_SCREEN_HEIGHT);
+ bitmap.fill(border_colour, rect);
+ }
+ else
+ {
+ /* no blank */
+
+
+ /* render top border */
+ rectangle rect(0, PCW16_SCREEN_WIDTH, 0, PCW16_BORDER_HEIGHT);
+ bitmap.fill(border_colour, rect);
+
+ /* render bottom border */
+ rect.set(0, PCW16_SCREEN_WIDTH, PCW16_BORDER_HEIGHT + PCW16_DISPLAY_HEIGHT, PCW16_BORDER_HEIGHT + PCW16_DISPLAY_HEIGHT + PCW16_BORDER_HEIGHT);
+ bitmap.fill(border_colour, rect);
+
+ /* render border on either side of display */
+ bitmap.plot_box(0, PCW16_BORDER_HEIGHT, 8, PCW16_DISPLAY_HEIGHT, border_colour);
+ bitmap.plot_box(PCW16_DISPLAY_WIDTH + PCW16_BORDER_WIDTH, PCW16_BORDER_HEIGHT, 8, PCW16_DISPLAY_HEIGHT, border_colour);
+
+ /* render display */
+ for (y=0; y<PCW16_DISPLAY_HEIGHT; y++)
+ {
+ int b;
+ int ScanLineAddr;
+ int Addr;
+ int AddrUpper;
+ int mode;
+
+ /* get line address */
+ ScanLineAddr = (pScanLine[0] & 0x0ff) | ((pScanLine[1] & 0x0ff)<<8);
+
+ /* generate address */
+ Addr = (ScanLineAddr & 0x03fff)<<4;
+
+ /* get upper bits of addr */
+ AddrUpper = Addr & (~0x0ffff);
+
+ /* get mode */
+ mode = ((ScanLineAddr>>14) & 0x03);
+
+ /* set initial x position */
+ x = PCW16_BORDER_WIDTH;
+
+ for (b=0; b<80; b++)
+ {
+ int byte;
+
+ byte = ram[Addr];
+
+ switch (mode)
+ {
+ case 0:
+ {
+ pcw16_vh_decode_mode0(state, bitmap, x, y+PCW16_BORDER_HEIGHT, byte);
+ }
+ break;
+
+ case 1:
+ {
+ pcw16_vh_decode_mode1(state, bitmap, x, y+PCW16_BORDER_HEIGHT, byte);
+ }
+ break;
+
+ case 3:
+ case 2:
+ {
+ pcw16_vh_decode_mode2(state, bitmap, x, y+PCW16_BORDER_HEIGHT, byte);
+ }
+ break;
+ }
+
+ /* only lowest 16 bits are incremented between fetches */
+ Addr = ((Addr+1) & 0x0ffff) | AddrUpper;
+
+ x=x+8;
+ }
+
+ pScanLine+=2;
+ }
+ }
+ return 0;
+}
diff --git a/src/mess/video/pdp1.c b/src/mess/video/pdp1.c
new file mode 100644
index 00000000000..0fc917fd7fd
--- /dev/null
+++ b/src/mess/video/pdp1.c
@@ -0,0 +1,609 @@
+/*
+ video/pdp1.c
+
+ PDP1 video emulation.
+
+ We emulate three display devices:
+ * CRT screen
+ * control panel
+ * typewriter output
+
+ For the actual emulation of these devices look at the machine/pdp1.c. This
+ file only includes the display routines.
+
+ Raphael Nabet 2002-2004
+ Based on earlier work by Chris Salomon
+*/
+
+#include <math.h>
+
+#include "emu.h"
+#include "cpu/pdp1/pdp1.h"
+#include "includes/pdp1.h"
+#include "video/crt.h"
+
+
+
+
+
+
+static void pdp1_draw_panel_backdrop(running_machine &machine, bitmap_ind16 &bitmap);
+static void pdp1_draw_panel(running_machine &machine, bitmap_ind16 &bitmap);
+
+static void pdp1_erase_lightpen(pdp1_state *state, bitmap_ind16 &bitmap);
+static void pdp1_draw_lightpen(pdp1_state *state, bitmap_ind16 &bitmap);
+
+INLINE void pdp1_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = color;
+}
+
+/*
+ video init
+*/
+VIDEO_START( pdp1 )
+{
+ pdp1_state *state = machine.driver_data<pdp1_state>();
+ state->m_typewriter_color = color_typewriter_black;
+
+ /* alloc bitmaps for our private fun */
+ state->m_panel_bitmap.allocate(panel_window_width, panel_window_height, BITMAP_FORMAT_IND16);
+ state->m_typewriter_bitmap.allocate(typewriter_window_width, typewriter_window_height, BITMAP_FORMAT_IND16);
+
+ /* set up out bitmaps */
+ pdp1_draw_panel_backdrop(machine, state->m_panel_bitmap);
+
+ const rectangle typewriter_bitmap_bounds(0, typewriter_window_width-1, 0, typewriter_window_height-1);
+ state->m_typewriter_bitmap.fill(pen_typewriter_bg, typewriter_bitmap_bounds);
+
+ state->m_crt = machine.device("crt");
+}
+
+
+SCREEN_VBLANK( pdp1 )
+{
+ // rising edge
+ if (vblank_on)
+ {
+ pdp1_state *state = screen.machine().driver_data<pdp1_state>();
+
+ crt_eof(state->m_crt);
+ }
+}
+
+/*
+ schedule a pixel to be plotted
+*/
+void pdp1_plot(running_machine &machine, int x, int y)
+{
+ pdp1_state *state = machine.driver_data<pdp1_state>();
+ /* compute pixel coordinates and plot */
+ x = x*crt_window_width/01777;
+ y = y*crt_window_height/01777;
+ crt_plot(state->m_crt, x, y);
+}
+
+
+/*
+ video_update_pdp1: effectively redraw the screen
+*/
+SCREEN_UPDATE_IND16( pdp1 )
+{
+ pdp1_state *state = screen.machine().driver_data<pdp1_state>();
+ pdp1_erase_lightpen(state, bitmap);
+ crt_update(state->m_crt, bitmap);
+ pdp1_draw_lightpen(state, bitmap);
+
+ pdp1_draw_panel(screen.machine(), state->m_panel_bitmap);
+ copybitmap(bitmap, state->m_panel_bitmap, 0, 0, panel_window_offset_x, panel_window_offset_y, cliprect);
+
+ copybitmap(bitmap, state->m_typewriter_bitmap, 0, 0, typewriter_window_offset_x, typewriter_window_offset_y, cliprect);
+ return 0;
+}
+
+
+
+/*
+ Operator control panel code
+*/
+
+enum
+{
+ x_panel_col1_offset = 8,
+ x_panel_col2_offset = x_panel_col1_offset+144+8,
+ x_panel_col3_offset = x_panel_col2_offset+96+8
+};
+
+enum
+{
+ /* column 1: registers, test word, test address */
+ y_panel_pc_offset = 0,
+ y_panel_ma_offset = y_panel_pc_offset+2*8,
+ y_panel_mb_offset = y_panel_ma_offset+2*8,
+ y_panel_ac_offset = y_panel_mb_offset+2*8,
+ y_panel_io_offset = y_panel_ac_offset+2*8,
+ y_panel_ta_offset = y_panel_io_offset+2*8, /* test address and extend switch */
+ y_panel_tw_offset = y_panel_ta_offset+2*8,
+
+ /* column 2: 1-bit indicators */
+ y_panel_run_offset = 8,
+ y_panel_cyc_offset = y_panel_run_offset+8,
+ y_panel_defer_offset = y_panel_cyc_offset+8,
+ y_panel_hs_cyc_offset = y_panel_defer_offset+8,
+ y_panel_brk_ctr_1_offset = y_panel_hs_cyc_offset+8,
+ y_panel_brk_ctr_2_offset = y_panel_brk_ctr_1_offset+8,
+ y_panel_ov_offset = y_panel_brk_ctr_2_offset+8,
+ y_panel_rim_offset = y_panel_ov_offset+8,
+ y_panel_sbm_offset = y_panel_rim_offset+8,
+ y_panel_exd_offset = y_panel_sbm_offset+8,
+ y_panel_ioh_offset = y_panel_exd_offset+8,
+ y_panel_ioc_offset = y_panel_ioh_offset+8,
+ y_panel_ios_offset = y_panel_ioc_offset+8,
+
+ /* column 3: power, single step, single inst, sense, flags, instr... */
+ y_panel_power_offset = 8,
+ y_panel_sngl_step_offset = y_panel_power_offset+8,
+ y_panel_sngl_inst_offset = y_panel_sngl_step_offset+8,
+ y_panel_sep1_offset = y_panel_sngl_inst_offset+8,
+ y_panel_ss_offset = y_panel_sep1_offset+8,
+ y_panel_sep2_offset = y_panel_ss_offset+3*8,
+ y_panel_pf_offset = y_panel_sep2_offset+8,
+ y_panel_ir_offset = y_panel_pf_offset+2*8
+};
+
+/* draw a small 8*8 LED (or is this a lamp? ) */
+static void pdp1_draw_led(running_machine &machine, bitmap_ind16 &bitmap, int x, int y, int state)
+{
+ int xx, yy;
+
+ for (yy=1; yy<7; yy++)
+ for (xx=1; xx<7; xx++)
+ pdp1_plot_pixel(bitmap, x+xx, y+yy, state ? pen_lit_lamp : pen_unlit_lamp);
+}
+
+/* draw nb_bits leds which represent nb_bits bits in value */
+static void pdp1_draw_multipleled(running_machine &machine, bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits)
+{
+ while (nb_bits)
+ {
+ nb_bits--;
+
+ pdp1_draw_led(machine, bitmap, x, y, (value >> nb_bits) & 1);
+
+ x += 8;
+ }
+}
+
+
+/* draw a small 8*8 switch */
+static void pdp1_draw_switch(running_machine &machine, bitmap_ind16 &bitmap, int x, int y, int state)
+{
+ int xx, yy;
+ int i;
+
+ /* erase area */
+ for (yy=0; yy<8; yy++)
+ for (xx=0; xx<8; xx++)
+ pdp1_plot_pixel(bitmap, x+xx, y+yy, pen_panel_bg);
+
+
+ /* draw nut (-> circle) */
+ for (i=0; i<4;i++)
+ {
+ pdp1_plot_pixel(bitmap, x+2+i, y+1, pen_switch_nut);
+ pdp1_plot_pixel(bitmap, x+2+i, y+6, pen_switch_nut);
+ pdp1_plot_pixel(bitmap, x+1, y+2+i, pen_switch_nut);
+ pdp1_plot_pixel(bitmap, x+6, y+2+i, pen_switch_nut);
+ }
+ pdp1_plot_pixel(bitmap, x+2, y+2, pen_switch_nut);
+ pdp1_plot_pixel(bitmap, x+5, y+2, pen_switch_nut);
+ pdp1_plot_pixel(bitmap, x+2, y+5, pen_switch_nut);
+ pdp1_plot_pixel(bitmap, x+5, y+5, pen_switch_nut);
+
+ /* draw button (->disc) */
+ if (! state)
+ y += 4;
+ for (i=0; i<2;i++)
+ {
+ pdp1_plot_pixel(bitmap, x+3+i, y, pen_switch_button);
+ pdp1_plot_pixel(bitmap, x+3+i, y+3, pen_switch_button);
+ }
+ for (i=0; i<4;i++)
+ {
+ pdp1_plot_pixel(bitmap, x+2+i, y+1, pen_switch_button);
+ pdp1_plot_pixel(bitmap, x+2+i, y+2, pen_switch_button);
+ }
+}
+
+
+/* draw nb_bits switches which represent nb_bits bits in value */
+static void pdp1_draw_multipleswitch(running_machine &machine, bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits)
+{
+ while (nb_bits)
+ {
+ nb_bits--;
+
+ pdp1_draw_switch(machine, bitmap, x, y, (value >> nb_bits) & 1);
+
+ x += 8;
+ }
+}
+
+
+/* write a single char on screen */
+static void pdp1_draw_char(running_machine &machine, bitmap_ind16 &bitmap, char character, int x, int y, int color)
+{
+ drawgfx_transpen(bitmap, bitmap.cliprect(), machine.gfx[0], character-32, color, 0, 0,
+ x+1, y, 0);
+}
+
+/* write a string on screen */
+static void pdp1_draw_string(running_machine &machine, bitmap_ind16 &bitmap, const char *buf, int x, int y, int color)
+{
+ while (* buf)
+ {
+ pdp1_draw_char(machine, bitmap, *buf, x, y, color);
+
+ x += 8;
+ buf++;
+ }
+}
+
+
+/*
+ draw the operator control panel (fixed backdrop)
+*/
+static void pdp1_draw_panel_backdrop(running_machine &machine, bitmap_ind16 &bitmap)
+{
+ pdp1_state *state = machine.driver_data<pdp1_state>();
+ /* fill with black */
+ const rectangle panel_bitmap_bounds(0, panel_window_width-1, 0, panel_window_height-1);
+ state->m_panel_bitmap.fill(pen_panel_bg, panel_bitmap_bounds);
+
+ /* column 1: registers, test word, test address */
+ pdp1_draw_string(machine, bitmap, "program counter", x_panel_col1_offset, y_panel_pc_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "memory address", x_panel_col1_offset, y_panel_ma_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "memory buffer", x_panel_col1_offset, y_panel_mb_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "accumulator", x_panel_col1_offset, y_panel_ac_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "in-out", x_panel_col1_offset, y_panel_io_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "extend address", x_panel_col1_offset, y_panel_ta_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "test word", x_panel_col1_offset, y_panel_tw_offset, color_panel_caption);
+
+ /* column separator */
+ bitmap.plot_box(x_panel_col2_offset-4, panel_window_offset_y+8, 1, 96, pen_panel_caption);
+
+ /* column 2: 1-bit indicators */
+ pdp1_draw_string(machine, bitmap, "run", x_panel_col2_offset+8, y_panel_run_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "cycle", x_panel_col2_offset+8, y_panel_cyc_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "defer", x_panel_col2_offset+8, y_panel_defer_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "h. s. cycle", x_panel_col2_offset+8, y_panel_hs_cyc_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "brk. ctr. 1", x_panel_col2_offset+8, y_panel_brk_ctr_1_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "brk. ctr. 2", x_panel_col2_offset+8, y_panel_brk_ctr_2_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "overflow", x_panel_col2_offset+8, y_panel_ov_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "read in", x_panel_col2_offset+8, y_panel_rim_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "seq. break", x_panel_col2_offset+8, y_panel_sbm_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "extend", x_panel_col2_offset+8, y_panel_exd_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "i-o halt", x_panel_col2_offset+8, y_panel_ioh_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "i-o com'ds", x_panel_col2_offset+8, y_panel_ioc_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "i-o sync", x_panel_col2_offset+8, y_panel_ios_offset, color_panel_caption);
+
+ /* column separator */
+ bitmap.plot_box(x_panel_col3_offset-4, panel_window_offset_y+8, 1, 96, pen_panel_caption);
+
+ /* column 3: power, single step, single inst, sense, flags, instr... */
+ pdp1_draw_string(machine, bitmap, "power", x_panel_col3_offset+16, y_panel_power_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "single step", x_panel_col3_offset+16, y_panel_sngl_step_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "single inst.", x_panel_col3_offset+16, y_panel_sngl_inst_offset, color_panel_caption);
+ /* separator */
+ bitmap.plot_box(x_panel_col3_offset+8, y_panel_sep1_offset+4, 96, 1, pen_panel_caption);
+ pdp1_draw_string(machine, bitmap, "sense switches", x_panel_col3_offset, y_panel_ss_offset, color_panel_caption);
+ /* separator */
+ bitmap.plot_box(x_panel_col3_offset+8, y_panel_sep2_offset+4, 96, 1, pen_panel_caption);
+ pdp1_draw_string(machine, bitmap, "program flags", x_panel_col3_offset, y_panel_pf_offset, color_panel_caption);
+ pdp1_draw_string(machine, bitmap, "instruction", x_panel_col3_offset, y_panel_ir_offset, color_panel_caption);
+}
+
+/*
+ draw the operator control panel (dynamic elements)
+*/
+static void pdp1_draw_panel(running_machine &machine, bitmap_ind16 &bitmap)
+{
+ /* column 1: registers, test word, test address */
+ pdp1_draw_multipleled(machine, bitmap, x_panel_col1_offset+16, y_panel_pc_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_PC), 16);
+ pdp1_draw_multipleled(machine, bitmap, x_panel_col1_offset+16, y_panel_ma_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_MA), 16);
+ pdp1_draw_multipleled(machine, bitmap, x_panel_col1_offset, y_panel_mb_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_MB), 18);
+ pdp1_draw_multipleled(machine, bitmap, x_panel_col1_offset, y_panel_ac_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_AC), 18);
+ pdp1_draw_multipleled(machine, bitmap, x_panel_col1_offset, y_panel_io_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_IO), 18);
+ pdp1_draw_switch(machine, bitmap, x_panel_col1_offset, y_panel_ta_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_EXTEND_SW));
+ pdp1_draw_multipleswitch(machine, bitmap, x_panel_col1_offset+16, y_panel_ta_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_TA), 16);
+ pdp1_draw_multipleswitch(machine, bitmap, x_panel_col1_offset, y_panel_tw_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_TW), 18);
+
+ /* column 2: 1-bit indicators */
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_run_offset, cpu_get_reg(machine.device("maincpu"), PDP1_RUN));
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_cyc_offset, cpu_get_reg(machine.device("maincpu"), PDP1_CYC));
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_defer_offset, cpu_get_reg(machine.device("maincpu"), PDP1_DEFER));
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_hs_cyc_offset, 0); /* not emulated */
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_brk_ctr_1_offset, cpu_get_reg(machine.device("maincpu"), PDP1_BRK_CTR) & 1);
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_brk_ctr_2_offset, cpu_get_reg(machine.device("maincpu"), PDP1_BRK_CTR) & 2);
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_ov_offset, cpu_get_reg(machine.device("maincpu"), PDP1_OV));
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_rim_offset, cpu_get_reg(machine.device("maincpu"), PDP1_RIM));
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_sbm_offset, cpu_get_reg(machine.device("maincpu"), PDP1_SBM));
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_exd_offset, cpu_get_reg(machine.device("maincpu"), PDP1_EXD));
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_ioh_offset, cpu_get_reg(machine.device("maincpu"), PDP1_IOH));
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_ioc_offset, cpu_get_reg(machine.device("maincpu"), PDP1_IOC));
+ pdp1_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_ios_offset, cpu_get_reg(machine.device("maincpu"), PDP1_IOS));
+
+ /* column 3: power, single step, single inst, sense, flags, instr... */
+ pdp1_draw_led(machine, bitmap, x_panel_col3_offset, y_panel_power_offset, 1); /* always on */
+ pdp1_draw_switch(machine, bitmap, x_panel_col3_offset+8, y_panel_power_offset, 1); /* always on */
+ pdp1_draw_led(machine, bitmap, x_panel_col3_offset, y_panel_sngl_step_offset, cpu_get_reg(machine.device("maincpu"), PDP1_SNGL_STEP));
+ pdp1_draw_switch(machine, bitmap, x_panel_col3_offset+8, y_panel_sngl_step_offset, cpu_get_reg(machine.device("maincpu"), PDP1_SNGL_STEP));
+ pdp1_draw_led(machine, bitmap, x_panel_col3_offset, y_panel_sngl_inst_offset, cpu_get_reg(machine.device("maincpu"), PDP1_SNGL_INST));
+ pdp1_draw_switch(machine, bitmap, x_panel_col3_offset+8, y_panel_sngl_inst_offset, cpu_get_reg(machine.device("maincpu"), PDP1_SNGL_INST));
+ pdp1_draw_multipleled(machine, bitmap, x_panel_col3_offset, y_panel_ss_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_SS), 6);
+ pdp1_draw_multipleswitch(machine, bitmap, x_panel_col3_offset, y_panel_ss_offset+16, cpu_get_reg(machine.device("maincpu"), PDP1_SS), 6);
+ pdp1_draw_multipleled(machine, bitmap, x_panel_col3_offset, y_panel_pf_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_PF), 6);
+ pdp1_draw_multipleled(machine, bitmap, x_panel_col3_offset, y_panel_ir_offset+8, cpu_get_reg(machine.device("maincpu"), PDP1_IR), 5);
+}
+
+
+/*
+ Typewriter code
+*/
+
+
+
+
+enum
+{
+ typewriter_line_height = 8,
+ typewriter_write_offset_y = typewriter_window_height-typewriter_line_height,
+ typewriter_scroll_step = typewriter_line_height
+};
+
+enum
+{
+ tab_step = 8
+};
+
+
+static void pdp1_typewriter_linefeed(running_machine &machine)
+{
+ pdp1_state *state = machine.driver_data<pdp1_state>();
+ UINT8 buf[typewriter_window_width];
+ int y;
+
+ for (y=0; y<typewriter_window_height-typewriter_scroll_step; y++)
+ {
+ extract_scanline8(state->m_typewriter_bitmap, 0, y+typewriter_scroll_step, typewriter_window_width, buf);
+ draw_scanline8(state->m_typewriter_bitmap, 0, y, typewriter_window_width, buf, machine.pens);
+ }
+
+ const rectangle typewriter_scroll_clear_window(0, typewriter_window_width-1, typewriter_window_height-typewriter_scroll_step, typewriter_window_height-1);
+ state->m_typewriter_bitmap.fill(pen_typewriter_bg, typewriter_scroll_clear_window);
+}
+
+void pdp1_typewriter_drawchar(running_machine &machine, int character)
+{
+ pdp1_state *state = machine.driver_data<pdp1_state>();
+ static const char ascii_table[2][64] =
+ { /* n-s = non-spacing */
+ { /* lower case */
+ ' ', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', '*', '*',
+ '*', '*', '*', '*',
+ '0', '/', 's', 't',
+ 'u', 'v', 'w', 'x',
+ 'y', 'z', '*', ',',
+ '*',/*black*/ '*',/*red*/ '*',/*Tab*/ '*',
+ '\200',/*n-s middle dot*/'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ 'q', 'r', '*', '*',
+ '-', ')', '\201',/*n-s overstrike*/'(',
+ '*', 'a', 'b', 'c',
+ 'd', 'e', 'f', 'g',
+ 'h', 'i', '*',/*Lower Case*/ '.',
+ '*',/*Upper Case*/ '*',/*Backspace*/ '*', '*'/*Carriage Return*/
+ },
+ { /* upper case */
+ ' ', '"', '\'', '~',
+ '\202',/*implies*/ '\203',/*or*/ '\204',/*and*/ '<',
+ '>', '\205',/*up arrow*/ '*', '*',
+ '*', '*', '*', '*',
+ '\206',/*right arrow*/'?', 'S', 'T',
+ 'U', 'V', 'W', 'X',
+ 'Y', 'Z', '*', '=',
+ '*',/*black*/ '*',/*red*/ '*',/*Tab*/ '*',
+ '_',/*n-s???*/ 'J', 'K', 'L',
+ 'M', 'N', 'O', 'P',
+ 'Q', 'R', '*', '*',
+ '+', ']', '|',/*n-s???*/ '[',
+ '*', 'A', 'B', 'C',
+ 'D', 'E', 'F', 'G',
+ 'H', 'I', '*',/*Lower Case*/ '\207',/*multiply*/
+ '*',/*Upper Case*/ '*',/*Backspace*/ '*', '*'/*Carriage Return*/
+ }
+ };
+
+
+
+ character &= 0x3f;
+
+ switch (character)
+ {
+ case 034:
+ /* Black */
+ state->m_typewriter_color = color_typewriter_black;
+ break;
+
+ case 035:
+ /* Red */
+ state->m_typewriter_color = color_typewriter_red;
+ break;
+
+ case 036:
+ /* Tab */
+ state->m_pos = state->m_pos + tab_step - (state->m_pos % tab_step);
+ break;
+
+ case 072:
+ /* Lower case */
+ state->m_case_shift = 0;
+ break;
+
+ case 074:
+ /* Upper case */
+ state->m_case_shift = 1;
+ break;
+
+ case 075:
+ /* Backspace */
+ if (state->m_pos)
+ state->m_pos--;
+ break;
+
+ case 077:
+ /* Carriage Return */
+ state->m_pos = 0;
+ pdp1_typewriter_linefeed(machine);
+ break;
+
+ default:
+ /* Any printable character... */
+
+ if (state->m_pos >= 80)
+ { /* if past right border, wrap around. (Right???) */
+ pdp1_typewriter_linefeed(machine); /* next line */
+ state->m_pos = 0; /* return to start of line */
+ }
+
+ /* print character (lookup ASCII equivalent in table) */
+ pdp1_draw_char(machine, state->m_typewriter_bitmap, ascii_table[state->m_case_shift][character],
+ 8*state->m_pos, typewriter_write_offset_y,
+ state->m_typewriter_color); /* print char */
+
+ if ((character!= 040) && (character!= 056)) /* 040 and 056 are non-spacing characters */
+ state->m_pos++; /* step carriage forward */
+
+ break;
+ }
+}
+
+
+
+/*
+ lightpen code
+*/
+
+void pdp1_update_lightpen_state(running_machine &machine, const lightpen_t *new_state)
+{
+ pdp1_state *state = machine.driver_data<pdp1_state>();
+ state->m_lightpen_state = *new_state;
+}
+
+#if 1
+static void pdp1_draw_circle(bitmap_ind16 &bitmap, int x, int y, int radius, int color_)
+{
+ int interval;
+ int a;
+
+ x = x*crt_window_width/01777;
+ y = y*crt_window_width/01777;
+ radius = radius*crt_window_width/01777;
+
+ interval = ceil(radius/sqrt(2.));
+
+ for (a=0; a<=interval; a++)
+ {
+ int b = sqrt((double)radius*radius-a*a) + .5;
+
+ if ((x-a >= 0) && (y-b >= 0))
+ pdp1_plot_pixel(bitmap, x-a, y-b, color_);
+ if ((x-a >= 0) && (y+b <= crt_window_height-1))
+ pdp1_plot_pixel(bitmap, x-a, y+b, color_);
+ if ((x+a <= crt_window_width-1) && (y-b >= 0))
+ pdp1_plot_pixel(bitmap, x+a, y-b, color_);
+ if ((x+a <= crt_window_width-1) && (y+b <= crt_window_height-1))
+ pdp1_plot_pixel(bitmap, x+a, y+b, color_);
+
+ if ((x-b >= 0) && (y-a >= 0))
+ pdp1_plot_pixel(bitmap, x-b, y-a, color_);
+ if ((x-b >= 0) && (y+a <= crt_window_height-1))
+ pdp1_plot_pixel(bitmap, x-b, y+a, color_);
+ if ((x+b <= crt_window_width-1) && (y-a >= 0))
+ pdp1_plot_pixel(bitmap, x+b, y-a, color_);
+ if ((x+b <= crt_window_width-1) && (y+a <= crt_window_height-1))
+ pdp1_plot_pixel(bitmap, x+b, y+a, color_);
+ }
+}
+#else
+static void pdp1_draw_circle(bitmap_ind16 &bitmap, int x, int y, int radius, int color)
+{
+ float fx, fy;
+ float interval;
+
+
+ fx = (float)x*crt_window_width/01777;
+ fy = (float)y*crt_window_height/01777;
+
+ interval = radius/sqrt(2.);
+
+ for (x=/*ceil*/(fx-interval); x<=fx+interval; x++)
+ {
+ float dy = sqrt(radius*radius-(x-fx)*(x-fx));
+
+ if ((x >= 0) && (x <= crt_window_width-1) && (fy-dy >= 0))
+ pdp1_plot_pixel(bitmap, x, fy-dy, color);
+ if ((x >= 0) && (x <= crt_window_width-1) && (y+dy <= crt_window_height-1))
+ pdp1_plot_pixel(bitmap, x, fy+dy, color);
+ }
+ for (y=/*ceil*/(fy-interval); y<=fy+interval; y++)
+ {
+ float dx = sqrt(radius*radius-(y-fy)*(y-fy));
+
+ if ((fx-dx >= 0) && (y >= 0) && (y <= crt_window_height-1))
+ pdp1_plot_pixel(bitmap, fx-dx, y, color);
+ if ((fx+dx <= crt_window_width-1) && (y >= 0) && (y <= crt_window_height-1))
+ pdp1_plot_pixel(bitmap, fx+dx, y, color);
+ }
+}
+#endif
+
+static void pdp1_erase_lightpen(pdp1_state *state, bitmap_ind16 &bitmap)
+{
+ if (state->m_previous_lightpen_state.active)
+ {
+#if 0
+ if (state->m_previous_lightpen_state.x>0)
+ pdp1_plot_pixel(bitmap, state->m_previous_lightpen_state.x/2-1, state->m_previous_lightpen_state.y/2, pen_black);
+ if (state->m_previous_lightpen_state.x<1023)
+ pdp1_plot_pixel(bitmap, state->m_previous_lightpen_state.x/2+1, state->m_previous_lightpen_state.y/2, pen_black);
+ if (state->m_previous_lightpen_state.y>0)
+ pdp1_plot_pixel(bitmap, state->m_previous_lightpen_state.x/2, state->m_previous_lightpen_state.y/2-1, pen_black);
+ if (state->m_previous_lightpen_state.y<1023)
+ pdp1_plot_pixel(bitmap, state->m_previous_lightpen_state.x/2, state->m_previous_lightpen_state.y/2+1, pen_black);
+#endif
+ pdp1_draw_circle(bitmap, state->m_previous_lightpen_state.x, state->m_previous_lightpen_state.y, state->m_previous_lightpen_state.radius, pen_black);
+ }
+}
+
+static void pdp1_draw_lightpen(pdp1_state *state, bitmap_ind16 &bitmap)
+{
+ if (state->m_lightpen_state.active)
+ {
+ int color_ = state->m_lightpen_state.down ? pen_lightpen_pressed : pen_lightpen_nonpressed;
+#if 0
+ if (state->m_lightpen_state.x>0)
+ pdp1_plot_pixel(bitmap, state->m_lightpen_state.x/2-1, state->m_lightpen_state.y/2, color);
+ if (state->m_lightpen_state.x<1023)
+ pdp1_plot_pixel(bitmap, state->m_lightpen_state.x/2+1, state->m_lightpen_state.y/2, color);
+ if (state->m_lightpen_state.y>0)
+ pdp1_plot_pixel(bitmap, state->m_lightpen_state.x/2, state->m_lightpen_state.y/2-1, color);
+ if (state->m_lightpen_state.y<1023)
+ pdp1_plot_pixel(bitmap, state->m_lightpen_state.x/2, state->m_lightpen_state.y/2+1, color);
+#endif
+ pdp1_draw_circle(bitmap, state->m_lightpen_state.x, state->m_lightpen_state.y, state->m_lightpen_state.radius, color_);
+ }
+ state->m_previous_lightpen_state = state->m_lightpen_state;
+}
diff --git a/src/mess/video/pecom.c b/src/mess/video/pecom.c
new file mode 100644
index 00000000000..f93d862da7e
--- /dev/null
+++ b/src/mess/video/pecom.c
@@ -0,0 +1,121 @@
+/***************************************************************************
+
+ Pecom driver by Miodrag Milanovic
+
+ 08/11/2008 Preliminary driver.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "sound/cdp1869.h"
+#include "sound/wave.h"
+#include "cpu/cosmac/cosmac.h"
+#include "includes/pecom.h"
+
+WRITE8_MEMBER(pecom_state::pecom_cdp1869_w)
+{
+
+ UINT16 ma = m_cdp1802->get_memory_address();
+
+ switch (offset + 3)
+ {
+ case 3:
+ m_cdp1869->out3_w(space, ma, data);
+ break;
+
+ case 4:
+ m_cdp1869->out4_w(space, ma, data);
+ break;
+
+ case 5:
+ m_cdp1869->out5_w(space, ma, data);
+ break;
+
+ case 6:
+ m_cdp1869->out6_w(space, ma, data);
+ break;
+
+ case 7:
+ m_cdp1869->out7_w(space, ma, data);
+ break;
+ }
+}
+
+static ADDRESS_MAP_START( cdp1869_page_ram, AS_0, 8, driver_device )
+ AM_RANGE(0x000, 0x3ff) AM_MIRROR(0x400) AM_RAM
+ADDRESS_MAP_END
+
+static CDP1869_CHAR_RAM_READ( pecom_char_ram_r )
+{
+ pecom_state *state = device->machine().driver_data<pecom_state>();
+
+ UINT8 column = pmd & 0x7f;
+ UINT16 charaddr = (column << 4) | cma;
+
+ return state->m_charram[charaddr];
+}
+
+static CDP1869_CHAR_RAM_WRITE( pecom_char_ram_w )
+{
+ pecom_state *state = device->machine().driver_data<pecom_state>();
+
+ UINT8 column = pmd & 0x7f;
+ UINT16 charaddr = (column << 4) | cma;
+
+ state->m_charram[charaddr] = data;
+}
+
+static CDP1869_PCB_READ( pecom_pcb_r )
+{
+ return BIT(pmd, 7);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( pecom_prd_w )
+{
+ pecom_state *driver_state = device->machine().driver_data<pecom_state>();
+
+ // every other PRD triggers a DMAOUT request
+ if (driver_state->m_dma)
+ {
+ cputag_set_input_line(device->machine(), CDP1802_TAG, COSMAC_INPUT_LINE_DMAOUT, HOLD_LINE);
+ }
+
+ driver_state->m_dma = !driver_state->m_dma;
+}
+
+static CDP1869_INTERFACE( pecom_cdp1869_intf )
+{
+ SCREEN_TAG,
+ CDP1869_COLOR_CLK_PAL,
+ CDP1869_PAL,
+ pecom_pcb_r,
+ pecom_char_ram_r,
+ pecom_char_ram_w,
+ DEVCB_LINE(pecom_prd_w)
+};
+
+static VIDEO_START( pecom )
+{
+ pecom_state *state = machine.driver_data<pecom_state>();
+
+ /* allocate memory */
+ state->m_charram = auto_alloc_array(machine, UINT8, PECOM_CHAR_RAM_SIZE);
+
+ /* register for state saving */
+ state->save_item(NAME(state->m_reset));
+ state->save_item(NAME(state->m_dma));
+ state->save_pointer(NAME(state->m_charram), PECOM_CHAR_RAM_SIZE);
+}
+
+MACHINE_CONFIG_FRAGMENT( pecom_video )
+ MCFG_CDP1869_SCREEN_PAL_ADD(CDP1869_TAG, SCREEN_TAG, CDP1869_DOT_CLK_PAL)
+
+ MCFG_VIDEO_START(pecom)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_CDP1869_ADD(CDP1869_TAG, CDP1869_DOT_CLK_PAL, pecom_cdp1869_intf, cdp1869_page_ram)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+ MCFG_SOUND_WAVE_ADD(WAVE_TAG, CASSETTE_TAG)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/pet.c b/src/mess/video/pet.c
new file mode 100644
index 00000000000..5e10b5be2a2
--- /dev/null
+++ b/src/mess/video/pet.c
@@ -0,0 +1,113 @@
+/***************************************************************************
+
+ commodore pet discrete video circuit
+
+ PeT mess@utanet.at
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/pet.h"
+
+
+void pet_vh_init (running_machine &machine)
+{
+ UINT8 *gfx = machine.root_device().memregion("gfx1")->base();
+ int i;
+
+ /* inversion logic on board */
+ for (i = 0; i < 0x400; i++)
+ {
+ gfx[0x800+i] = gfx[0x400+i];
+ gfx[0x400+i] = gfx[i]^0xff;
+ gfx[0xc00+i] = gfx[0x800+i]^0xff;
+ }
+}
+
+void pet80_vh_init (running_machine &machine)
+{
+ UINT8 *gfx = machine.root_device().memregion("gfx1")->base();
+ int i;
+
+ /* inversion logic on board */
+ for (i = 0; i < 0x400; i++) {
+ gfx[0x800+i] = gfx[0x400+i];
+ gfx[0x400+i] = gfx[i]^0xff;
+ gfx[0x0c00+i] = gfx[0x800+i]^0xff;
+ }
+ // I assume the hardware logic is not displaying line 8 and 9 of char
+ // I draw it like lines would be 8-15 are black!
+ for (i=511; i>=0; i--) {
+ memcpy(gfx+i*16, gfx+i*8, 8);
+ memset(gfx+i*16+8, 0, 8);
+ }
+}
+
+void superpet_vh_init (running_machine &machine)
+{
+ UINT8 *gfx = machine.root_device().memregion("gfx1")->base();
+ int i;
+
+ for (i=0; i<0x400; i++) {
+ gfx[0x1000+i]=gfx[0x800+i];
+ gfx[0x1800+i]=gfx[0xc00+i];
+ gfx[0x1c00+i]=gfx[0x1800+i]^0xff;
+ gfx[0x1400+i]=gfx[0x1000+i]^0xff;
+ gfx[0x800+i]=gfx[0x400+i];
+ gfx[0xc00+i]=gfx[0x800+i]^0xff;
+ gfx[0x400+i]=gfx[i]^0xff;
+ }
+ // I assume the hardware logic is not displaying line 8 and 9 of char
+ // I draw it like lines 8-15 are black!
+ for (i=1023; i>=0; i--) {
+ memcpy(gfx+i*16, gfx+i*8, 8);
+ memset(gfx+i*16+8, 0, 8);
+ }
+}
+
+// commodore pet discrete video circuit
+SCREEN_UPDATE_IND16( pet )
+{
+ pet_state *state = screen.machine().driver_data<pet_state>();
+ UINT8 *videoram = state->m_videoram;
+ int x, y, i;
+
+ for (y=0, i=0; y<25;y++)
+ {
+ for (x=0;x<40;x++, i++)
+ {
+ drawgfx_opaque(bitmap, cliprect,screen.machine().gfx[state->m_font],
+ videoram[i], 0, 0, 0, 8*x,8*y);
+ }
+ }
+ return 0;
+}
+
+
+MC6845_UPDATE_ROW( pet40_update_row )
+{
+ pet_state *state = device->machine().driver_data<pet_state>();
+ UINT8 *videoram = state->m_videoram;
+ int i;
+
+ for( i = 0; i < x_count; i++ ) {
+ drawgfx_opaque( bitmap, cliprect, device->machine().gfx[state->m_font], videoram[(ma+i)&0x3ff], 0, 0, 0, 8 * i, y-ra );
+ }
+}
+
+MC6845_UPDATE_ROW( pet80_update_row )
+{
+ pet_state *state = device->machine().driver_data<pet_state>();
+ UINT8 *videoram = state->m_videoram;
+ int i;
+
+ for( i = 0; i < x_count; i++ ) {
+ drawgfx_opaque( bitmap, cliprect, device->machine().gfx[state->m_font], videoram[((ma+i)<<1)&0x7ff], 0, 0, 0, 16 * i, y-ra );
+ drawgfx_opaque( bitmap, cliprect, device->machine().gfx[state->m_font], videoram[(((ma+i)<<1)+1)&0x7ff], 0, 0, 0, 16 * i + 8, y-ra );
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER( pet_display_enable_changed )
+{
+}
+
diff --git a/src/mess/video/pk8020.c b/src/mess/video/pk8020.c
new file mode 100644
index 00000000000..bbb55d0c138
--- /dev/null
+++ b/src/mess/video/pk8020.c
@@ -0,0 +1,58 @@
+/***************************************************************************
+
+ PK-8020 driver by Miodrag Milanovic
+ based on work of Sergey Erokhin from pk8020.narod.ru
+
+ 18/07/2008 Preliminary driver.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "includes/pk8020.h"
+#include "machine/ram.h"
+
+VIDEO_START( pk8020 )
+{
+}
+
+SCREEN_UPDATE_IND16( pk8020 )
+{
+ pk8020_state *state = screen.machine().driver_data<pk8020_state>();
+ int y, x, b, j;
+ UINT8 *gfx = state->memregion("gfx1")->base();
+ UINT8 *ram = screen.machine().device<ram_device>(RAM_TAG)->pointer();
+
+ for (y = 0; y < 16; y++)
+ {
+ for (x = 0; x < 64; x++)
+ {
+ UINT8 chr = ram[x +(y*64) + 0x40000];
+ UINT8 attr= ram[x +(y*64) + 0x40400];
+ for (j = 0; j < 16; j++) {
+ UINT32 addr = 0x10000 + x + ((y*16+j)*64) + (state->m_video_page * 0xC000);
+ UINT8 code1 = ram[addr];
+ UINT8 code2 = ram[addr + 0x4000];
+ UINT8 code3 = ram[addr + 0x8000];
+ UINT8 code4 = gfx[((chr<<4) + j) + (state->m_font*0x1000)];
+ if (attr) code4 ^= 0xff;
+ for (b = 0; b < 8; b++)
+ {
+ UINT8 col = (((code4 >> b) & 0x01) ? 0x08 : 0x00);
+ col |= (((code3 >> b) & 0x01) ? 0x04 : 0x00);
+ col |= (((code2 >> b) & 0x01) ? 0x02 : 0x00);
+ col |= (((code1 >> b) & 0x01) ? 0x01 : 0x00);
+ bitmap.pix16((y*16)+j, x*8+(7-b)) = col;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+PALETTE_INIT( pk8020 )
+{
+ int i;
+ for(i=0;i<16;i++) {
+ palette_set_color( machine, i, MAKE_RGB(i*0x10,i*0x10,i*0x10) );
+ }
+}
diff --git a/src/mess/video/pmd85.c b/src/mess/video/pmd85.c
new file mode 100644
index 00000000000..7ead1c05c4f
--- /dev/null
+++ b/src/mess/video/pmd85.c
@@ -0,0 +1,66 @@
+/***************************************************************************
+
+ pmd85.c
+
+ Functions to emulate the video hardware of PMD-85.
+
+ Krzysztof Strzecha
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/pmd85.h"
+#include "machine/ram.h"
+
+const unsigned char pmd85_palette[3*3] =
+{
+ 0x00, 0x00, 0x00,
+ 0x7f, 0x7f, 0x7f,
+ 0xff, 0xff, 0xff
+};
+
+PALETTE_INIT( pmd85 )
+{
+ int i;
+
+ for ( i = 0; i < sizeof(pmd85_palette) / 3; i++ ) {
+ palette_set_color_rgb(machine, i, pmd85_palette[i*3], pmd85_palette[i*3+1], pmd85_palette[i*3+2]);
+ }
+}
+
+VIDEO_START( pmd85 )
+{
+}
+
+static void pmd85_draw_scanline(running_machine &machine,bitmap_ind16 &bitmap, int pmd85_scanline)
+{
+ int x, i;
+ int pen0, pen1;
+ UINT8 data;
+
+ /* set up scanline */
+ UINT16 *scanline = &bitmap.pix16(pmd85_scanline);
+
+ /* address of current line in PMD-85 video memory */
+ UINT8* pmd85_video_ram_line = machine.device<ram_device>(RAM_TAG)->pointer() + 0xc000 + 0x40*pmd85_scanline;
+
+ for (x=0; x<288; x+=6)
+ {
+ data = pmd85_video_ram_line[x/6];
+ pen0 = 0;
+ pen1 = data & 0x80 ? 1 : 2;
+
+ for (i=0; i<6; i++)
+ scanline[x+i] = (data & (0x01<<i)) ? pen1 : pen0;
+
+ }
+}
+
+SCREEN_UPDATE_IND16( pmd85 )
+{
+ int pmd85_scanline;
+
+ for (pmd85_scanline=0; pmd85_scanline<256; pmd85_scanline++)
+ pmd85_draw_scanline (screen.machine(),bitmap, pmd85_scanline);
+ return 0;
+}
diff --git a/src/mess/video/pocketc.c b/src/mess/video/pocketc.c
new file mode 100644
index 00000000000..6df0893f631
--- /dev/null
+++ b/src/mess/video/pocketc.c
@@ -0,0 +1,70 @@
+#include "emu.h"
+#include "includes/pocketc.h"
+
+/* PC126x
+ 24x2 5x7 space between char
+ 2000 .. 203b, 2800 .. 283b
+ 2040 .. 207b, 2840 .. 287b
+ 203d: 0 BUSY, 1 PRINT, 3 JAPAN, 4 SMALL, 5 SHIFT, 6 DEF
+ 207c: 1 DEF 1 RAD 2 GRAD 5 ERROR 6 FLAG */
+
+static const UINT8 pocketc_palette[] =
+{
+ 99,107,99,
+ 94,111,103,
+ 255,255,255,
+ 255,255,255,
+ 60, 66, 60,
+ 0, 0, 0
+};
+
+const unsigned short pocketc_colortable[8][2] = {
+ { 5, 4 },
+ { 5, 0 },
+ { 5, 2 },
+ { 4, 5 },
+ { 1, 4 },
+ { 0, 5 },
+ { 1, 5 },
+ { 3, 5 }
+};
+
+PALETTE_INIT( pocketc )
+{
+ UINT8 i=0, r, b, g, color_count = 6;
+
+ machine.colortable = colortable_alloc(machine, color_count);
+
+ while (color_count--)
+ {
+ r = pocketc_palette[i++]; g = pocketc_palette[i++]; b = pocketc_palette[i++];
+ colortable_palette_set_color(machine.colortable, 5 - color_count, MAKE_RGB(r, g, b));
+ }
+
+ for( i = 0; i < 8; i++ )
+ {
+ colortable_entry_set_value(machine.colortable, i*2, pocketc_colortable[i][0]);
+ colortable_entry_set_value(machine.colortable, i*2+1, pocketc_colortable[i][1]);
+ }
+}
+
+
+/* Draw an indicator (DEG, SHIFT, etc) */
+void pocketc_draw_special(bitmap_ind16 &bitmap, int x, int y, const POCKETC_FIGURE fig, int color)
+{
+ int i,j;
+ for (i=0; fig[i]; i++, y++)
+ {
+ for (j=0; fig[i][j]!=0; j++)
+ {
+ switch(fig[i][j])
+ {
+ case '1':
+ bitmap.pix16(y, x+j) = color;
+ break;
+ case 'e':
+ return;
+ }
+ }
+ }
+}
diff --git a/src/mess/video/poly88.c b/src/mess/video/poly88.c
new file mode 100644
index 00000000000..40f7180537b
--- /dev/null
+++ b/src/mess/video/poly88.c
@@ -0,0 +1,103 @@
+/***************************************************************************
+
+ Poly-88 video by Miodrag Milanovic
+
+ 18/05/2009 Initial implementation
+
+****************************************************************************/
+
+#include "emu.h"
+#include "includes/poly88.h"
+
+static const UINT8 mcm6571a_shift[] =
+{
+ 0,1,1,0,0,0,1,0,0,0,0,1,0,0,0,0,
+ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,
+ 1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0
+};
+
+VIDEO_START( poly88 )
+{
+ poly88_state *state = machine.driver_data<poly88_state>();
+ state->m_FNT = state->memregion("chargen")->base();
+}
+
+SCREEN_UPDATE_IND16( poly88 )
+{
+ poly88_state *state = screen.machine().driver_data<poly88_state>();
+ int x,y,j,b;
+ UINT16 addr;
+ int xpos;
+ UINT8 l,r;
+
+ for(y = 0; y < 16; y++ )
+ {
+ addr = y*64;
+ xpos = 0;
+ for(x = 0; x < 64; x++ )
+ {
+ UINT8 code = state->m_video_ram[addr + x];
+ if ((code & 0x80)==0)
+ {
+ for(j = 0; j < 15; j++ )
+ {
+ l = j/5;
+ for(b = 0; b < 10; b++ )
+ {
+ r = b/5;
+ if (l==0 && r==0)
+ bitmap.pix16(y*15+j, xpos+b ) = BIT(code,5) ? 0 : 1;
+
+ if (l==0 && r==1)
+ bitmap.pix16(y*15+j, xpos+b ) = BIT(code,2) ? 0 : 1;
+
+ if (l==1 && r==0)
+ bitmap.pix16(y*15+j, xpos+b ) = BIT(code,4) ? 0 : 1;
+
+ if (l==1 && r==1)
+ bitmap.pix16(y*15+j, xpos+b ) = BIT(code,1) ? 0 : 1;
+
+ if (l==2 && r==0)
+ bitmap.pix16(y*15+j, xpos+b ) = BIT(code,3) ? 0 : 1;
+
+ if (l==2 && r==1)
+ bitmap.pix16(y*15+j, xpos+b ) = BIT(code,0) ? 0 : 1;
+ }
+ }
+ }
+ else
+ {
+ for(j = 0; j < 15; j++ )
+ {
+ code &= 0x7f;
+ l = 0;
+ if (mcm6571a_shift[code]==0)
+ {
+ if (j < 9)
+ l = state->m_FNT[code*16 + j];
+ }
+ else
+ {
+ if ((j > 2) && (j < 12))
+ l = state->m_FNT[code*16 + j - 3];
+ }
+
+ for(b = 0; b < 7; b++ )
+ bitmap.pix16(y*15+j, xpos+b ) = (l >> (6-b)) & 1;
+
+ bitmap.pix16(y*15+j, xpos+7 ) = 0;
+ bitmap.pix16(y*15+j, xpos+8 ) = 0;
+ bitmap.pix16(y*15+j, xpos+9 ) = 0;
+ }
+ }
+ xpos += 10;
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/pp01.c b/src/mess/video/pp01.c
new file mode 100644
index 00000000000..915c4ad791f
--- /dev/null
+++ b/src/mess/video/pp01.c
@@ -0,0 +1,57 @@
+/***************************************************************************
+
+ PP-01 driver by Miodrag Milanovic
+
+ 08/09/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/pp01.h"
+#include "machine/ram.h"
+
+VIDEO_START( pp01 )
+{
+}
+
+SCREEN_UPDATE_IND16( pp01 )
+{
+ pp01_state *state = screen.machine().driver_data<pp01_state>();
+ UINT8 code_r,code_g,code_b;
+ UINT8 col;
+ int y, x, b;
+ UINT8 *ram = screen.machine().device<ram_device>(RAM_TAG)->pointer();
+
+ for (y = 0; y < 256; y++)
+ {
+ for (x = 0; x < 32; x++)
+ {
+ code_r = ram[0x6000 + ((y+state->m_video_scroll)&0xff)*32 + x];
+ code_g = ram[0xa000 + ((y+state->m_video_scroll)&0xff)*32 + x];
+ code_b = ram[0xe000 + ((y+state->m_video_scroll)&0xff)*32 + x];
+ for (b = 0; b < 8; b++)
+ {
+ col = (((code_r >> b) & 0x01) ? 4 : 0) + (((code_g >> b) & 0x01) ? 2 : 0) + (((code_b >> b) & 0x01) ? 1 : 0);
+ bitmap.pix16(y, x*8+(7-b)) = col;
+ }
+ }
+ }
+ return 0;
+}
+
+static const rgb_t pp01_palette[8] = {
+ MAKE_RGB(0x00, 0x00, 0x00), // 0
+ MAKE_RGB(0x00, 0x00, 0x80), // 1
+ MAKE_RGB(0x00, 0x80, 0x00), // 2
+ MAKE_RGB(0x00, 0x80, 0x80), // 3
+ MAKE_RGB(0x80, 0x00, 0x00), // 4
+ MAKE_RGB(0x80, 0x00, 0x80), // 5
+ MAKE_RGB(0x80, 0x80, 0x00), // 6
+ MAKE_RGB(0x80, 0x80, 0x80), // 7
+};
+
+PALETTE_INIT( pp01 )
+{
+ palette_set_colors(machine, 0, pp01_palette, ARRAY_LENGTH(pp01_palette));
+}
diff --git a/src/mess/video/primo.c b/src/mess/video/primo.c
new file mode 100644
index 00000000000..064a1c849e8
--- /dev/null
+++ b/src/mess/video/primo.c
@@ -0,0 +1,46 @@
+/***************************************************************************
+
+ primo.c
+
+ Functions to emulate the video hardware of Primo.
+
+ Krzysztof Strzecha
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/primo.h"
+
+
+
+static void primo_draw_scanline(running_machine &machine,bitmap_ind16 &bitmap, int primo_scanline)
+{
+ primo_state *state = machine.driver_data<primo_state>();
+ int x, i;
+ UINT8 data;
+
+ /* set up scanline */
+ UINT16 *scanline = &bitmap.pix16(primo_scanline);
+
+ /* address of current line in Primo video memory */
+ const UINT8* primo_video_ram_line = (const UINT8*)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_read_ptr(state->m_video_memory_base + 32 * primo_scanline);
+
+ for (x=0; x<256; x+=8)
+ {
+ data = primo_video_ram_line[x/8];
+
+ for (i=0; i<8; i++)
+ scanline[x+i]=(data & (0x80>>i)) ? 1 : 0;
+
+ }
+}
+
+
+SCREEN_UPDATE_IND16( primo )
+{
+ int primo_scanline;
+
+ for (primo_scanline=0; primo_scanline<192; primo_scanline++)
+ primo_draw_scanline(screen.machine(), bitmap, primo_scanline);
+ return 0;
+}
diff --git a/src/mess/video/psion.c b/src/mess/video/psion.c
new file mode 100644
index 00000000000..18801740409
--- /dev/null
+++ b/src/mess/video/psion.c
@@ -0,0 +1,107 @@
+/***************************************************************************
+
+ Psion Organiser II LZ series custom LCD controller
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/psion.h"
+
+// devices
+const device_type PSION_CUSTOM_LCDC = &device_creator<psion_custom_lcdc>;
+
+
+//**************************************************************************
+// live device
+//**************************************************************************
+
+//-------------------------------------------------
+// psion_custom_lcdc - constructor
+//-------------------------------------------------
+
+psion_custom_lcdc::psion_custom_lcdc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ hd44780_device(mconfig, PSION_CUSTOM_LCDC, "Psion Custom LCD Controller", tag, owner, clock)
+{
+}
+
+
+//**************************************************************************
+// device interface
+//**************************************************************************
+
+UINT32 psion_custom_lcdc::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ assert(height*9 <= bitmap.height() && width*6 <= bitmap.width());
+
+ bitmap.fill(0, cliprect);
+
+ if (m_display_on)
+ for (int l=0; l<height; l++)
+ for (int i=0; i<width; i++)
+ {
+ static const UINT8 psion_display_layout[] =
+ {
+ 0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x40, 0x41, 0x42, 0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x44, 0x45, 0x46, 0x47, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
+ };
+
+ INT8 char_pos = psion_display_layout[l*width + i];
+
+ for (int y=0; y<8; y++)
+ for (int x=0; x<5; x++)
+ if (m_ddram[char_pos] <= 0x10)
+ {
+ //draw CGRAM characters
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(m_cgram[(m_ddram[char_pos]&0x07)*8+y], 4-x);
+ }
+ else
+ {
+ //draw CGROM characters
+ if (region()->bytes() <= 0x800)
+ {
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(region()->u8(m_ddram[char_pos]*8+y), 4-x);
+ }
+ else
+ {
+ if(m_ddram[char_pos] < 0xe0)
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(region()->u8(m_ddram[char_pos]*8+y), 4-x);
+ else
+ bitmap.pix16(l*9 + y, i*6 + x) = BIT(region()->u8(0x700+((m_ddram[char_pos]-0xe0)*11)+y), 4-x);
+ }
+ }
+
+ // if is the correct position draw cursor and blink
+ if (char_pos == m_cursor_pos)
+ {
+ //draw the cursor
+ if (m_cursor_on)
+ for (int x=0; x<5; x++)
+ bitmap.pix16(l*9 + 7, i * 6 + x) = 1;
+
+ if (!m_blink && m_blink_on)
+ for (int y=0; y<7; y++)
+ for (int x=0; x<5; x++)
+ bitmap.pix16(l*9 + y, i * 6 + x) = 1;
+ }
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(psion_custom_lcdc::control_write)
+{
+ if (BIT(data, 7)) // Set DDRAM Address
+ {
+ m_ac_mode = 0;
+ m_ac = data & 0x7f;
+ if (data != 0x81)
+ m_cursor_pos = m_ac;
+ set_busy_flag(37);
+ }
+ else
+ hd44780_device::control_write(space, offset, data);
+}
+
+
diff --git a/src/mess/video/radio86.c b/src/mess/video/radio86.c
new file mode 100644
index 00000000000..98ea47de9fe
--- /dev/null
+++ b/src/mess/video/radio86.c
@@ -0,0 +1,129 @@
+/***************************************************************************
+
+ Radio-86RK video driver by Miodrag Milanovic
+
+ 06/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "video/i8275.h"
+#include "includes/radio86.h"
+
+void radio86_state::video_start()
+{
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+}
+
+UINT32 radio86_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+I8275_DISPLAY_PIXELS(radio86_display_pixels)
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ int i;
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ UINT8 *charmap = state->memregion("gfx1")->base();
+ UINT8 pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
+ if (vsp) {
+ pixels = 0;
+ }
+ if (lten) {
+ pixels = 0xff;
+ }
+ if (rvv) {
+ pixels ^= 0xff;
+ }
+ for(i=0;i<6;i++) {
+ bitmap.pix16(y, x + i) = (pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0;
+ }
+}
+
+
+I8275_DISPLAY_PIXELS(mikrosha_display_pixels)
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ int i;
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ UINT8 *charmap = state->memregion("gfx1")->base() + (state->m_mikrosha_font_page & 1) * 0x400;
+ UINT8 pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
+ if (vsp) {
+ pixels = 0;
+ }
+ if (lten) {
+ pixels = 0xff;
+ }
+ if (rvv) {
+ pixels ^= 0xff;
+ }
+ for(i=0;i<6;i++) {
+ bitmap.pix16(y, x + i) = (pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0;
+ }
+}
+
+I8275_DISPLAY_PIXELS(apogee_display_pixels)
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ int i;
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ UINT8 *charmap = state->memregion("gfx1")->base() + (gpa & 1) * 0x400;
+ UINT8 pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
+ if (vsp) {
+ pixels = 0;
+ }
+ if (lten) {
+ pixels = 0xff;
+ }
+ if (rvv) {
+ pixels ^= 0xff;
+ }
+ for(i=0;i<6;i++) {
+ bitmap.pix16(y, x + i) = (pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0;
+ }
+}
+
+I8275_DISPLAY_PIXELS(partner_display_pixels)
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ int i;
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ UINT8 *charmap = state->memregion("gfx1")->base() + 0x400 * (gpa * 2 + hlgt);
+ UINT8 pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
+ if (vsp) {
+ pixels = 0;
+ }
+ if (lten) {
+ pixels = 0xff;
+ }
+ if (rvv) {
+ pixels ^= 0xff;
+ }
+ for(i=0;i<6;i++) {
+ bitmap.pix16(y, x + i) = (pixels >> (5-i)) & 1;
+ }
+}
+
+SCREEN_UPDATE_IND16( radio86 )
+{
+ radio86_state *state = screen.machine().driver_data<radio86_state>();
+ device_t *devconf = screen.machine().device("i8275");
+ i8275_update( devconf, bitmap, cliprect);
+ copybitmap(bitmap, state->m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+static const rgb_t radio86_palette[3] = {
+ MAKE_RGB(0x00, 0x00, 0x00), // black
+ MAKE_RGB(0xa0, 0xa0, 0xa0), // white
+ MAKE_RGB(0xff, 0xff, 0xff) // highlight
+};
+
+PALETTE_INIT( radio86 )
+{
+ palette_set_colors(machine, 0, radio86_palette, ARRAY_LENGTH(radio86_palette));
+}
+
diff --git a/src/mess/video/rm380z.c b/src/mess/video/rm380z.c
new file mode 100644
index 00000000000..2d4298644c4
--- /dev/null
+++ b/src/mess/video/rm380z.c
@@ -0,0 +1,409 @@
+
+/*
+
+RM 380Z video code
+
+*/
+
+
+#include "includes/rm380z.h"
+
+
+void rm380z_state::put_point(int charnum,int x,int y,int col)
+{
+ int mx=3;
+ if (y==6) mx=4;
+
+ for (int r=y;r<(y+mx);r++)
+ {
+ for (int c=x;c<(x+3);c++)
+ {
+ m_graphic_chars[charnum][c+(r*(RM380Z_CHDIMX+1))]=col;
+ }
+ }
+}
+
+void rm380z_state::init_graphic_chars()
+{
+ for (int c=0;c<0x3f;c++)
+ {
+ if (c&0x01) put_point(c,0,0,1);
+ else put_point(c,0,0,0);
+
+ if (c&0x02) put_point(c,3,0,1);
+ else put_point(c,3,0,0);
+
+ if (c&0x04) put_point(c,0,3,1);
+ else put_point(c,0,3,0);
+
+ if (c&0x08) put_point(c,3,3,1);
+ else put_point(c,3,3,0);
+
+ if (c&0x10) put_point(c,0,6,1);
+ else put_point(c,0,6,0);
+
+ if (c&0x20) put_point(c,3,6,1);
+ else put_point(c,3,6,0);
+ }
+}
+
+void rm380z_state::config_videomode()
+{
+ if (m_port0&0x20)
+ {
+ // 80 cols
+ m_videomode=RM380Z_VIDEOMODE_80COL;
+ }
+ else
+ {
+ // 40 cols
+ m_videomode=RM380Z_VIDEOMODE_40COL;
+ }
+
+ if (m_old_videomode!=m_videomode)
+ {
+ m_old_videomode=m_videomode;
+ }
+}
+
+// char attribute bits in COS 4.0
+
+// 0=alternate charset
+// 1=underline
+// 2=dim
+// 3=reverse
+
+
+void rm380z_state::decode_videoram_char(int pos,UINT8& chr,UINT8& attrib)
+{
+ UINT8 ch1=m_vramchars[pos];
+ UINT8 ch2=m_vramattribs[pos];
+
+ // "special" (unknown) cases first
+ if ((ch1==0x80)&&(ch2==0x04))
+ {
+ // blank out
+ chr=0x20;
+ attrib=0;
+ return;
+ }
+ else if ((ch1==0)&&(ch2==8))
+ {
+ // cursor
+ chr=0x20;
+ attrib=8;
+ return;
+ }
+ else if ((ch1==0)&&(ch2==0))
+ {
+ // delete char (?)
+ chr=0x20;
+ attrib=0;
+ return;
+ }
+ else if ((ch1==4)&&(ch2==4))
+ {
+ // reversed cursor?
+ chr=0x20;
+ attrib=0;
+ return;
+ }
+ else if ((ch1==4)&&(ch2==8))
+ {
+ // normal cursor
+ chr=0x20;
+ attrib=8;
+ return;
+ }
+ else
+ {
+ chr=ch1;
+ attrib=ch2;
+
+ //printf("unhandled character combination [%x][%x]\n",ch1,ch2);
+ }
+}
+
+void rm380z_state::scroll_videoram()
+{
+ rm380z_state *state = machine().driver_data<rm380z_state>();
+
+ int lineWidth=0x80;
+ if (m_videomode==RM380Z_VIDEOMODE_40COL)
+ {
+ lineWidth=0x40;
+ }
+
+ // scroll up one row of videoram
+
+ for (int row=1;row<RM380Z_SCREENROWS;row++)
+ {
+ for (int c=0;c<lineWidth;c++)
+ {
+ int sourceaddr=(row*lineWidth)+c;
+ int destaddr=((row-1)*lineWidth)+c;
+
+ state->m_vram[destaddr]=state->m_vram[sourceaddr];
+ state->m_vramchars[destaddr]=state->m_vramchars[sourceaddr];
+ state->m_vramattribs[destaddr]=state->m_vramattribs[sourceaddr];
+ }
+ }
+
+ // the last line is filled with spaces
+
+ for (int c=0;c<lineWidth;c++)
+ {
+ state->m_vram[((RM380Z_SCREENROWS-1)*lineWidth)+c]=0x20;
+ state->m_vramchars[((RM380Z_SCREENROWS-1)*lineWidth)+c]=0x20;
+ state->m_vramattribs[((RM380Z_SCREENROWS-1)*lineWidth)+c]=0x00;
+ }
+}
+
+void rm380z_state::check_scroll_register()
+{
+ UINT8 r[3];
+
+ r[0]=m_old_old_fbfd;
+ r[1]=m_old_fbfd;
+ r[2]=m_fbfd;
+
+ if ( ((r[1]&0x20)==0) && ((r[2]&0x20)==0) )
+ {
+ // it's a scroll command
+
+ if (r[2]>r[1])
+ {
+ scroll_videoram();
+ }
+ else if ((r[2]==0x00)&&(r[1]==0x17))
+ {
+ // wrap-scroll
+ scroll_videoram();
+ }
+
+ }
+}
+
+// after ctrl-L (clear screen?): routine at EBBD is executed
+// EB30??? next line?
+// memory at FF02 seems to hold the line counter (same as FBFD)
+//
+// basics:
+// 20e2: prints "Ready:"
+// 0195: prints "\n"
+
+WRITE8_MEMBER( rm380z_state::videoram_write )
+{
+ rm380z_state *state = machine().driver_data<rm380z_state>();
+
+ //printf("vramw [%2.2x][%2.2x] port0 [%2.2x] fbfd [%2.2x] fbfe [%2.2x] PC [%4.4x]\n",offset,data,state->m_port0,m_fbfd,m_fbfe,cpu_get_pc(machine().device("maincpu")));
+
+ int lineWidth=0x80;
+ if (m_videomode==RM380Z_VIDEOMODE_40COL)
+ {
+ lineWidth=0x40;
+ }
+
+ int rowadder=(m_fbfe&0x0f)*2;
+ if (m_videomode==RM380Z_VIDEOMODE_40COL) rowadder=0; // FBFE register is not used in VDU-40
+
+ int lineAdder=rowadder*lineWidth;
+ int realA=(offset+lineAdder);
+
+ // we suppose videoram is being written as character/attribute couple
+ // fbfc 6th bit set=attribute, unset=char
+
+ if (!(state->m_port0&0x40))
+ {
+ m_vramchars[realA%RM380Z_SCREENSIZE]=data;
+ }
+ else
+ {
+ m_vramattribs[realA%RM380Z_SCREENSIZE]=data;
+ }
+
+ //
+
+ state->m_mainVideoram[offset]=data;
+}
+
+READ8_MEMBER( rm380z_state::videoram_read )
+{
+ rm380z_state *state = machine().driver_data<rm380z_state>();
+ return state->m_mainVideoram[offset];
+}
+
+void rm380z_state::putChar(int charnum,int attribs,int x,int y,bitmap_ind16 &bitmap,unsigned char* chsb,int vmode)
+{
+ //bool attrDim=false;
+ bool attrRev=false;
+ bool attrUnder=false;
+
+ if (attribs&0x02) attrUnder=true;
+ //if (attribs&0x04) attrDim=true;
+ if (attribs&0x08) attrRev=true;
+
+ if ((charnum>0)&&(charnum<=0x7f))
+ {
+ // normal chars (base set)
+
+ if (vmode==RM380Z_VIDEOMODE_80COL)
+ {
+ int basex=RM380Z_CHDIMX*(charnum/RM380Z_NCY);
+ int basey=RM380Z_CHDIMY*(charnum%RM380Z_NCY);
+
+ for (int r=0;r<RM380Z_CHDIMY;r++)
+ {
+ for (int c=0;c<RM380Z_CHDIMX;c++)
+ {
+ UINT8 chval=(chsb[((basey+r)*(RM380Z_CHDIMX*RM380Z_NCX))+(basex+c)])==0xff?0:1;
+
+ if (attrRev)
+ {
+ if (chval==0) chval=1;
+ else chval=0;
+ }
+
+ if (attrUnder)
+ {
+ if (r==(RM380Z_CHDIMY-1))
+ {
+ if (attrRev) chval=0;
+ else chval=1;
+ }
+ }
+
+ UINT16 *dest=&bitmap.pix16((y*(RM380Z_CHDIMY+1))+r,(x*(RM380Z_CHDIMX+1))+c);
+ *dest=chval;
+ }
+ }
+
+ // last pixel of underline
+ if (attrUnder&&(!attrRev))
+ {
+ UINT16 *dest=&bitmap.pix16((y*(RM380Z_CHDIMY+1))+(RM380Z_CHDIMY-1),(x*(RM380Z_CHDIMX+1))+RM380Z_CHDIMX);
+ *dest=attrRev?0:1;
+ }
+
+ // if reversed, print another column of pixels on the right
+ if (attrRev)
+ {
+ for (int r=0;r<RM380Z_CHDIMY;r++)
+ {
+ UINT16 *dest=&bitmap.pix16((y*(RM380Z_CHDIMY+1))+r,(x*(RM380Z_CHDIMX+1))+RM380Z_CHDIMX);
+ *dest=1;
+ }
+ }
+ }
+ else if (vmode==RM380Z_VIDEOMODE_40COL)
+ {
+ int basex=RM380Z_CHDIMX*(charnum/RM380Z_NCY);
+ int basey=RM380Z_CHDIMY*(charnum%RM380Z_NCY);
+
+ for (int r=0;r<RM380Z_CHDIMY;r++)
+ {
+ for (int c=0;c<(RM380Z_CHDIMX*2);c+=2)
+ {
+ UINT8 chval=(chsb[((basey+r)*(RM380Z_CHDIMX*RM380Z_NCX))+(basex+(c/2))])==0xff?0:1;
+
+ if (attrRev)
+ {
+ if (chval==0) chval=1;
+ else chval=0;
+ }
+
+ if (attrUnder)
+ {
+ if (r==(RM380Z_CHDIMY-1))
+ {
+ if (attrRev) chval=0;
+ else chval=1;
+ }
+ }
+
+ UINT16 *dest=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c);
+ UINT16 *dest2=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c+1);
+ *dest=chval;
+ *dest2=chval;
+ }
+ }
+
+ // last 2 pixels of underline
+ if (attrUnder)
+ {
+ UINT16 *dest=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+RM380Z_CHDIMY-1 , ((x*(RM380Z_CHDIMX+1))*2)+(RM380Z_CHDIMX*2));
+ UINT16 *dest2=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+RM380Z_CHDIMY-1 , ((x*(RM380Z_CHDIMX+1))*2)+(RM380Z_CHDIMX*2)+1);
+ *dest=attrRev?0:1;
+ *dest2=attrRev?0:1;
+ }
+
+ // if reversed, print another 2 columns of pixels on the right
+ if (attrRev)
+ {
+ for (int r=0;r<RM380Z_CHDIMY;r++)
+ {
+ UINT16 *dest=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+((RM380Z_CHDIMX)*2));
+ UINT16 *dest2=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+((RM380Z_CHDIMX)*2)+1);
+ *dest=1;
+ *dest2=1;
+ }
+ }
+ }
+ }
+ else
+ {
+ // graphic chars: 0x80-0xbf is "dimmed", 0xc0-0xff is full bright
+ if (vmode==RM380Z_VIDEOMODE_80COL)
+ {
+ for (int r=0;r<(RM380Z_CHDIMY+1);r++)
+ {
+ for (int c=0;c<RM380Z_CHDIMX;c++)
+ {
+ UINT16 *dest=&bitmap.pix16((y*(RM380Z_CHDIMY+1))+r,(x*(RM380Z_CHDIMX+1))+c);
+ *dest=m_graphic_chars[charnum&0x3f][c+(r*(RM380Z_CHDIMX+1))];
+ }
+ }
+ }
+ else
+ {
+ for (int r=0;r<RM380Z_CHDIMY;r++)
+ {
+ for (int c=0;c<(RM380Z_CHDIMX*2);c+=2)
+ {
+ UINT16 *dest=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c);
+ UINT16 *dest2=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c+1);
+ *dest=m_graphic_chars[charnum&0x3f][(c/2)+(r*(RM380Z_CHDIMX+1))];
+ *dest2=m_graphic_chars[charnum&0x3f][(c/2)+(r*(RM380Z_CHDIMX+1))];
+ }
+ }
+ }
+ }
+}
+
+void rm380z_state::update_screen(bitmap_ind16 &bitmap)
+{
+ unsigned char* pChar=machine().root_device().memregion("chargen")->base();
+
+ int lineWidth=0x80;
+ int ncols=80;
+
+ if (m_videomode==RM380Z_VIDEOMODE_40COL)
+ {
+ lineWidth=0x40;
+ ncols=40;
+ }
+
+ // blank screen
+ bitmap.fill(0);
+
+ for (int row=0;row<RM380Z_SCREENROWS;row++)
+ {
+ for (int col=0;col<ncols;col++)
+ {
+ UINT8 curch,attribs;
+ decode_videoram_char((row*lineWidth)+col,curch,attribs);
+ putChar(curch,attribs,col,row,bitmap,pChar,m_videomode);
+ //putChar(0x44,0x00,10,10,bitmap,pChar,m_videomode);
+ }
+ }
+}
diff --git a/src/mess/video/rmnimbus.c b/src/mess/video/rmnimbus.c
new file mode 100644
index 00000000000..97e0b40b562
--- /dev/null
+++ b/src/mess/video/rmnimbus.c
@@ -0,0 +1,679 @@
+/*
+ video/rmnimbus.c
+
+ Research machines Nimbus.
+
+ 2009-11-14, P.Harvey-Smith.
+
+ This is my best guess implementation of the operation of the Nimbus
+ video system.
+
+ On the real machine, the Video chip has a block of 64K of memory which is
+ completely seperate from the main 80186 memory.
+
+ The main CPU write to the video chip via a series of registers in the
+ 0x0000 to 0x002F reigon, the video chip then manages all video memory
+ from there.
+
+ As I cannot find a datasheet for the vide chip marked
+ MB61H201 Fujitsu RML 12835 GCV, I have had to determine most of its
+ operation by disassembling the Nimbus bios and by writing experemental
+ code on the real machine.
+*/
+
+#include "emu.h"
+#include "debug/debugcpu.h"
+#include "debug/debugcon.h"
+#include "includes/rmnimbus.h"
+
+
+#define WIDTH_MASK 0x07
+#define XOR_MASK 0x08
+#define MASK_4080 0x10
+
+// Offsets of nimbus video registers within register array
+
+#define reg000 0x00
+#define reg002 0x01
+#define reg004 0x02
+#define reg006 0x03
+#define reg008 0x04
+#define reg00A 0x05
+#define reg00C 0x06
+#define reg00E 0x07
+#define reg010 0x08
+#define reg012 0x09
+#define reg014 0x0A
+#define reg016 0x0B
+#define reg018 0x0C
+#define reg01A 0x0D
+#define reg01C 0x0E
+#define reg01E 0x0F
+#define reg020 0x10
+#define reg022 0x11
+#define reg024 0x12
+#define reg026 0x13
+#define reg028 0x14
+#define reg02A 0x15
+#define reg02C 0x16
+#define reg02E 0x17
+
+#define FG_COLOUR (state->m_vidregs[reg024]&0x0F)
+#define BG_COLOUR ((state->m_vidregs[reg024]&0xF0)>>4)
+
+#define IS_80COL (state->m_vidregs[reg026]&MASK_4080)
+#define IS_XOR (state->m_vidregs[reg022]&XOR_MASK)
+
+
+
+
+#define DEBUG_TEXT 0x01
+#define DEBUG_DB 0x02
+#define DEBUG_PIXEL 0x04
+
+#define DEBUG_SET(flags) ((state->m_debug_video & (flags))==(flags))
+
+static UINT8 get_pixel(rmnimbus_state *state, UINT16 x, UINT16 y);
+static UINT16 read_pixel_line(rmnimbus_state *state, UINT16 x, UINT16 y, UINT8 width);
+static UINT16 read_pixel_data(rmnimbus_state *state, UINT16 x, UINT16 y);
+static UINT16 read_reg_00A(rmnimbus_state *state);
+
+static void set_pixel(rmnimbus_state *state, UINT16 x, UINT16 y, UINT8 colour);
+static void write_pixel_line(rmnimbus_state *state, UINT16 x, UINT16 y, UINT16 data, UINT8 width);
+static void write_pixel_data(rmnimbus_state *state, UINT16 x, UINT16 y, UINT16 data);
+static void move_pixel_line(rmnimbus_state *state, UINT16 x, UINT16 y, UINT16 data, UINT8 width);
+static void write_reg_004(rmnimbus_state *state);
+static void write_reg_006(rmnimbus_state *state);
+static void write_reg_010(rmnimbus_state *state);
+static void write_reg_012(rmnimbus_state *state);
+static void write_reg_014(rmnimbus_state *state);
+static void write_reg_016(rmnimbus_state *state);
+static void write_reg_01A(rmnimbus_state *state);
+static void write_reg_01C(rmnimbus_state *state);
+static void write_reg_01E(rmnimbus_state *state);
+static void write_reg_026(rmnimbus_state *state);
+static void change_palette(running_machine &machine, UINT8 bank, UINT16 colours, UINT8 regno);
+
+static void video_debug(running_machine &machine, int ref, int params, const char *param[]);
+static void video_regdump(running_machine &machine, int ref, int params, const char *param[]);
+
+/*
+ I'm not sure which of thes return values on a real machine, so for the time being I'm going
+ to return the values for all of them, it doesn't seem to hurt !
+*/
+
+READ16_MEMBER(rmnimbus_state::nimbus_video_io_r)
+{
+ rmnimbus_state *state = machine().driver_data<rmnimbus_state>();
+ int pc=cpu_get_pc(&space.device());
+ UINT16 result;
+
+ switch (offset)
+ {
+ case reg000 : result=m_vidregs[reg000]; break;
+ case reg002 : result=m_vidregs[reg002]; break;
+ case reg004 : result=m_vidregs[reg004]; break;
+ case reg006 : result=m_vidregs[reg006]; break;
+ case reg008 : result=m_vidregs[reg008]; break;
+ case reg00A : result=read_reg_00A(state); break;
+ case reg00C : result=m_vidregs[reg00C]; break;
+ case reg00E : result=m_vidregs[reg00E]; break;
+
+ case reg010 : result=m_vidregs[reg010]; break;
+ case reg012 : result=m_vidregs[reg012]; break;
+ case reg014 : result=m_vidregs[reg014]; break;
+ case reg016 : result=m_vidregs[reg016]; break;
+ case reg018 : result=m_vidregs[reg018]; break;
+ case reg01A : result=m_vidregs[reg01A]; break;
+ case reg01C : result=m_vidregs[reg01C]; break;
+ case reg01E : result=m_vidregs[reg01E]; break;
+
+ case reg020 : result=m_vidregs[reg020]; break;
+ case reg022 : result=m_vidregs[reg022]; break;
+ case reg024 : result=m_vidregs[reg024]; break;
+ case reg026 : result=m_vidregs[reg026]; break;
+ case reg028 : result=m_hs_count; break; //result=m_vidregs[reg028]; break;
+ case reg02A : result=m_vidregs[reg02A]; break;
+ case reg02C : result=m_vidregs[reg02C]; break;
+ case reg02E : result=m_vidregs[reg02E]; break;
+ default : result=0; break;
+ }
+
+ if(DEBUG_SET(DEBUG_TEXT))
+ logerror("Nimbus video IOR at %05X from %04X mask=%04X, data=%04X\n",pc,(offset*2),mem_mask,result);
+
+ return result;
+}
+
+static UINT8 get_pixel(rmnimbus_state *state, UINT16 x, UINT16 y)
+{
+ UINT8 result = 0;
+
+ if((x<SCREEN_WIDTH_PIXELS) && (y<SCREEN_HEIGHT_LINES))
+ {
+ if(IS_80COL)
+ result=state->m_video_mem[x][y];
+ else
+ result=state->m_video_mem[x*2][y];
+ }
+
+ return result;
+}
+
+static UINT16 read_pixel_line(rmnimbus_state *state, UINT16 x, UINT16 y, UINT8 width)
+{
+ UINT16 result = 0;
+ UINT16 mask;
+ UINT16 pixel_x;
+ UINT16 colour;
+ UINT8 shifts;
+
+ if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL))
+ logerror("read_pixel_line(x=%04X, y=%04X, width=%02X, bpp=%02X, pixel_mask=%02X)\n",x,y,width,state->m_bpp,state->m_pixel_mask);
+
+ shifts=width-state->m_bpp;
+
+ for(mask=state->m_pixel_mask, pixel_x=(x*(width/state->m_bpp)); mask>0; mask=(mask>>state->m_bpp), pixel_x++)
+ {
+ colour=get_pixel(state,pixel_x,y);
+
+ if(state->m_bpp==1)
+ colour=((colour==FG_COLOUR) ? 1 : 0) << shifts;
+ else
+ colour=colour << shifts;
+
+ result=(result & ~mask) | colour;
+
+ shifts-=state->m_bpp;
+ }
+
+ return result;
+}
+
+static UINT16 read_pixel_data(rmnimbus_state *state, UINT16 x, UINT16 y)
+{
+ UINT16 result=0;
+
+ if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL))
+ logerror("read_pixel_data(x=%04X, y=%04X), reg022=%04X\n",x,y,state->m_vidregs[reg022]);
+
+ if(IS_80COL)
+ {
+ switch (state->m_vidregs[reg022] & WIDTH_MASK)
+ {
+ case 0x00 : break;
+
+ case 0x01 : break;
+
+ case 0x02 : break;
+
+ case 0x03 : break;
+
+ case 0x04 : break;
+
+ case 0x05 : break;
+
+ case 0x06 : state->m_bpp=2; state->m_pixel_mask=0xC000;
+ result=read_pixel_line(state,x,y,16);
+ break;
+
+ case 0x07 : break;
+ }
+ }
+ else /* 40 Col */
+ {
+ switch (state->m_vidregs[reg022] & WIDTH_MASK)
+ {
+ case 0x00 : break;
+
+ case 0x01 : break;
+
+ case 0x02 : break;
+
+ case 0x03 : break;
+
+ case 0x04 : break;
+
+ case 0x05 : break;
+
+ case 0x06 : state->m_bpp=4; state->m_pixel_mask=0xF000;
+ result=read_pixel_line(state,x,y,16);
+ break;
+
+ case 0x07 : break;
+ }
+ }
+
+ return result;
+}
+
+static UINT16 read_reg_00A(rmnimbus_state *state)
+{
+ return read_pixel_data(state, ++state->m_vidregs[reg002],state->m_vidregs[reg00C]);
+}
+
+
+/*
+ Write to the video registers, the default action is to write to the array of registers.
+ If a register also needs some special action call the action function for that register.
+
+ Incase anyone wonders about the DEBUG_DB statement, this allows me to log which registers
+ are being written to and then play them back at the real machine, this has helped greatly
+ in figuring out what the video registers do.
+
+*/
+
+WRITE16_MEMBER(rmnimbus_state::nimbus_video_io_w)
+{
+ rmnimbus_state *state = machine().driver_data<rmnimbus_state>();
+ int pc=cpu_get_pc(&space.device());
+
+ if(offset<reg028)
+ {
+ if(DEBUG_SET(DEBUG_TEXT))
+ logerror("Nimbus video IOW at %05X write of %04X to %04X mask=%04X\n",pc,data,(offset*2),mem_mask);
+
+ if(DEBUG_SET(DEBUG_DB))
+ logerror("dw %05X,%05X\n",(offset*2),data);
+ }
+
+ switch (offset)
+ {
+ case reg000 : m_vidregs[reg000]=data; break;
+ case reg002 : m_vidregs[reg002]=data; break;
+ case reg004 : m_vidregs[reg004]=data; write_reg_004(state); break;
+ case reg006 : m_vidregs[reg006]=data; write_reg_006(state); break;
+ case reg008 : m_vidregs[reg008]=data; break;
+ case reg00A : m_vidregs[reg00A]=data; break;
+ case reg00C : m_vidregs[reg00C]=data; break;
+ case reg00E : m_vidregs[reg00E]=data; break;
+
+ case reg010 : m_vidregs[reg010]=data; write_reg_010(state); break;
+ case reg012 : m_vidregs[reg012]=data; write_reg_012(state); break;
+ case reg014 : m_vidregs[reg014]=data; write_reg_014(state); break;
+ case reg016 : m_vidregs[reg016]=data; write_reg_016(state); break;
+ case reg018 : m_vidregs[reg018]=data; break;
+ case reg01A : m_vidregs[reg01A]=data; write_reg_01A(state); break;
+ case reg01C : m_vidregs[reg01C]=data; write_reg_01C(state);break;
+ case reg01E : m_vidregs[reg01E]=data; write_reg_01E(state);break;
+
+ case reg020 : m_vidregs[reg020]=data; break;
+ case reg022 : m_vidregs[reg022]=data; break;
+ case reg024 : m_vidregs[reg024]=data; break;
+ case reg026 : m_vidregs[reg026]=data; write_reg_026(state); break;
+ case reg028 : change_palette(machine(),0,data,reg028); break;
+ case reg02A : change_palette(machine(),1,data,reg02A); break;
+ case reg02C : change_palette(machine(),2,data,reg02C); break;
+ case reg02E : change_palette(machine(),3,data,reg02E); break;
+
+ default : break;
+ }
+}
+
+static void set_pixel(rmnimbus_state *state, UINT16 x, UINT16 y, UINT8 colour)
+{
+ if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL))
+ logerror("set_pixel(x=%04X, y=%04X, colour=%04X), IS_XOR=%02X\n",x,y,colour,IS_XOR);
+
+ if(IS_80COL)
+ colour&=0x03;
+
+ if((x<SCREEN_WIDTH_PIXELS) && (y<SCREEN_HEIGHT_LINES))
+ {
+ if(IS_XOR)
+ state->m_video_mem[x][y]^=colour;
+ else
+ state->m_video_mem[x][y]=colour;
+ }
+}
+
+static void set_pixel40(rmnimbus_state *state, UINT16 x, UINT16 y, UINT8 colour)
+{
+ set_pixel(state, (x*2),y,colour);
+ set_pixel(state, (x*2)+1,y,colour);
+}
+
+static void write_pixel_line(rmnimbus_state *state, UINT16 x, UINT16 y, UINT16 data, UINT8 width)
+{
+ UINT16 mask;
+ UINT16 pixel_x;
+ UINT16 colour;
+ UINT8 shifts;
+
+ if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL))
+ logerror("write_pixel_line(x=%04X, y=%04X, data=%04X, width=%02X, bpp=%02X, pixel_mask=%02X)\n",x,y,data,width,state->m_bpp,state->m_pixel_mask);
+
+ shifts=width-state->m_bpp;
+
+ for(mask=state->m_pixel_mask, pixel_x=(x*(width/state->m_bpp)); mask>0; mask=(mask>>state->m_bpp), pixel_x++)
+ {
+ if(state->m_bpp==1)
+ colour=(data & mask) ? FG_COLOUR : BG_COLOUR;
+ else
+ colour=(data & mask) >> shifts;
+
+ //logerror("write_pixel_line: data=%04X, mask=%04X, shifts=%02X, bpp=%02X colour=%02X\n",data,mask,shifts,state->m_bpp,colour);
+
+ if(IS_80COL)
+ set_pixel(state,pixel_x,y,colour);
+ else
+ set_pixel40(state,pixel_x,y,colour);
+
+ shifts-=state->m_bpp;
+ }
+}
+
+static void move_pixel_line(rmnimbus_state *state, UINT16 x, UINT16 y, UINT16 data, UINT8 width)
+{
+ UINT16 pixelno;
+ UINT16 pixelx;
+
+ if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL))
+ logerror("move_pixel_line(x=%04X, y=%04X, data=%04X, width=%02X)\n",x,y,data,width);
+
+ for(pixelno=0;pixelno<width;pixelno++)
+ {
+ pixelx=(x*width)+pixelno;
+ if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL))
+ logerror("pixelx=%04X\n",pixelx);
+ state->m_video_mem[pixelx][state->m_vidregs[reg020]]=state->m_video_mem[pixelx][y];
+ }
+}
+
+
+
+/*
+ The values in the bottom 3 bits of reg022 seem to determine the number of bits per pixel
+ for following operations.
+
+ The values that I have decoded so far are :
+
+ 000 1bpp, foreground and background colours taken from reg024
+ 001 2bpp, using the first 4 colours of the pallette
+ 010
+ 011
+ 100 4bpp, must be a 16 bit word, of which the upper byte is a mask anded with the lower byte
+ containing the pixel data for two pixels.
+ 101 Move pixel data at x,reg020 to x,y, used for scrolling.
+ 110 if 40 col
+ 4bpp, 16 bit word containing the pixel data for 4 pixels.
+ else
+ 2bpp, 16 bit word containing the pixel data for 8 pixels.
+ 111
+
+ Bit 3 of reg022 is as follows :
+
+ 0 pixels are written from supplied colour data
+ 1 pixels are xor'ed onto the screen
+*/
+
+static void write_pixel_data(rmnimbus_state *state, UINT16 x, UINT16 y, UINT16 data)
+{
+ if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL))
+ logerror("write_pixel_data(x=%04X, y=%04X, data=%04X), reg022=%04X\n",x,y,data,state->m_vidregs[reg022]);
+
+ if(IS_80COL)
+ {
+ switch (state->m_vidregs[reg022] & WIDTH_MASK)
+ {
+ case 0x00 : state->m_bpp=1; state->m_pixel_mask=0x8000;
+ write_pixel_line(state,x,y,data,16);
+ break;
+
+ case 0x01 : state->m_bpp=1; state->m_pixel_mask=0x80;
+ write_pixel_line(state,x,y,data,8);
+ break;
+
+ case 0x02 : state->m_bpp=1; state->m_pixel_mask=0x0080;
+ write_pixel_line(state,x,y,data,8);
+ break;
+
+ case 0x03 : state->m_bpp=1;
+ set_pixel(state,x,y,FG_COLOUR);
+ break;
+
+ case 0x04 : state->m_bpp=2; state->m_pixel_mask=0xC0;
+ write_pixel_line(state,x,y,((data & 0xFF) & ((data & 0xFF00)>>8)),8);
+ break;
+
+ case 0x05 : move_pixel_line(state,x,y,data,16);
+ break;
+
+ case 0x06 : state->m_bpp=2; state->m_pixel_mask=0xC000;
+ write_pixel_line(state,x,y,data,16);
+ break;
+
+ case 0x07 : state->m_bpp=1;
+ set_pixel(state,x,y,FG_COLOUR);
+ break;
+ }
+ }
+ else /* 40 Col */
+ {
+ switch (state->m_vidregs[reg022] & WIDTH_MASK)
+ {
+ case 0x00 : state->m_bpp=1; state->m_pixel_mask=0x0080;
+ write_pixel_line(state,x,y,data,8);
+ break;
+
+ case 0x01 : state->m_bpp=2; state->m_pixel_mask=0xC0;
+ write_pixel_line(state,x,y,data,8);
+ break;
+
+ case 0x02 : state->m_bpp=1; state->m_pixel_mask=0x0080;
+ set_pixel40(state,x,y,FG_COLOUR);
+ break;
+
+ case 0x03 : state->m_bpp=1;
+ set_pixel(state,x,y,FG_COLOUR);
+ break;
+
+ case 0x04 : state->m_bpp=4; state->m_pixel_mask=0xF0;
+ write_pixel_line(state,x,y,((data & 0xFF) & ((data & 0xFF00)>>8)),8);
+ break;
+
+ case 0x05 : move_pixel_line(state,x,y,data,16);
+ break;
+
+ case 0x06 : state->m_bpp=4; state->m_pixel_mask=0xF000;
+ write_pixel_line(state,x,y,data,16);
+ break;
+
+ case 0x07 : state->m_bpp=1;
+ set_pixel(state,x,y,FG_COLOUR);
+ break;
+ }
+ }
+}
+
+static void write_reg_004(rmnimbus_state *state)
+{
+ state->m_vidregs[reg002]=0;
+ state->m_vidregs[reg00C]++;
+}
+
+static void write_reg_006(rmnimbus_state *state)
+{
+ state->m_vidregs[reg00C]++;
+ state->m_vidregs[reg002]=state->m_vidregs[reg006];
+}
+
+static void write_reg_010(rmnimbus_state *state)
+{
+ write_pixel_data(state, state->m_vidregs[reg002],state->m_vidregs[reg00C],state->m_vidregs[reg010]);
+}
+
+static void write_reg_012(rmnimbus_state *state)
+{
+ // I dunno if this is actually what is happening as the regs seem to be write only....
+ // doing this however does seem to make some programs (worms from the welcom disk)
+ // work correctly.
+ state->m_vidregs[reg002]=state->m_vidregs[reg012];
+
+ write_pixel_data(state, state->m_vidregs[reg012],state->m_vidregs[reg00C],FG_COLOUR);
+}
+
+static void write_reg_014(rmnimbus_state *state)
+{
+ write_pixel_data(state, state->m_vidregs[reg002],state->m_vidregs[reg00C]++,state->m_vidregs[reg014]);
+}
+
+static void write_reg_016(rmnimbus_state *state)
+{
+ state->m_vidregs[reg002]=state->m_vidregs[reg016];
+
+ write_pixel_data(state, state->m_vidregs[reg002],state->m_vidregs[reg00C]++,FG_COLOUR);
+}
+
+
+static void write_reg_01A(rmnimbus_state *state)
+{
+ write_pixel_data(state, ++state->m_vidregs[reg002],state->m_vidregs[reg00C],state->m_vidregs[reg01A]);
+}
+
+static void write_reg_01C(rmnimbus_state *state)
+{
+ // I dunno if this is actually what is happening as the regs seem to be write only....
+ // doing this however does seem to make some programs (welcome from the welcom disk,
+ // and others using the standard RM box menus) work correctly.
+ state->m_vidregs[reg00C]=state->m_vidregs[reg01C];
+
+ write_pixel_data(state, state->m_vidregs[reg002],state->m_vidregs[reg01C],FG_COLOUR);
+}
+
+static void write_reg_01E(rmnimbus_state *state)
+{
+ state->m_vidregs[reg00C]=state->m_vidregs[reg01E];
+
+ write_pixel_data(state, ++state->m_vidregs[reg002],state->m_vidregs[reg00C],FG_COLOUR);
+}
+
+/*
+ bits 0..3 of reg026 contain the border colour.
+ bit 5 contains the 40/80 column (320/640 pixel) flag.
+*/
+
+static void write_reg_026(rmnimbus_state *state)
+{
+ if(DEBUG_SET(DEBUG_TEXT))
+ logerror("reg 026 write, border_colour=%02X\n",state->m_vidregs[reg026] & 0x0F);
+}
+
+static void change_palette(running_machine &machine, UINT8 bank, UINT16 colours, UINT8 regno)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ UINT8 colourno;
+ UINT16 mask;
+ UINT8 shifts;
+ UINT8 paletteidx;
+ UINT8 colourmax;
+ UINT8 first;
+
+ // for the register's data has changed update it, and then update the pallette, else do nothing.
+ if(state->m_vidregs[regno]!=colours)
+ state->m_vidregs[regno]=colours;
+ else
+ return;
+
+ // Setup parameters for pallette change
+ colourmax=IS_80COL ? 1 : 4;
+ first=IS_80COL ? bank : bank*4;
+
+ shifts=0;
+ mask=0x000F;
+
+ // loop over changing colours
+ for(colourno=first; colourno<(first+colourmax); colourno++)
+ {
+ paletteidx=(colours & mask) >> shifts;
+ palette_set_color_rgb(machine, colourno, nimbus_palette[paletteidx][RED], nimbus_palette[paletteidx][GREEN], nimbus_palette[paletteidx][BLUE]);
+
+ if(DEBUG_SET(DEBUG_TEXT))
+ logerror("set colourno[%02X](r,g,b)=(%02X,%02X,%02X), paletteidx=%02X\n",colourno, nimbus_palette[paletteidx][RED], nimbus_palette[paletteidx][GREEN], nimbus_palette[paletteidx][BLUE],paletteidx);
+ mask=mask<<4;
+ shifts+=4;
+ }
+}
+
+static void video_debug(running_machine &machine, int ref, int params, const char *param[])
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ if(params>0)
+ {
+ sscanf(param[0],"%d",&state->m_debug_video);
+ }
+ else
+ {
+ debug_console_printf(machine,"Error usage : nimbus_vid_debug <debuglevel>\n");
+ debug_console_printf(machine,"Current debuglevel=%02X\n",state->m_debug_video);
+ }
+}
+
+static void video_regdump(running_machine &machine, int ref, int params, const char *param[])
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ int regno;
+
+ for(regno=0;regno<0x08;regno++)
+ {
+ debug_console_printf(machine,"reg%03X=%04X reg%03X=%04X reg%03X=%04X\n",
+ regno*2,state->m_vidregs[regno],
+ (regno+0x08)*2,state->m_vidregs[regno+0x08],
+ (regno+0x10)*2,state->m_vidregs[regno+0x10]);
+
+ logerror("reg%03X=%04X reg%03X=%04X reg%03X=%04X\n",
+ regno*2,state->m_vidregs[regno],
+ (regno+0x08)*2,state->m_vidregs[regno+0x08],
+ (regno+0x10)*2,state->m_vidregs[regno+0x10]);
+ }
+}
+
+VIDEO_START( nimbus )
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ state->m_debug_video=0;
+
+ logerror("VIDEO_START\n");
+
+ if (machine.debug_flags & DEBUG_FLAG_ENABLED)
+ {
+ debug_console_register_command(machine, "nimbus_vid_debug", CMDFLAG_NONE, 0, 0, 1, video_debug);
+ debug_console_register_command(machine, "nimbus_vid_regdump", CMDFLAG_NONE, 0, 0, 1, video_regdump);
+ }
+}
+
+VIDEO_RESET( nimbus )
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ // When we reset clear the video registers and video memory.
+ memset(&state->m_vidregs,0x00,sizeof(state->m_vidregs));
+ memset(&state->m_video_mem,0,sizeof(state->m_video_mem));
+
+ state->m_bpp=4; // bits per pixel
+ logerror("Video reset\n");
+}
+
+SCREEN_VBLANK( nimbus )
+{
+
+// logerror("SCREEN_VBLANK( nimbus )\n");
+}
+
+SCREEN_UPDATE_IND16( nimbus )
+{
+ rmnimbus_state *state = screen.machine().driver_data<rmnimbus_state>();
+ int XCoord;
+ int YCoord = screen.vpos();
+
+ for(XCoord=0;XCoord<SCREEN_WIDTH_PIXELS;XCoord++)
+ {
+ bitmap.pix16(YCoord, XCoord)=state->m_video_mem[XCoord][YCoord];
+ }
+
+ state->m_hs_count++;
+ if((state->m_hs_count & 0x000F)>0x0A)
+ state->m_hs_count&=0xFFF0;
+
+ return 0;
+}
+
diff --git a/src/mess/video/saa505x.c b/src/mess/video/saa505x.c
new file mode 100644
index 00000000000..d6004436ab2
--- /dev/null
+++ b/src/mess/video/saa505x.c
@@ -0,0 +1,3581 @@
+/************************************************************************
+SAA505X Teletext
+
+Variant Character set
+5050 English
+5051 German
+5052 Swedish
+5053 Italian
+5054 Belgian
+5055 US ASCII
+5056 Hebrew
+5057 Cyrillic
+
+Pins
+1 Vss ground
+18 Vdd positive supply
+17 NC not connected
+
+Data In
+--------
+4-10 D1 to D7 in character data inputs
+
+16 ~TLC out transmitted large character
+
+Colour Our
+----------
+21 Y out monochrome video output
+22 Blue out blue video output
+23 Green out green video output
+24 Red out red video output
+25 BLAN out blanking output
+
+Display Control
+---------------
+27 PO in picture on in[ut
+28 DE in display enable input
+
+Remote Control Data Decoder and Store
+-------------------------------------
+2 ~SI in/out superimposer
+3 ~DATA in remote control data
+11 DLIM in remote control data clock
+12 ~GLR in general line reset
+
+Timing Generator/Flash Counter
+------------------------------
+13 DEW in data entry window
+19 TR6 in 6MHz input
+20 F1 in 1MHz input
+26 LOSE in load output shift register enable
+
+Character Rounding
+------------------
+14 CRS in character rounding select
+15 ~BCS in big character select
+
+
+
+
+Characters are output every 1us with a pixel dot rate of 6MHz.
+Each character is 6 x 10 pixels
+
+This device was designed to work over the top of a Television picture,
+so the BLAN blanking output is used to blank out the television signal under control
+of the PO and DE inputs and the box control characters.
+
+13 DEW Data Entry Window
+------------------------
+This input signal resets the internal ROM row address counter prior to the desplay peroid.
+It is also used internally to derive the 'flash' period.
+
+20 F1
+-----
+This input is a 1MHz equal mark/space ration signal. It is used to latch the 7-bit parallel character data into the input latches.
+
+26 LOSE Load output shift register enable
+-----------------------------------------
+This input resets the internal control character flip-flops prior to the start of each display line.
+This signal also defails the character display period.
+
+
+*/
+
+#include "emu.h"
+#include "saa505x.h"
+
+
+/* Normal Character Set */
+
+static const char teletext_saa5050_characters[96*60]={
+ // 0x20 ' '
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x21 '!'
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x22 '"'
+ 0,0,0,0,0,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x23 ' British Pound'
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,1,0,0,1,
+ 0,0,1,0,0,0,
+ 0,1,1,1,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x24 '$'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x25 '%'
+ 0,0,0,0,0,0,
+ 0,1,1,0,0,0,
+ 0,1,1,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,0,0,1,1,
+ 0,0,0,0,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x26 '&'
+ 0,0,0,0,0,0,
+ 0,0,1,0,0,0,
+ 0,1,0,1,0,0,
+ 0,1,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,0,1,0,1,
+ 0,1,0,0,1,0,
+ 0,0,1,1,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x27 '''
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x28 '('
+ 0,0,0,0,0,0,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x29 ')'
+ 0,0,0,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,1,0,
+ 0,0,0,0,1,0,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2a '*'
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,1,0,1,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,1,0,1,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2b '+'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2c ','
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2d '-'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2e '.'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2f '/'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x30 '0'
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x31 '1'
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x32 '2'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,1,1,0,
+ 0,0,1,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x33 '3'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x34 '4'
+ 0,0,0,0,0,0,
+ 0,0,0,0,1,0,
+ 0,0,0,1,1,0,
+ 0,0,1,0,1,0,
+ 0,1,0,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,1,0,
+ 0,0,0,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x35 '5'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x36 '6'
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,1,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x37 '7'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x38 '8'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x39 '9'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,1,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x3a ':'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x3b ';'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x3c '<'
+ 0,0,0,0,0,0,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,0,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x3d '='
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x3e '>'
+ 0,0,0,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,1,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x3f '?'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x40 '@'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,1,1,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,1,1,
+ 0,1,0,0,0,0,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x41 'A'
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x42 'B'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x43 'C'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x44 'D'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x45 'E'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x46 'F'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x47 'G'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,1,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x48 'H'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x49 'I'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4a 'J'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4b 'K'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,1,0,
+ 0,1,0,1,0,0,
+ 0,1,1,0,0,0,
+ 0,1,0,1,0,0,
+ 0,1,0,0,1,0,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4c 'L'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4d 'M'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,1,0,1,1,
+ 0,1,0,1,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4e 'N'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,0,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4f 'O'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x50 'P'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x51 'Q'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,0,1,0,
+ 0,0,1,1,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x52 'R'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,1,0,0,
+ 0,1,0,0,1,0,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x53 'S'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x54 'T'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x55 'U'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x56 'V'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x57 'W'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x58 'X'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x59 'Y'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5a 'Z'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5b Left Arrow
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,1,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5c ' 1/2 symbol'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,1,1,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0
+, // 0x5d Right Arrow
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5e Up Arrow
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,1,0,1,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5f '#'
+ 0,0,0,0,0,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,1,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x60 '_'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x61 'a'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x62 'b'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x63 'c'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x64 'd'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x65 'e'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x66 'f'
+ 0,0,0,0,0,0,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x67 'g'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,1,1,1,0
+, // 0x68 'h'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x69 'i'
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x6a 'j'
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,0,0,0
+, // 0x6b 'k'
+ 0,0,0,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,1,1,0,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x6c 'l'
+ 0,0,0,0,0,0,
+ 0,0,1,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x6d 'm'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,1,0,1,0,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x6e 'n'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x6f 'o'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x70 'p'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0
+, // 0x71 'q'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1
+, // 0x72 'r'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,0,1,1,
+ 0,0,1,1,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x73 's'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x74 't'
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x75 'u'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x76 'v'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x77 'w'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x78 'x'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,1,0,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x79 'y'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,1,1,1,0
+, // 0x7a 'z'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x7b 'one fourth symbol'
+ 0,0,0,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,0,
+ 0,0,1,0,0,1,
+ 0,0,0,0,1,1,
+ 0,0,0,1,0,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,0
+, // 0x7c '|'
+ 0,0,0,0,0,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x7d ' three fourths symbol'
+ 0,0,0,0,0,0,
+ 0,1,1,0,0,0,
+ 0,0,0,1,0,0,
+ 0,1,1,0,0,0,
+ 0,0,0,1,0,0,
+ 0,1,1,0,0,1,
+ 0,0,0,0,1,1,
+ 0,0,0,1,0,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,1
+, // 0x7e Divide
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x7f Block
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,1,1,1,1,1,
+ 0,1,1,1,1,1,
+ 0,1,1,1,1,1,
+ 0,1,1,1,1,1,
+ 0,1,1,1,1,1,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+};
+
+
+/* Graphics Character Set */
+
+static const char teletext_graphics[96*60]={
+ // 0x20
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x21
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x22
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x23
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x24
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x25
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x26
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x27
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x28
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x29
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2a
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2b
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2c
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2d
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2e
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x2f
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x30
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x31
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x32
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x33
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x34
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x35
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x36
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x37
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x38
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x39
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x3a
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x3b
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x3c
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x3d
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x3e
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x3f
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0
+, // 0x40 '@'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,1,1,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,1,1,
+ 0,1,0,0,0,0,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x41 'A'
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x42 'B'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x43 'C'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x44 'D'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x45 'E'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x46 'F'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x47 'G'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,1,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x48 'H'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x49 'I'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4a 'J'
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4b 'K'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,1,0,
+ 0,1,0,1,0,0,
+ 0,1,1,0,0,0,
+ 0,1,0,1,0,0,
+ 0,1,0,0,1,0,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4c 'L'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4d 'M'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,1,0,1,1,
+ 0,1,0,1,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4e 'N'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,0,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x4f 'O'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x50 'P'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x51 'Q'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,0,1,0,
+ 0,0,1,1,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x52 'R'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,1,0,0,
+ 0,1,0,0,1,0,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x53 'S'
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x54 'T'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x55 'U'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x56 'V'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x57 'W'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x58 'X'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x59 'Y'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5a 'Z'
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5b Left Arrow
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,1,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5c '?'
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,1,1,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0
+, // 0x5d Right Arrow
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5e Up Arrow
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,1,0,1,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x5f '#'
+ 0,0,0,0,0,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,1,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+, // 0x60
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x61
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x62
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x63
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x64
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x65
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x66
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x67
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x68
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x69
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x6a
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x6b
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x6c
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x6d
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x6e
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x6f
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1
+, // 0x70
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x71
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x72
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x73
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x74
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x75
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x76
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x77
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x78
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x79
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x7a
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x7b
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x7c
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x7d
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,0,0,0,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x7e
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 0,0,0,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+, // 0x7f
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1,
+ 1,1,1,1,1,1
+};
+
+/* Separated Graphics Character Set */
+
+static const char teletext_separated_graphics[96*60]={
+ // Character ' ' (32)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '!' (33)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '"' (34)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '#' (35)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '$' (36)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '%' (37)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '&' (38)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character ''' (39)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '(' (40)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character ')' (41)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '*' (42)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '+' (43)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character ',' (44)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '-' (45)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '.' (46)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '/' (47)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '0' (48)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '1' (49)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '2' (50)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '3' (51)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '4' (52)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '5' (53)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '6' (54)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '7' (55)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '8' (56)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '9' (57)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character ':' (58)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character ';' (59)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '<' (60)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '=' (61)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '>' (62)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '?' (63)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '@' (64)
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,1,1,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,1,1,
+ 0,1,0,0,0,0,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'A' (65)
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'B' (66)
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'C' (67)
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'D' (68)
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'E' (69)
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'F' (70)
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'G' (71)
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,1,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'H' (72)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'I' (73)
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'J' (74)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'K' (75)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,1,0,
+ 0,1,0,1,0,0,
+ 0,1,1,0,0,0,
+ 0,1,0,1,0,0,
+ 0,1,0,0,1,0,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'L' (76)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'M' (77)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,1,0,1,1,
+ 0,1,0,1,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'N' (78)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,0,1,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'O' (79)
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'P' (80)
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'Q' (81)
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,0,1,0,
+ 0,0,1,1,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'R' (82)
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,1,1,1,0,
+ 0,1,0,1,0,0,
+ 0,1,0,0,1,0,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'S' (83)
+ 0,0,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,0,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'T' (84)
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'U' (85)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'V' (86)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'W' (87)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,1,0,1,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'X' (88)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,1,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'Y' (89)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,1,
+ 0,1,0,0,0,1,
+ 0,0,1,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character 'Z' (90)
+ 0,0,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '[' (91)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,0,0,0,
+ 0,1,1,1,1,1,
+ 0,0,1,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '\' (92)
+ 0,0,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,0,0,0,
+ 0,1,0,1,1,0,
+ 0,0,0,0,0,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,1,1,1,
+ 0,0,0,0,0,0
+,
+ // Character ']' (93)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,0,0,1,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '^' (94)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,0,0,
+ 0,0,1,1,1,0,
+ 0,1,0,1,0,1,
+ 0,0,0,1,0,0,
+ 0,0,0,1,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '_' (95)
+ 0,0,0,0,0,0,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,1,0,1,0,
+ 0,1,1,1,1,1,
+ 0,0,1,0,1,0,
+ 0,0,1,0,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0
+,
+ // Character '`' (96)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'a' (97)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'b' (98)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'c' (99)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'd' (100)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'e' (101)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'f' (102)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'g' (103)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'h' (104)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'i' (105)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'j' (106)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'k' (107)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'l' (108)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'm' (109)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'n' (110)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'o' (111)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'p' (112)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'q' (113)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'r' (114)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 's' (115)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 't' (116)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'u' (117)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'v' (118)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'w' (119)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'x' (120)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'y' (121)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,1,1,1,0,
+ 1,1,1,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character 'z' (122)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character '{' (123)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character '|' (124)
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character '}' (125)
+ 1,1,0,0,0,0,
+ 1,1,0,0,0,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character '~' (126)
+ 0,0,0,1,1,0,
+ 0,0,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+,
+ // Character '' (127)
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0,
+ 1,1,0,1,1,0,
+ 1,1,0,1,1,0,
+ 0,0,0,0,0,0
+};
+
+
+typedef struct
+{
+ int data;
+ int lose;
+
+ const char *lookup;
+ const char *graphics;
+ int colour;
+ int rcolour;
+ int bgcolour;
+ int start_line;
+ int double_height;
+ int double_height_set;
+ int double_height_offset;
+ int linecount;
+ int flash;
+ int holdgraphics;
+ int lastcode;
+
+ int frame_count;
+ const saa505x_interface *intf;
+} teletext_t;
+
+
+INLINE teletext_t *get_safe_token( device_t *device )
+{
+ assert(device != NULL);
+ assert(device->type() == SAA505X);
+
+ return (teletext_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+static DEVICE_START( saa505x )
+{
+ teletext_t *tt = get_safe_token(device);
+ tt->lookup=teletext_saa5050_characters;
+ tt->graphics=teletext_graphics;
+ tt->colour=7;
+ tt->intf = (const saa505x_interface *)device->static_config();
+}
+
+DEVICE_GET_INFO( saa505x )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(teletext_t); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(saa505x); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "SAA505x Video"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "SAA505x Video"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(SAA505X, saa505x);
+
+void teletext_data_w(device_t *device, int offset, int data)
+{
+ teletext_t *tt = get_safe_token(device);
+ tt->data=data & 0x7f;
+}
+
+void teletext_DEW(device_t *device)
+{
+ teletext_t *tt = get_safe_token(device);
+ tt->linecount=18;
+ tt->double_height=0;
+ tt->double_height_set=0;
+ tt->double_height_offset=0;
+ tt->frame_count=(tt->frame_count+1)%50;
+}
+
+void teletext_LOSE_w(device_t *device, int offset, int data)
+{
+ teletext_t *tt = get_safe_token(device);
+
+ if ((data)&&(!tt->lose))
+ {
+
+ tt->lookup=teletext_saa5050_characters;
+ tt->colour=7;
+ tt->bgcolour=0;
+ tt->graphics=teletext_graphics;
+ tt->linecount=(tt->linecount+1)%19;
+ tt->start_line=0;
+ tt->double_height=0;
+ tt->flash=0;
+ tt->holdgraphics=0;
+ tt->lastcode=0x20;
+
+ // only check the double height stuff if at the first row of a new line
+ if (!tt->linecount)
+ {
+ tt->double_height_offset=((!tt->double_height_set)||tt->double_height_offset)?0:10;
+ tt->double_height_set=0;
+ }
+
+ }
+
+ tt->lose=data;
+}
+
+
+void teletext_F1(device_t *device)
+{
+ teletext_t *tt = get_safe_token(device);
+ int sc1;
+ int code;
+ code=tt->data;
+
+ switch (code)
+ {
+ // 0x00 Not used
+
+ case 0x01: case 0x02: case 0x03: case 0x04:
+ case 0x05: case 0x06: case 0x07:
+ tt->lookup=teletext_saa5050_characters;
+ tt->colour=code;
+ break;
+
+
+ case 0x08: // Flash
+ tt->flash=tt->frame_count<20?1:0;
+ break;
+ case 0x09: // Steady
+ tt->flash=0;
+ break;
+
+ // 0x0a End Box NOT USED
+ // 0x0b Start Box NOT USED
+
+ case 0x0c: // Normal Height
+ tt->double_height=0;
+ tt->start_line=0;
+ break;
+ case 0x0d: // Double Height
+ tt->double_height=1;
+ tt->double_height_set=1;
+ tt->start_line=tt->double_height_offset;
+ break;
+
+ // 0x0e S0 NOT USED
+ // 0x0f S1 NOT USED
+ // 0x10 DLE NOT USED
+
+ case 0x11: case 0x12: case 0x13: case 0x14:
+ case 0x15: case 0x16: case 0x17:
+ tt->lookup=tt->graphics;
+ tt->colour=code&0x07;
+ break;
+
+ // 0x18 Conceal Display
+
+ case 0x19: // Contiguois Graphics
+ tt->graphics=teletext_graphics;
+ if (tt->lookup!=teletext_saa5050_characters)
+ tt->lookup=tt->graphics;
+ break;
+ case 0x1a: // Separated Graphics
+ tt->graphics=teletext_separated_graphics;
+ if (tt->lookup!=teletext_saa5050_characters)
+ tt->lookup=tt->graphics;
+ break;
+
+ // 0x1b ESC NOT USED
+
+ case 0x1c: // Black Background
+ tt->bgcolour=0;
+ break;
+ case 0x1d: // New Background
+ tt->bgcolour=tt->colour;
+ break;
+
+ case 0x1e:
+ tt->holdgraphics=1;
+ break;
+
+ case 0x1f:
+ tt->holdgraphics=0;
+ break;
+ }
+
+ if (tt->lose)
+ {
+ tt->rcolour=tt->flash?tt->bgcolour:tt->colour;
+ if (code<0x20) {
+ if (tt->holdgraphics) {
+ code=tt->lastcode;
+ } else {
+ code=0x20;
+ }
+ }
+ tt->lastcode=code;
+ code=(code-0x20)*60+(6*(((tt->linecount/2)+tt->start_line)>>tt->double_height));
+ for(sc1=0;sc1<6;sc1++)
+ {
+ (tt->intf->out_Pixel_func)(device,0,tt->lookup[code++]?tt->rcolour:tt->bgcolour);
+ }
+ } else {
+
+ (tt->intf->out_Pixel_func)(device,0,0);
+ (tt->intf->out_Pixel_func)(device,0,0);
+ (tt->intf->out_Pixel_func)(device,0,0);
+ (tt->intf->out_Pixel_func)(device,0,0);
+ (tt->intf->out_Pixel_func)(device,0,0);
+ (tt->intf->out_Pixel_func)(device,0,0);
+ }
+}
diff --git a/src/mess/video/saa505x.h b/src/mess/video/saa505x.h
new file mode 100644
index 00000000000..7597cbf28ad
--- /dev/null
+++ b/src/mess/video/saa505x.h
@@ -0,0 +1,27 @@
+/************************************************************************
+ saa505x
+
+ MESS Driver By:
+
+ Gordon Jefferyes
+ mess_bbc@gjeffery.dircon.co.uk
+
+ ************************************************************************/
+
+
+typedef struct _saa505x_interface saa505x_interface;
+struct _saa505x_interface
+{
+ void (*out_Pixel_func)(device_t *device, int offset, int data);
+};
+
+void teletext_DEW(device_t *device);
+void teletext_LOSE_w(device_t *device, int offset, int data);
+void teletext_data_w(device_t *device, int offset, int data);
+void teletext_F1(device_t *device);
+
+DECLARE_LEGACY_DEVICE(SAA505X, saa505x);
+
+#define MCFG_SAA505X_VIDEO_ADD(_tag, _intf) \
+ MCFG_DEVICE_ADD(_tag, SAA505X, 0) \
+ MCFG_DEVICE_CONFIG(_intf)
diff --git a/src/mess/video/samcoupe.c b/src/mess/video/samcoupe.c
new file mode 100644
index 00000000000..4f8c05e25e9
--- /dev/null
+++ b/src/mess/video/samcoupe.c
@@ -0,0 +1,176 @@
+/***************************************************************************
+
+ SAM Coupe
+
+ Functions to emulate the video hardware
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/samcoupe.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* border color from border register */
+#define BORDER_COLOR(x) ((x & 0x20) >> 2 | (x & 0x07))
+
+/* foreground and background color from attribute byte in mode 1 and 2 */
+#define ATTR_BG(x) ((x >> 3) & 0x07)
+#define ATTR_FG(x) (((x >> 3) & 0x08) | (x & 0x07))
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+void samcoupe_state::video_start()
+{
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+}
+
+UINT32 samcoupe_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+static void draw_mode4_line(running_machine &machine, int y, int hpos)
+{
+ samcoupe_state *state = machine.driver_data<samcoupe_state>();
+ UINT8 *videoram = state->m_videoram;
+
+ /* get start address */
+ UINT8 *vram = videoram + ((y - SAM_BORDER_TOP) * 128) + ((hpos - SAM_BORDER_LEFT) / 4);
+
+ for (int i = 0; i < (SAM_BLOCK*2)/4; i++)
+ {
+ /* draw 2 pixels (doublewidth) */
+ state->m_bitmap.pix16(y, hpos + i * 4 + 0) = state->m_clut[(*vram >> 4) & 0x0f];
+ state->m_bitmap.pix16(y, hpos + i * 4 + 1) = state->m_clut[(*vram >> 4) & 0x0f];
+ state->m_bitmap.pix16(y, hpos + i * 4 + 2) = state->m_clut[(*vram >> 0) & 0x0f];
+ state->m_bitmap.pix16(y, hpos + i * 4 + 3) = state->m_clut[(*vram >> 0) & 0x0f];
+
+ /* move to next address */
+ vram++;
+
+ /* attribute register contains the third displayed byte */
+ if (i == 2)
+ state->m_attribute = *vram;
+ }
+}
+
+static void draw_mode3_line(running_machine &machine, int y, int hpos)
+{
+ samcoupe_state *state = machine.driver_data<samcoupe_state>();
+ UINT8 *videoram = state->m_videoram;
+
+ /* get start address */
+ UINT8 *vram = videoram + ((y - SAM_BORDER_TOP) * 128) + ((hpos - SAM_BORDER_LEFT) / 4);
+
+ for (int i = 0; i < (SAM_BLOCK*2)/4; i++)
+ {
+ /* draw 4 pixels */
+ state->m_bitmap.pix16(y, hpos + i * 4 + 0) = state->m_clut[(*vram >> 6) & 0x03];
+ state->m_bitmap.pix16(y, hpos + i * 4 + 1) = state->m_clut[(*vram >> 4) & 0x03];
+ state->m_bitmap.pix16(y, hpos + i * 4 + 2) = state->m_clut[(*vram >> 2) & 0x03];
+ state->m_bitmap.pix16(y, hpos + i * 4 + 3) = state->m_clut[(*vram >> 0) & 0x03];
+
+ /* move to next address */
+ vram++;
+
+ /* attribute register contains the third displayed byte */
+ if (i == 2)
+ state->m_attribute = *vram;
+ }
+}
+
+static void draw_mode12_block(samcoupe_state *state, bitmap_ind16 &bitmap, int vpos, int hpos, UINT8 mask)
+{
+ /* extract colors from attribute */
+ UINT8 ink = state->m_clut[ATTR_FG(state->m_attribute)];
+ UINT8 pap = state->m_clut[ATTR_BG(state->m_attribute)];
+
+ /* draw block of 8 pixels (doubled to 16) */
+ for (int i = 0; i < SAM_BLOCK; i++)
+ {
+ bitmap.pix16(vpos, hpos + i*2 + 0) = BIT(mask, 7 - i) ? ink : pap;
+ bitmap.pix16(vpos, hpos + i*2 + 1) = BIT(mask, 7 - i) ? ink : pap;
+ }
+}
+
+static void draw_mode2_line(running_machine &machine, int y, int hpos)
+{
+ samcoupe_state *state = machine.driver_data<samcoupe_state>();
+ UINT8 *videoram = state->m_videoram;
+
+ int cell = (y - SAM_BORDER_TOP) * 32 + (hpos - SAM_BORDER_LEFT) / SAM_BLOCK / 2;
+
+ UINT8 mask = videoram[cell];
+ state->m_attribute = videoram[cell + 0x2000];
+
+ draw_mode12_block(state, state->m_bitmap, y, hpos, mask);
+}
+
+static void draw_mode1_line(running_machine &machine, int y, int hpos)
+{
+ samcoupe_state *state = machine.driver_data<samcoupe_state>();
+ UINT8 *videoram = state->m_videoram;
+
+ UINT8 mask = videoram[((((y - SAM_BORDER_TOP) & 0xc0) << 5) | (((y - SAM_BORDER_TOP) & 0x07) << 8) | (((y - SAM_BORDER_TOP) & 0x38) << 2)) + (hpos - SAM_BORDER_LEFT) / SAM_BLOCK / 2];
+ state->m_attribute = videoram[32*192 + (((y - SAM_BORDER_TOP) & 0xf8) << 2) + (hpos - SAM_BORDER_LEFT) / SAM_BLOCK / 2];
+
+ draw_mode12_block(state, state->m_bitmap, y, hpos, mask);
+}
+
+TIMER_CALLBACK( sam_video_update_callback )
+{
+ samcoupe_state *state = machine.driver_data<samcoupe_state>();
+ int vpos = machine.primary_screen->vpos();
+ int hpos = machine.primary_screen->hpos();
+
+ int next_vpos = vpos;
+ int next_hpos = hpos + SAM_BLOCK*2;
+
+ /* next scanline? */
+ if (next_hpos >= SAM_BORDER_LEFT + SAM_SCREEN_WIDTH + SAM_BORDER_RIGHT)
+ {
+ next_vpos = (vpos + 1) % (SAM_BORDER_TOP + SAM_SCREEN_HEIGHT + SAM_BORDER_BOTTOM);
+ next_hpos = 0;
+ }
+
+ /* display disabled? (only in mode 3 or 4) */
+ if (BIT(state->m_vmpr, 6) && BIT(state->m_border, 7))
+ {
+ state->m_bitmap.plot_box(hpos, vpos, SAM_BLOCK*2, 1, 0);
+ }
+ else
+ {
+ /* border area? */
+ if (vpos < SAM_BORDER_TOP || vpos >= SAM_BORDER_TOP + SAM_SCREEN_HEIGHT || hpos < SAM_BORDER_LEFT || hpos >= SAM_BORDER_LEFT + SAM_SCREEN_WIDTH)
+ {
+ state->m_attribute = 0xff;
+ state->m_bitmap.plot_box(hpos, vpos, SAM_BLOCK*2, 1, state->m_clut[BORDER_COLOR(state->m_border)]);
+ }
+ else
+ {
+ /* main screen area */
+ switch ((state->m_vmpr & 0x60) >> 5)
+ {
+ case 0: draw_mode1_line(machine, vpos, hpos); break;
+ case 1: draw_mode2_line(machine, vpos, hpos); break;
+ case 2: draw_mode3_line(machine, vpos, hpos); break;
+ case 3: draw_mode4_line(machine, vpos, hpos); break;
+ }
+ }
+ }
+
+ /* do we need to trigger the scanline interrupt (interrupt happens at the start of the right border before the specified line)? */
+ if (state->m_line_int < SAM_SCREEN_HEIGHT && hpos == SAM_BORDER_LEFT + SAM_SCREEN_WIDTH && vpos == (state->m_line_int + SAM_BORDER_TOP - 1))
+ samcoupe_irq(machine.firstcpu, SAM_LINE_INT);
+
+ /* schedule next update */
+ state->m_video_update_timer->adjust(machine.primary_screen->time_until_pos(next_vpos, next_hpos));
+}
diff --git a/src/mess/video/sapi1.c b/src/mess/video/sapi1.c
new file mode 100644
index 00000000000..1530ed4f8a2
--- /dev/null
+++ b/src/mess/video/sapi1.c
@@ -0,0 +1,150 @@
+/***************************************************************************
+
+ SAPI-1 driver by Miodrag Milanovic
+
+ 09/09/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "includes/sapi1.h"
+
+static const UINT8 MHB2501[] = {
+ 0x0c,0x11,0x13,0x15,0x17,0x10,0x0e,0x00, // @
+ 0x04,0x0a,0x11,0x11,0x1f,0x11,0x11,0x00, // A
+ 0x1e,0x11,0x11,0x1e,0x11,0x11,0x1e,0x00, // B
+ 0x0e,0x11,0x10,0x10,0x10,0x11,0x0e,0x00, // C
+ 0x1e,0x09,0x09,0x09,0x09,0x09,0x1e,0x00, // D
+ 0x1f,0x10,0x10,0x1e,0x10,0x10,0x1f,0x00, // E
+ 0x1f,0x10,0x10,0x1e,0x10,0x10,0x10,0x00, // F
+ 0x0e,0x11,0x10,0x10,0x13,0x11,0x0f,0x00, // G
+
+ 0x11,0x11,0x11,0x1f,0x11,0x11,0x11,0x00, // H
+ 0x0e,0x04,0x04,0x04,0x04,0x04,0x0e,0x00, // I
+ 0x01,0x01,0x01,0x01,0x11,0x11,0x0e,0x00, // J
+ 0x11,0x12,0x14,0x18,0x14,0x12,0x11,0x00, // K
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x1f,0x00, // L
+ 0x11,0x1b,0x15,0x15,0x11,0x11,0x11,0x00, // M
+ 0x11,0x11,0x19,0x15,0x13,0x11,0x11,0x00, // N
+ 0x0e,0x11,0x11,0x11,0x11,0x11,0x0e,0x00, // O
+
+ 0x1e,0x11,0x11,0x1e,0x10,0x10,0x10,0x00, // P
+ 0x0e,0x11,0x11,0x11,0x15,0x12,0x0d,0x00, // Q
+ 0x1e,0x11,0x11,0x1e,0x14,0x12,0x11,0x00, // R
+ 0x0e,0x11,0x10,0x0e,0x01,0x11,0x0e,0x00, // S
+ 0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x00, // T
+ 0x11,0x11,0x11,0x11,0x11,0x11,0x0e,0x00, // U
+ 0x11,0x11,0x11,0x0a,0x0a,0x04,0x04,0x00, // V
+ 0x11,0x11,0x11,0x15,0x15,0x15,0x0a,0x00, // W
+
+ 0x11,0x11,0x0a,0x04,0x0a,0x11,0x11,0x00, // X
+ 0x11,0x11,0x0a,0x04,0x04,0x04,0x04,0x00, // Y
+ 0x1f,0x01,0x02,0x04,0x08,0x10,0x1f,0x00, // Z
+ 0x1c,0x10,0x10,0x10,0x10,0x10,0x1c,0x00, // [
+ 0x00,0x10,0x08,0x04,0x02,0x01,0x00,0x00, // backslash
+ 0x07,0x01,0x01,0x01,0x01,0x01,0x07,0x00, // ]
+ 0x0e,0x11,0x00,0x00,0x00,0x00,0x00,0x00, // ^
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00, // _
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
+ 0x04,0x04,0x04,0x04,0x04,0x00,0x04,0x00, // !
+ 0x0a,0x0a,0x0a,0x00,0x00,0x00,0x00,0x00, // "
+ 0x0a,0x0a,0x1f,0x0a,0x1f,0x0a,0x0a,0x00, // #
+ 0x00,0x11,0x0e,0x0a,0x0e,0x11,0x00,0x00, //
+ 0x18,0x19,0x02,0x04,0x08,0x13,0x03,0x00, // %
+ 0x04,0x0a,0x0a,0x0c,0x15,0x12,0x0d,0x00, // &
+ 0x04,0x04,0x08,0x00,0x00,0x00,0x00,0x00, // '
+
+ 0x02,0x04,0x08,0x08,0x08,0x04,0x02,0x00, // (
+ 0x08,0x04,0x02,0x02,0x02,0x04,0x08,0x00, // )
+ 0x00,0x04,0x15,0x0e,0x15,0x04,0x00,0x00, // *
+ 0x00,0x04,0x04,0x1f,0x04,0x04,0x00,0x00, // +
+ 0x00,0x00,0x00,0x00,0x08,0x08,0x10,0x00, // ,
+ 0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00, // -
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00, // .
+ 0x00,0x01,0x02,0x04,0x08,0x10,0x00,0x00, // /
+
+ 0x0e,0x11,0x13,0x15,0x19,0x11,0x0e,0x00, // 0
+ 0x04,0x0c,0x04,0x04,0x04,0x04,0x0e,0x00, // 1
+ 0x0e,0x11,0x01,0x06,0x08,0x10,0x1f,0x00, // 2
+ 0x1f,0x01,0x02,0x06,0x01,0x11,0x0e,0x00, // 3
+ 0x02,0x06,0x0a,0x12,0x1f,0x02,0x02,0x00, // 4
+ 0x1f,0x10,0x1e,0x01,0x01,0x11,0x0e,0x00, // 5
+ 0x07,0x08,0x10,0x1e,0x11,0x11,0x0e,0x00, // 6
+ 0x1f,0x01,0x02,0x04,0x08,0x08,0x08,0x00, // 7
+
+ 0x0e,0x11,0x11,0x0e,0x11,0x11,0x0e,0x00, // 8
+ 0x0e,0x11,0x11,0x0f,0x01,0x02,0x1c,0x00, // 9
+ 0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00, // :
+ 0x00,0x00,0x04,0x00,0x04,0x04,0x08,0x00, // ;
+ 0x02,0x04,0x08,0x10,0x08,0x04,0x02,0x00, // <
+ 0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00, // =
+ 0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00, // >
+ 0x0e,0x11,0x01,0x02,0x04,0x00,0x04,0x00 // ?
+};
+
+
+VIDEO_START( sapi1 )
+{
+ sapi1_state *state = machine.driver_data<sapi1_state>();
+ state->m_refresh_counter = 0;
+}
+
+SCREEN_UPDATE_IND16( sapi1 )
+{
+ sapi1_state *state = screen.machine().driver_data<sapi1_state>();
+ int x,y,j,b;
+ UINT16 addr;
+ int xpos;
+
+ for(y = 0; y < 24; y++ )
+ {
+ addr = y*64;
+ xpos = 0;
+ for(x = 0; x < 40; x++ )
+ {
+ UINT8 code = state->m_sapi_video_ram[addr + x];
+ UINT8 attr = (code >> 6) & 3;
+ code &= 0x3f;
+ for(j = 0; j < 9; j++ )
+ {
+ for(b = 0; b < 6; b++ )
+ {
+ UINT8 val;
+ if (j==8) {
+ if (attr==2) {
+ val = (state->m_refresh_counter & 0x20) ? 1 : 0;
+ } else {
+ val = 0;
+ }
+ } else {
+ val = (MHB2501[code*8 + j] >> (5-b)) & 1;
+ if (attr==1) {
+ val = (state->m_refresh_counter & 0x20) ? val : 0;
+ }
+ }
+ if(attr==3) {
+ bitmap.pix16(y*9+j, xpos+2*b ) = val;
+ bitmap.pix16(y*9+j, xpos+2*b+1 ) = val;
+ } else {
+ bitmap.pix16(y*9+j, xpos+b ) = val;
+ }
+ }
+ }
+ xpos+= (attr==3) ? 12 : 6;
+ if (xpos>=6*40) break;
+ }
+ }
+ state->m_refresh_counter++;
+ return 0;
+}
+
+
+VIDEO_START( sapizps3 )
+{
+}
+
+SCREEN_UPDATE_IND16( sapizps3 )
+{
+ return 0;
+}
diff --git a/src/mess/video/special.c b/src/mess/video/special.c
new file mode 100644
index 00000000000..dae46d939ff
--- /dev/null
+++ b/src/mess/video/special.c
@@ -0,0 +1,155 @@
+/***************************************************************************
+
+ Specialist video driver by Miodrag Milanovic
+
+ 15/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "includes/special.h"
+
+
+VIDEO_START( special )
+{
+}
+
+SCREEN_UPDATE_IND16( special )
+{
+ special_state *state = screen.machine().driver_data<special_state>();
+ UINT8 code;
+ int y, x, b;
+
+ for (x = 0; x < 48; x++)
+ {
+ for (y = 0; y < 256; y++)
+ {
+ code = state->m_p_videoram[y + x*256];
+ for (b = 7; b >= 0; b--)
+ bitmap.pix16(y, x*8+(7-b)) = (code >> b) & 0x01;
+ }
+ }
+ return 0;
+}
+VIDEO_START( specialp )
+{
+}
+
+SCREEN_UPDATE_IND16( specialp )
+{
+ special_state *state = screen.machine().driver_data<special_state>();
+ UINT8 code;
+ int y, x, b;
+
+ for (x = 0; x < 64; x++)
+ {
+ for (y = 0; y < 256; y++)
+ {
+ code = state->m_p_videoram[y + x*256];
+ for (b = 7; b >= 0; b--)
+ bitmap.pix16(y, x*8+(7-b)) = (code >> b) & 0x01;
+ }
+ }
+ return 0;
+}
+
+
+const rgb_t specimx_palette[16] = {
+ MAKE_RGB(0x00, 0x00, 0x00), // 0
+ MAKE_RGB(0x00, 0x00, 0xaa), // 1
+ MAKE_RGB(0x00, 0xaa, 0x00), // 2
+ MAKE_RGB(0x00, 0xaa, 0xaa), // 3
+ MAKE_RGB(0xaa, 0x00, 0x00), // 4
+ MAKE_RGB(0xaa, 0x00, 0xaa), // 5
+ MAKE_RGB(0xaa, 0x55, 0x00), // 6
+ MAKE_RGB(0xaa, 0xaa, 0xaa), // 7
+ MAKE_RGB(0x55, 0x55, 0x55), // 8
+ MAKE_RGB(0x55, 0x55, 0xff), // 9
+ MAKE_RGB(0x55, 0xff, 0x55), // A
+ MAKE_RGB(0x55, 0xff, 0xff), // B
+ MAKE_RGB(0xff, 0x55, 0x55), // C
+ MAKE_RGB(0xff, 0x55, 0xff), // D
+ MAKE_RGB(0xff, 0xff, 0x55), // E
+ MAKE_RGB(0xff, 0xff, 0xff) // F
+};
+
+PALETTE_INIT( specimx )
+{
+ palette_set_colors(machine, 0, specimx_palette, ARRAY_LENGTH(specimx_palette));
+}
+
+
+VIDEO_START( specimx )
+{
+ special_state *state = machine.driver_data<special_state>();
+ state->m_specimx_colorram = auto_alloc_array(machine, UINT8, 0x3000);
+ memset(state->m_specimx_colorram,0x70,0x3000);
+}
+
+SCREEN_UPDATE_IND16( specimx )
+{
+ special_state *state = screen.machine().driver_data<special_state>();
+ UINT8 code, color;
+ int y, x, b;
+
+ for (x = 0; x < 48; x++)
+ {
+ for (y = 0; y < 256; y++)
+ {
+ code = state->m_ram->pointer()[0x9000 + y + x*256];
+ color = state->m_specimx_colorram[y + x*256];
+ for (b = 7; b >= 0; b--)
+ bitmap.pix16(y, x*8+(7-b)) = ((code >> b) & 0x01)==0 ? color & 0x0f : (color >> 4)& 0x0f ;
+ }
+ }
+ return 0;
+}
+
+static const rgb_t erik_palette[8] = {
+ MAKE_RGB(0x00, 0x00, 0x00), // 0
+ MAKE_RGB(0x00, 0x00, 0xff), // 1
+ MAKE_RGB(0xff, 0x00, 0x00), // 2
+ MAKE_RGB(0xff, 0x00, 0xff), // 3
+ MAKE_RGB(0x00, 0xff, 0x00), // 4
+ MAKE_RGB(0x00, 0xff, 0xff), // 5
+ MAKE_RGB(0xff, 0xff, 0x00), // 6
+ MAKE_RGB(0xff, 0xff, 0xff) // 7
+};
+
+PALETTE_INIT( erik )
+{
+ palette_set_colors(machine, 0, erik_palette, ARRAY_LENGTH(erik_palette));
+}
+
+
+VIDEO_START( erik )
+{
+}
+
+SCREEN_UPDATE_IND16( erik )
+{
+ special_state *state = screen.machine().driver_data<special_state>();
+ UINT8 code1, code2, color1, color2;
+ int y, x, b;
+ UINT8 *erik_video_ram_p1, *erik_video_ram_p2;
+
+ erik_video_ram_p1 = state->m_ram->pointer() + 0x9000;
+ erik_video_ram_p2 = state->m_ram->pointer() + 0xd000;
+
+ for (x = 0; x < 48; x++)
+ {
+ for (y = 0; y < 256; y++)
+ {
+ code1 = erik_video_ram_p1[y + x*256];
+ code2 = erik_video_ram_p2[y + x*256];
+
+ for (b = 7; b >= 0; b--)
+ {
+ color1 = ((code1 >> b) & 0x01)==0 ? state->m_erik_background : state->m_erik_color_1;
+ color2 = ((code2 >> b) & 0x01)==0 ? state->m_erik_background : state->m_erik_color_2;
+ bitmap.pix16(y, x*8+(7-b)) = color1 | color2;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/mess/video/spectrum.c b/src/mess/video/spectrum.c
new file mode 100644
index 00000000000..6fbed0a07c4
--- /dev/null
+++ b/src/mess/video/spectrum.c
@@ -0,0 +1,608 @@
+/***************************************************************************
+
+ spectrum.c
+
+ Functions to emulate the video hardware of the ZX Spectrum.
+
+ Changes:
+
+ DJR 08/02/00 - Added support for FLASH 1.
+ DJR 16/05/00 - Support for TS2068/TC2048 hires and 64 column modes.
+ DJR 19/05/00 - Speeded up Spectrum 128 screen refresh.
+ DJR 23/05/00 - Preliminary support for border colour emulation.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/spectrum.h"
+
+/***************************************************************************
+ Start the video hardware emulation.
+***************************************************************************/
+VIDEO_START( spectrum )
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ state->m_LastDisplayedBorderColor = -1;
+ state->m_frame_invert_count = 25;
+ state->m_frame_number = 0;
+ state->m_flash_invert = 0;
+
+ spectrum_EventList_Initialise(machine, 30000);
+
+ state->m_retrace_cycles = SPEC_RETRACE_CYCLES;
+
+ state->m_screen_location = state->m_video_ram;
+}
+
+VIDEO_START( spectrum_128 )
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ state->m_LastDisplayedBorderColor = -1;
+ state->m_frame_invert_count = 25;
+ state->m_frame_number = 0;
+ state->m_flash_invert = 0;
+
+ spectrum_EventList_Initialise(machine, 30000);
+
+ state->m_retrace_cycles = SPEC128_RETRACE_CYCLES;
+}
+
+
+/* return the color to be used inverting FLASHing colors if necessary */
+INLINE unsigned char get_display_color (unsigned char color, int invert)
+{
+ if (invert && (color & 0x80))
+ return (color & 0xc0) + ((color & 0x38) >> 3) + ((color & 0x07) << 3);
+ else
+ return color;
+}
+
+/* Code to change the FLASH status every 25 frames. Note this must be
+ independent of frame skip etc. */
+SCREEN_VBLANK( spectrum )
+{
+ // rising edge
+ if (vblank_on)
+ {
+ spectrum_state *state = screen.machine().driver_data<spectrum_state>();
+ EVENT_LIST_ITEM *pItem;
+ int NumItems;
+
+ state->m_frame_number++;
+ if (state->m_frame_number >= state->m_frame_invert_count)
+ {
+ state->m_frame_number = 0;
+ state->m_flash_invert = !state->m_flash_invert;
+ }
+
+ /* Empty event buffer for undisplayed frames noting the last border
+ colour (in case colours are not changed in the next frame). */
+ NumItems = spectrum_EventList_NumEvents(screen.machine());
+ if (NumItems)
+ {
+ pItem = spectrum_EventList_GetFirstItem(screen.machine());
+ spectrum_border_set_last_color ( screen.machine(), pItem[NumItems-1].Event_Data );
+ spectrum_EventList_Reset(screen.machine());
+ spectrum_EventList_SetOffsetStartTime ( screen.machine(), screen.machine().firstcpu->attotime_to_cycles(screen.scan_period() * screen.vpos()) );
+ logerror ("Event log reset in callback fn.\n");
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ Update the spectrum screen display.
+
+ The screen consists of 312 scanlines as follows:
+ 64 border lines (the last 48 are actual border lines; the others may be
+ border lines or vertical retrace)
+ 192 screen lines
+ 56 border lines
+
+ Each screen line has 48 left border pixels, 256 screen pixels and 48 right
+ border pixels.
+
+ Each scanline takes 224 T-states divided as follows:
+ 128 Screen (reads a screen and ATTR byte [8 pixels] every 4 T states)
+ 24 Right border
+ 48 Horizontal retrace
+ 24 Left border
+
+ The 128K Spectrums have only 63 scanlines before the TV picture (311 total)
+ and take 228 T-states per scanline.
+
+***************************************************************************/
+
+INLINE void spectrum_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = (UINT16)color;
+}
+
+SCREEN_UPDATE_IND16( spectrum )
+{
+ /* for now do a full-refresh */
+ spectrum_state *state = screen.machine().driver_data<spectrum_state>();
+ int x, y, b, scrx, scry;
+ unsigned short ink, pap;
+ unsigned char *attr, *scr;
+ int full_refresh = 1;
+
+ scr=state->m_screen_location;
+
+ for (y=0; y<192; y++)
+ {
+ scrx=SPEC_LEFT_BORDER;
+ scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0);
+ attr=state->m_screen_location + ((scry>>3)*32) + 0x1800;
+
+ for (x=0;x<32;x++)
+ {
+ /* Get ink and paper colour with bright */
+ if (state->m_flash_invert && (*attr & 0x80))
+ {
+ ink=((*attr)>>3) & 0x0f;
+ pap=((*attr) & 0x07) + (((*attr)>>3) & 0x08);
+ }
+ else
+ {
+ ink=((*attr) & 0x07) + (((*attr)>>3) & 0x08);
+ pap=((*attr)>>3) & 0x0f;
+ }
+
+ for (b=0x80;b!=0;b>>=1)
+ {
+ if (*scr&b)
+ spectrum_plot_pixel(bitmap,scrx++,SPEC_TOP_BORDER+scry,ink);
+ else
+ spectrum_plot_pixel(bitmap,scrx++,SPEC_TOP_BORDER+scry,pap);
+ }
+
+ scr++;
+ attr++;
+ }
+ }
+
+ spectrum_border_draw(screen.machine(), bitmap, full_refresh,
+ SPEC_TOP_BORDER, SPEC_DISPLAY_YSIZE, SPEC_BOTTOM_BORDER,
+ SPEC_LEFT_BORDER, SPEC_DISPLAY_XSIZE, SPEC_RIGHT_BORDER,
+ SPEC_LEFT_BORDER_CYCLES, SPEC_DISPLAY_XSIZE_CYCLES,
+ SPEC_RIGHT_BORDER_CYCLES, state->m_retrace_cycles, 200, 0xfe);
+ return 0;
+}
+
+
+static const rgb_t spectrum_palette[16] = {
+ MAKE_RGB(0x00, 0x00, 0x00),
+ MAKE_RGB(0x00, 0x00, 0xbf),
+ MAKE_RGB(0xbf, 0x00, 0x00),
+ MAKE_RGB(0xbf, 0x00, 0xbf),
+ MAKE_RGB(0x00, 0xbf, 0x00),
+ MAKE_RGB(0x00, 0xbf, 0xbf),
+ MAKE_RGB(0xbf, 0xbf, 0x00),
+ MAKE_RGB(0xbf, 0xbf, 0xbf),
+ MAKE_RGB(0x00, 0x00, 0x00),
+ MAKE_RGB(0x00, 0x00, 0xff),
+ MAKE_RGB(0xff, 0x00, 0x00),
+ MAKE_RGB(0xff, 0x00, 0xff),
+ MAKE_RGB(0x00, 0xff, 0x00),
+ MAKE_RGB(0x00, 0xff, 0xff),
+ MAKE_RGB(0xff, 0xff, 0x00),
+ MAKE_RGB(0xff, 0xff, 0xff)
+};
+/* Initialise the palette */
+PALETTE_INIT( spectrum )
+{
+ palette_set_colors(machine, 0, spectrum_palette, ARRAY_LENGTH(spectrum_palette));
+}
+
+/***************************************************************************
+ Border engine:
+
+ Functions for drawing multi-coloured screen borders using the
+ Event List processing.
+
+Changes:
+
+28/05/2000 DJR - Initial implementation.
+08/06/2000 DJR - Now only uses events with the correct ID value.
+28/06/2000 DJR - draw_border now uses full_refresh flag.
+
+***************************************************************************/
+
+/* Force the border to be redrawn on the next frame */
+void spectrum_border_force_redraw (running_machine &machine)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ state->m_LastDisplayedBorderColor = -1;
+}
+
+/* Set the last border colour to have been displayed. Used when loading snap
+ shots and to record the last colour change in a frame that was skipped. */
+void spectrum_border_set_last_color(running_machine &machine, int NewColor)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ state->m_CurrBorderColor = NewColor;
+}
+
+void spectrum_border_draw(running_machine &machine, bitmap_ind16 &bitmap,
+ int full_refresh, /* Full refresh flag */
+ int TopBorderLines, /* Border lines before actual screen */
+ int ScreenLines, /* Screen height in pixels */
+ int BottomBorderLines, /* Border lines below screen */
+ int LeftBorderPixels, /* Border pixels to the left of each screen line */
+ int ScreenPixels, /* Width of actual screen in pixels */
+ int RightBorderPixels, /* Border pixels to the right of each screen line */
+ int LeftBorderCycles, /* Cycles taken to draw left border of each scan line */
+ int ScreenCycles, /* Cycles taken to draw screen data part of each scan line */
+ int RightBorderCycles, /* Cycles taken to draw right border of each scan line */
+ int HorizontalRetraceCycles, /* Cycles taken to return to LHS of CRT after each scan line */
+ int VRetraceTime, /* Cycles taken before start of first border line */
+ int EventID) /* Event ID of border messages */
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ EVENT_LIST_ITEM *pItem;
+ int TotalScreenHeight = TopBorderLines+ScreenLines+BottomBorderLines;
+ int TotalScreenWidth = LeftBorderPixels+ScreenPixels+RightBorderPixels;
+ int DisplayCyclesPerLine = LeftBorderCycles+ScreenCycles+RightBorderCycles;
+ int CyclesPerLine = DisplayCyclesPerLine+HorizontalRetraceCycles;
+ int CyclesSoFar = 0;
+ int NumItems, CurrItem = 0, NextItem;
+ int Count, ScrX, NextScrX, ScrY;
+ rectangle r;
+
+ pItem = spectrum_EventList_GetFirstItem(machine);
+ NumItems = spectrum_EventList_NumEvents(machine);
+
+ for (Count = 0; Count < NumItems; Count++)
+ {
+// logerror ("Event no %05d, ID = %04x, data = %04x, time = %ld\n", Count, pItem[Count].Event_ID, pItem[Count].Event_Data, (long) pItem[Count].Event_Time);
+ }
+
+ /* Find the first and second events with the correct ID */
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID))
+ CurrItem++;
+ NextItem = CurrItem + 1;
+ while ((NextItem < NumItems) && (pItem[NextItem].Event_ID != EventID))
+ NextItem++;
+
+ /* Single border colour */
+ if ((CurrItem < NumItems) && (NextItem >= NumItems))
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+
+ if ((NextItem >= NumItems) && (state->m_CurrBorderColor==state->m_LastDisplayedBorderColor) && !full_refresh)
+ {
+ /* Do nothing if border colour has not changed */
+ }
+ else if (NextItem >= NumItems)
+ {
+ /* Single border colour - this is not strictly correct as the
+ colour change may have occurred midway through the frame
+ or after the last visible border line however the whole
+ border would be redrawn in the correct colour during the
+ next frame anyway! */
+ r.set(0, TotalScreenWidth-1, 0, TopBorderLines-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+
+ r.set(0, LeftBorderPixels-1, TopBorderLines, TopBorderLines+ScreenLines-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+
+ r.setx(LeftBorderPixels+ScreenPixels, TotalScreenWidth-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+
+ r.set(0, TotalScreenWidth-1, TopBorderLines+ScreenLines, TotalScreenHeight-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+
+// logerror ("Setting border colour to %d (Last = %d, Full Refresh = %d)\n", state->m_CurrBorderColor, state->m_LastDisplayedBorderColor, full_refresh);
+ state->m_LastDisplayedBorderColor = state->m_CurrBorderColor;
+ }
+ else
+ {
+ /* Multiple border colours */
+
+ /* Process entries before first displayed line */
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_Time <= VRetraceTime))
+ {
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+ }
+
+ /* Draw top border */
+ CyclesSoFar = VRetraceTime;
+ for (ScrY = 0; ScrY < TopBorderLines; ScrY++)
+ {
+ r.min_x = 0;
+ r.min_y = r.max_y = ScrY;
+ if ((CurrItem >= NumItems) || (pItem[CurrItem].Event_Time >= (CyclesSoFar+DisplayCyclesPerLine)))
+ {
+ /* Single colour on line */
+ r.max_x = TotalScreenWidth-1;
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ }
+ else
+ {
+ /* Multiple colours on a line */
+ ScrX = (int)(pItem[CurrItem].Event_Time - CyclesSoFar) * (float)TotalScreenWidth / (float)DisplayCyclesPerLine;
+ r.max_x = ScrX-1;
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_Time < (CyclesSoFar+DisplayCyclesPerLine)))
+ {
+ NextScrX = (int)(pItem[CurrItem].Event_Time - CyclesSoFar) * (float)TotalScreenWidth / (float)DisplayCyclesPerLine;
+ r.setx(ScrX, NextScrX-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ ScrX = NextScrX;
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+ }
+ r.setx(ScrX, TotalScreenWidth-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ }
+
+ /* Process colour changes during horizontal retrace */
+ CyclesSoFar+= CyclesPerLine;
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_Time <= CyclesSoFar))
+ {
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+ }
+ }
+
+ /* Draw left and right borders next to screen lines */
+ for (ScrY = TopBorderLines; ScrY < (TopBorderLines+ScreenLines); ScrY++)
+ {
+ /* Draw left hand border */
+ r.min_x = 0;
+ r.min_y = r.max_y = ScrY;
+
+ if ((CurrItem >= NumItems) || (pItem[CurrItem].Event_Time >= (CyclesSoFar+LeftBorderCycles)))
+ {
+ /* Single colour */
+ r.max_x = LeftBorderPixels-1;
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ }
+ else
+ {
+ /* Multiple colours */
+ ScrX = (int)(pItem[CurrItem].Event_Time - CyclesSoFar) * (float)LeftBorderPixels / (float)LeftBorderCycles;
+ r.max_x = ScrX-1;
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_Time < (CyclesSoFar+LeftBorderCycles)))
+ {
+ NextScrX = (int)(pItem[CurrItem].Event_Time - CyclesSoFar) * (float)LeftBorderPixels / (float)LeftBorderCycles;
+ r.setx(ScrX, NextScrX-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ ScrX = NextScrX;
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+ }
+ r.setx(ScrX, LeftBorderPixels-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ }
+
+ /* Process colour changes during screen draw */
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_Time <= (CyclesSoFar+LeftBorderCycles+ScreenCycles)))
+ {
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+ }
+
+ /* Draw right hand border */
+ r.min_x = LeftBorderPixels+ScreenPixels;
+ if ((CurrItem >= NumItems) || (pItem[CurrItem].Event_Time >= (CyclesSoFar+DisplayCyclesPerLine)))
+ {
+ /* Single colour */
+ r.max_x = TotalScreenWidth-1;
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ }
+ else
+ {
+ /* Multiple colours */
+ ScrX = LeftBorderPixels + ScreenPixels + (int)(pItem[CurrItem].Event_Time - CyclesSoFar) * (float)RightBorderPixels / (float)RightBorderCycles;
+ r.max_x = ScrX-1;
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_Time < (CyclesSoFar+DisplayCyclesPerLine)))
+ {
+ NextScrX = LeftBorderPixels + ScreenPixels + (int)(pItem[CurrItem].Event_Time - CyclesSoFar) * (float)RightBorderPixels / (float)RightBorderCycles;
+ r.setx(ScrX, NextScrX-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ ScrX = NextScrX;
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+ }
+ r.setx(ScrX, TotalScreenWidth-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ }
+
+ /* Process colour changes during horizontal retrace */
+ CyclesSoFar+= CyclesPerLine;
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_Time <= CyclesSoFar))
+ {
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+ }
+ }
+
+ /* Draw bottom border */
+ for (ScrY = TopBorderLines+ScreenLines; ScrY < TotalScreenHeight; ScrY++)
+ {
+ r.min_x = 0;
+ r.min_y = r.max_y = ScrY;
+ if ((CurrItem >= NumItems) || (pItem[CurrItem].Event_Time >= (CyclesSoFar+DisplayCyclesPerLine)))
+ {
+ /* Single colour on line */
+ r.max_x = TotalScreenWidth-1;
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ }
+ else
+ {
+ /* Multiple colours on a line */
+ ScrX = (int)(pItem[CurrItem].Event_Time - CyclesSoFar) * (float)TotalScreenWidth / (float)DisplayCyclesPerLine;
+ r.max_x = ScrX-1;
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_Time < (CyclesSoFar+DisplayCyclesPerLine)))
+ {
+ NextScrX = (int)(pItem[CurrItem].Event_Time - CyclesSoFar) * (float)TotalScreenWidth / (float)DisplayCyclesPerLine;
+ r.setx(ScrX, NextScrX-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ ScrX = NextScrX;
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+ }
+ r.setx(ScrX, TotalScreenWidth-1);
+ bitmap.fill(machine.pens[state->m_CurrBorderColor], r);
+ }
+
+ /* Process colour changes during horizontal retrace */
+ CyclesSoFar+= CyclesPerLine;
+ while ((CurrItem < NumItems) && (pItem[CurrItem].Event_Time <= CyclesSoFar))
+ {
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ do {
+ CurrItem++;
+ } while ((CurrItem < NumItems) && (pItem[CurrItem].Event_ID != EventID));
+ }
+ }
+
+ /* Process colour changes after last displayed line */
+ while (CurrItem < NumItems)
+ {
+ if (pItem[CurrItem].Event_ID == EventID)
+ state->m_CurrBorderColor = pItem[CurrItem].Event_Data;
+ CurrItem++;
+ }
+
+ /* Set value to ensure redraw on next frame */
+ state->m_LastDisplayedBorderColor = -1;
+
+// logerror ("Multi coloured border drawn (last colour = %d)\n", CurrBorderColor);
+ }
+
+ /* Assume all other routines have processed their data from the list */
+ spectrum_EventList_Reset(machine);
+ spectrum_EventList_SetOffsetStartTime ( machine, machine.firstcpu->attotime_to_cycles(machine.primary_screen->scan_period() * machine.primary_screen->vpos()));
+}
+
+
+/* initialise */
+
+/* if the CPU is the controlling factor, the size of the buffer
+can be setup as:
+
+Number_of_CPU_Cycles_In_A_Frame/Minimum_Number_Of_Cycles_Per_Instruction */
+void spectrum_EventList_Initialise(running_machine &machine, int NumEntries)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ state->m_pEventListBuffer = auto_alloc_array(machine, char, NumEntries);
+ state->m_TotalEvents = NumEntries;
+ state->m_CyclesPerFrame = 0;
+ spectrum_EventList_Reset(machine);
+}
+
+/* reset the change list */
+void spectrum_EventList_Reset(running_machine &machine)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ state->m_NumEvents = 0;
+ state->m_pCurrentItem = (EVENT_LIST_ITEM *)state->m_pEventListBuffer;
+}
+
+
+#ifdef UNUSED_FUNCTION
+/* add an event to the buffer */
+void EventList_AddItem(running_machine &machine, int ID, int Data, int Time)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ if (state->m_NumEvents < state->m_TotalEvents)
+ {
+ /* setup item only if there is space in the buffer */
+ state->m_pCurrentItem->Event_ID = ID;
+ state->m_pCurrentItem->Event_Data = Data;
+ state->m_pCurrentItem->Event_Time = Time;
+
+ state->m_pCurrentItem++;
+ state->m_NumEvents++;
+ }
+}
+#endif
+
+/* set the start time for use with EventList_AddItemOffset usually this will
+ be cpu_getcurrentcycles() at the time that the screen is being refreshed */
+void spectrum_EventList_SetOffsetStartTime(running_machine &machine, int StartTime)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ state->m_LastFrameStartTime = StartTime;
+}
+
+/* add an event to the buffer with a time index offset from a specified time */
+void spectrum_EventList_AddItemOffset(running_machine &machine, int ID, int Data, int Time)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+
+ if (!state->m_CyclesPerFrame)
+ state->m_CyclesPerFrame = (int)(machine.firstcpu->unscaled_clock() / machine.primary_screen->frame_period().attoseconds); //totalcycles(); //_(int)(cpunum_get_clock(0) / machine.config()->frames_per_second);
+
+ if (state->m_NumEvents < state->m_TotalEvents)
+ {
+ /* setup item only if there is space in the buffer */
+ state->m_pCurrentItem->Event_ID = ID;
+ state->m_pCurrentItem->Event_Data = Data;
+
+ Time -= state->m_LastFrameStartTime;
+ if ((Time < 0) || ((Time == 0) && state->m_NumEvents))
+ Time += state->m_CyclesPerFrame;
+ state->m_pCurrentItem->Event_Time = Time;
+
+ state->m_pCurrentItem++;
+ state->m_NumEvents++;
+ }
+}
+
+/* get number of events */
+int spectrum_EventList_NumEvents(running_machine &machine)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ return state->m_NumEvents;
+}
+
+/* get first item in buffer */
+EVENT_LIST_ITEM *spectrum_EventList_GetFirstItem(running_machine &machine)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ return (EVENT_LIST_ITEM *)state->m_pEventListBuffer;
+}
diff --git a/src/mess/video/ssystem3.c b/src/mess/video/ssystem3.c
new file mode 100644
index 00000000000..1e022dc5777
--- /dev/null
+++ b/src/mess/video/ssystem3.c
@@ -0,0 +1,238 @@
+/******************************************************************************
+ PeT mess@utanet.at
+******************************************************************************/
+
+#include "emu.h"
+#include "includes/ssystem3.h"
+
+void ssystem3_lcd_reset(running_machine &machine)
+{
+ ssystem3_state *state = machine.driver_data<ssystem3_state>();
+ state->m_lcd.count=0; state->m_lcd.clock=1;
+}
+
+void ssystem3_lcd_write(running_machine &machine, int clock, int data)
+{
+ ssystem3_state *state = machine.driver_data<ssystem3_state>();
+ if (clock&&!state->m_lcd.clock) {
+ state->m_lcd.data[state->m_lcd.count/8]&=~(1<<(state->m_lcd.count&7));
+ if (data) state->m_lcd.data[state->m_lcd.count/8]|=1<<(state->m_lcd.count&7);
+ if (state->m_lcd.count+1==40) {
+ logerror("%.4x lcd %02x%02x%02x%02x%02x\n",(int)cpu_get_pc(machine.device("maincpu")),
+ state->m_lcd.data[0], state->m_lcd.data[1], state->m_lcd.data[2], state->m_lcd.data[3], state->m_lcd.data[4]);
+ }
+ state->m_lcd.count=(state->m_lcd.count+1)%40;
+ }
+ state->m_lcd.clock=clock;
+}
+
+
+
+static const unsigned char ssystem3_palette[] =
+{
+ 0,12,12,
+ 80,82,75,
+ 0,12,12
+};
+
+
+PALETTE_INIT( ssystem3 )
+{
+ int i;
+
+ for ( i = 0; i < sizeof(ssystem3_palette) / 3; i++ ) {
+ palette_set_color_rgb(machine, i, ssystem3_palette[i*3], ssystem3_palette[i*3+1], ssystem3_palette[i*3+2]);
+ }
+}
+
+
+VIDEO_START( ssystem3 )
+{
+ ssystem3_state *state = machine.driver_data<ssystem3_state>();
+ // artwork seams to need this
+ state->m_videoram = auto_alloc_array(machine, UINT8, 6 * 2 + 24);
+}
+
+
+static const char led[]={
+ " aaaaaaaaaaaa\r"
+ " f aaaaaaaaaa b\r"
+ " ff aaaaaaaa bb\r"
+ " fff aaaaaa bbb\r"
+ " ffff bbbb\r"
+ " ffff bbbb\r"
+ " ffff bbbb\r"
+ " ffff bbbb\r"
+ " ffff bbbb\r"
+ " ffff bbbb\r"
+ " fff bbb\r"
+ " f gggggggg b\r"
+ " gggggggggggg\r"
+ " gggggggggggg\r"
+ " e gggggggg c\r"
+ " eee ccc\r"
+ " eeee cccc\r"
+ " eeee cccc\r"
+ "eeee cccc\r"
+ "eeee cccc\r"
+ "eeee cccc\r"
+ "eeee cccc\r"
+ "eee dddddd ccc\r"
+ "ee dddddddd cc\r"
+ "e dddddddddd c\r"
+ " dddddddddddd"
+};
+
+static void ssystem3_draw_7segment(bitmap_ind16 &bitmap,int value, int x, int y)
+{
+ int i, xi, yi, mask, color;
+
+ for (i=0, xi=0, yi=0; led[i]; i++) {
+ mask=0;
+ switch (led[i]) {
+ case 'a': mask=0x80; break;
+ case 'b': mask=0x40; break;
+ case 'c': mask=0x20; break;
+ case 'd': mask=0x10; break;
+ case 'e': mask=8; break;
+ case 'f': mask=4; break;
+ case 'g': mask=2; break;
+ case 'h':
+ // this is more likely wired to the separate leds
+ mask=1;
+ break;
+ }
+
+ if (mask!=0) {
+ color=(value&mask)?1:0;
+ bitmap.pix16(y+yi, x+xi) = color;
+ }
+ if (led[i]!='\r') xi++;
+ else { yi++, xi=0; }
+ }
+}
+
+static const struct {
+ int x,y;
+} ssystem3_led_pos[5]={
+ {150,123},
+ {170,123},
+ {200,123},
+ {220,123},
+ {125,123}
+};
+
+static const char single_led[]=
+" c 1 1\r"
+" bb ccccc bb 1 1\r"
+" bb c bb 1 1\r"
+" bb bb bb bb 1 1\r"
+" bb bbbbbbbbbbb bb 111 111\r"
+" 1 1\r"
+" 99 9999999 99 1 1\r"
+" 99 99 1 1\r"
+" 88888888888 9 1 1\r"
+" 88 8 9999\r"
+" 8888 6666666 8 9999\r"
+" 8888 6 6\r"
+" 6 777 6\r"
+" 6 777 6\r"
+" 6 777 6\r"
+" 6 777 6\r"
+" 6 77777 6\r"
+" 6 77777 6 2 2 4\r"
+" 6 7777777 6 2 2 4\r"
+" 6 7777777 6 2 2 4\r"
+" 6 777777777 6 2 2 44444\r"
+" 6 777777777 6 2 2 4\r"
+" 6 77777777777 6 2 2 33433\r"
+" 6 7 6 2 2 4\r"
+" 6666666 7 6666666 2 2 4\r"
+" 7 2 2 4\r"
+" 77777777777777777\r"
+"\r"
+"\r"
+"\r"
+" 5555555555555555555 000000 000000 00 00 0000000 00 00 00000000 00 00 00 0000000\r"
+"5 5 0000000 00000000 000 000 00000000 00 00 00000000 00 000 00 00000000\r"
+"5 5 00 00 00 0000 0000 00 00 00 00 00 00 0000 00 00\r"
+"5 5 00 00 00 00 00 00 00 00000000 00 00 00 00 00 00 00 00 0000\r"
+"5 5 00 00 00 00 00 00 00 0000000 00 00 00 00 00 0000 00 00\r"
+"5 5 0000000 00000000 00 0000 00 00 00000000 00 00 00 000 00000000\r"
+" 55555555 55555555 000000 000000 00 00 00 00 000000 00 00 00 00 0000000"
+;
+
+static void ssystem3_draw_led(bitmap_ind16 &bitmap,INT16 color, int x, int y, int ch)
+{
+ int j, xi=0;
+ for (j=0; single_led[j]; j++) {
+ switch (single_led[j]) {
+ default:
+ if (ch==single_led[j]) {
+ bitmap.pix16(y, x+xi) = color;
+ }
+ xi++;
+ break;
+ case ' ':
+ xi++;
+ break;
+ case '\r':
+ xi=0;
+ y++;
+ break;
+ };
+ }
+}
+
+SCREEN_UPDATE_IND16( ssystem3 )
+{
+ ssystem3_state *state = screen.machine().driver_data<ssystem3_state>();
+ int i;
+
+ for (i=0; i<4; i++) {
+ ssystem3_draw_7segment(bitmap, state->m_lcd.data[1+i], ssystem3_led_pos[i].x, ssystem3_led_pos[i].y);
+ }
+
+ ssystem3_draw_led(bitmap, state->m_lcd.data[0]&1?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '0'); //?
+ ssystem3_draw_led(bitmap, state->m_lcd.data[0]&2?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '5');
+ ssystem3_draw_led(bitmap, state->m_lcd.data[0]&4?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '7');
+ ssystem3_draw_led(bitmap, state->m_lcd.data[0]&8?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, 'b');
+ ssystem3_draw_led(bitmap, state->m_lcd.data[0]&0x10?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '9');
+ ssystem3_draw_led(bitmap, state->m_lcd.data[0]&0x20?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '8');
+ ssystem3_draw_led(bitmap, state->m_lcd.data[0]&0x40?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, 'c');
+ ssystem3_draw_led(bitmap, state->m_lcd.data[0]&0x80?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '6');
+ ssystem3_draw_led(bitmap, state->m_lcd.data[1]&1?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '2');
+ ssystem3_draw_led(bitmap, state->m_lcd.data[2]&1?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '1'); //?
+ ssystem3_draw_led(bitmap, state->m_lcd.data[3]&1?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '3');
+ ssystem3_draw_led(bitmap, state->m_lcd.data[4]&1?1:0, ssystem3_led_pos[4].x, ssystem3_led_pos[4].y, '4');
+
+ if (screen.machine().root_device().ioport("Configuration")->read()&1) { // playfield(optional device)
+ static const int lcd_signs_on[]={
+ 0, // empty
+ 1, // bauer
+ 3, // springer
+ 0x11, // l??ufer
+ 7, // turm
+ 0x1f, // dame
+ 0x17, // k??nig
+ 0
+ };
+ int y, x;
+ for (y=0; y<8; y++) {
+ for (x=0; x<8; x++) {
+ int figure, black;
+ int xp=263+x*22;
+ int yp=55+(y^7)*28;
+ ssystem3_playfield_getfigure(screen.machine(), x, y, &figure, &black);
+ ssystem3_draw_led(bitmap, lcd_signs_on[figure]&1?1:0, xp, yp, '6');
+ ssystem3_draw_led(bitmap, lcd_signs_on[figure]&2?1:0, xp, yp, '8');
+ ssystem3_draw_led(bitmap, lcd_signs_on[figure]&4?1:0, xp, yp, '9');
+ ssystem3_draw_led(bitmap, lcd_signs_on[figure]&8?1:0, xp, yp, 'b');
+ ssystem3_draw_led(bitmap, lcd_signs_on[figure]&0x10?1:0, xp, yp, 'c');
+ ssystem3_draw_led(bitmap, figure!=0 && black?1:0, xp, yp, '7');
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mess/video/stic.c b/src/mess/video/stic.c
new file mode 100644
index 00000000000..2dbd7d43944
--- /dev/null
+++ b/src/mess/video/stic.c
@@ -0,0 +1,187 @@
+#include "emu.h"
+#include "video/stic.h"
+#include "includes/intv.h"
+
+/* STIC variables */
+
+READ16_MEMBER( intv_state::intv_stic_r )
+{
+// intv_state *state = space->machine().driver_data<intv_state>();
+ //logerror("%x = stic_r(%x)\n",0,offset);
+ if (m_bus_copy_mode || !m_stic_handshake)
+ {
+ switch (offset)
+ {
+ case STIC_MXR + STIC_MOB0:
+ case STIC_MXR + STIC_MOB1:
+ case STIC_MXR + STIC_MOB2:
+ case STIC_MXR + STIC_MOB3:
+ case STIC_MXR + STIC_MOB4:
+ case STIC_MXR + STIC_MOB5:
+ case STIC_MXR + STIC_MOB6:
+ case STIC_MXR + STIC_MOB7:
+ return 0x3800 | (m_stic_registers[offset] & 0x07FF);
+ case STIC_MYR + STIC_MOB0:
+ case STIC_MYR + STIC_MOB1:
+ case STIC_MYR + STIC_MOB2:
+ case STIC_MYR + STIC_MOB3:
+ case STIC_MYR + STIC_MOB4:
+ case STIC_MYR + STIC_MOB5:
+ case STIC_MYR + STIC_MOB6:
+ case STIC_MYR + STIC_MOB7:
+ return 0x3000 | (m_stic_registers[offset] & 0x0FFF);
+ case STIC_MAR + STIC_MOB0:
+ case STIC_MAR + STIC_MOB1:
+ case STIC_MAR + STIC_MOB2:
+ case STIC_MAR + STIC_MOB3:
+ case STIC_MAR + STIC_MOB4:
+ case STIC_MAR + STIC_MOB5:
+ case STIC_MAR + STIC_MOB6:
+ case STIC_MAR + STIC_MOB7:
+ return m_stic_registers[offset] & 0x3FFF;
+ case STIC_MCR + STIC_MOB0:
+ case STIC_MCR + STIC_MOB1:
+ case STIC_MCR + STIC_MOB2:
+ case STIC_MCR + STIC_MOB3:
+ case STIC_MCR + STIC_MOB4:
+ case STIC_MCR + STIC_MOB5:
+ case STIC_MCR + STIC_MOB6:
+ case STIC_MCR + STIC_MOB7:
+ return 0x3C00 | (m_stic_registers[offset] & 0x03FF);
+ case STIC_GMR:
+ m_color_stack_mode = 1;
+ //logerror("Setting color stack mode\n");
+ /*** fall through ***/
+ case STIC_DER:
+ return 0x3FFF;
+ break;
+ case STIC_CSR + STIC_CSR0:
+ case STIC_CSR + STIC_CSR1:
+ case STIC_CSR + STIC_CSR2:
+ case STIC_CSR + STIC_CSR3:
+ case STIC_BCR:
+ return 0x3FF0 | (m_stic_registers[offset] & 0x000F);
+ case STIC_HDR:
+ case STIC_VDR:
+ return 0x3FF8 | (m_stic_registers[offset] & 0x0007);
+ case STIC_CBR:
+ return 0x3FFC | (m_stic_registers[offset] & 0x0003);
+ default:
+ //logerror("unmapped read from STIC register %02X\n", offset);
+ return 0x3FFF;
+ }
+ }
+ else { return (offset); }
+}
+
+WRITE16_MEMBER( intv_state::intv_stic_w )
+{
+ //intv_state *state = space->machine().driver_data<intv_state>();
+ intv_sprite_type *s;
+
+ //logerror("stic_w(%x) = %x\n",offset,data);
+ if (m_bus_copy_mode || !m_stic_handshake)
+ {
+ switch (offset)
+ {
+ /* X Positions */
+ case STIC_MXR + STIC_MOB0:
+ case STIC_MXR + STIC_MOB1:
+ case STIC_MXR + STIC_MOB2:
+ case STIC_MXR + STIC_MOB3:
+ case STIC_MXR + STIC_MOB4:
+ case STIC_MXR + STIC_MOB5:
+ case STIC_MXR + STIC_MOB6:
+ case STIC_MXR + STIC_MOB7:
+ s = &m_sprite[offset & (STIC_MOBS - 1)];
+ s->doublex = !!(data & STIC_MXR_XSIZE);
+ s->visible = !!(data & STIC_MXR_VIS);
+ s->coll = !!(data & STIC_MXR_COL);
+ s->xpos = (data & STIC_MXR_X);
+ break;
+ /* Y Positions */
+ case STIC_MYR + STIC_MOB0:
+ case STIC_MYR + STIC_MOB1:
+ case STIC_MYR + STIC_MOB2:
+ case STIC_MYR + STIC_MOB3:
+ case STIC_MYR + STIC_MOB4:
+ case STIC_MYR + STIC_MOB5:
+ case STIC_MYR + STIC_MOB6:
+ case STIC_MYR + STIC_MOB7:
+ s = &m_sprite[offset & (STIC_MOBS - 1)];
+ s->yflip = !!(data & STIC_MYR_YFLIP);
+ s->xflip = !!(data & STIC_MYR_XFLIP);
+ s->quady = !!(data & STIC_MYR_YSIZE);
+ s->doubley = !!(data & STIC_MYR_YFULL);
+ s->doubleyres = !!(data & STIC_MYR_YRES);
+ s->ypos = (data & STIC_MYR_Y);
+ break;
+ /* Attributes */
+ case STIC_MAR + STIC_MOB0:
+ case STIC_MAR + STIC_MOB1:
+ case STIC_MAR + STIC_MOB2:
+ case STIC_MAR + STIC_MOB3:
+ case STIC_MAR + STIC_MOB4:
+ case STIC_MAR + STIC_MOB5:
+ case STIC_MAR + STIC_MOB6:
+ case STIC_MAR + STIC_MOB7:
+ s = &m_sprite[offset & (STIC_MOBS - 1)];
+ s->behind_foreground = !!(data & STIC_MAR_PRI);
+ s->grom = !(data & STIC_MAR_SEL);
+ s->card = ((data & STIC_MAR_C) >> 3);
+ s->color = ((data & STIC_MAR_FG3) >> 9) | (data & STIC_MAR_FG20);
+ break;
+ /* Collision Detection - TBD */
+ case STIC_MCR + STIC_MOB0:
+ case STIC_MCR + STIC_MOB1:
+ case STIC_MCR + STIC_MOB2:
+ case STIC_MCR + STIC_MOB3:
+ case STIC_MCR + STIC_MOB4:
+ case STIC_MCR + STIC_MOB5:
+ case STIC_MCR + STIC_MOB6:
+ case STIC_MCR + STIC_MOB7:
+ // a MOB's own collision bit is *always* zero, even if a
+ // one is poked into it
+ data &= ~(1 << (offset & (STIC_MOBS - 1)));
+ break;
+ /* Display enable */
+ case STIC_DER:
+ //logerror("***Writing a %x to the STIC handshake\n",data);
+ m_stic_handshake = 1;
+ break;
+ /* Graphics Mode */
+ case STIC_GMR:
+ m_color_stack_mode = 0;
+ break;
+ /* Color Stack */
+ case STIC_CSR + STIC_CSR0:
+ case STIC_CSR + STIC_CSR1:
+ case STIC_CSR + STIC_CSR2:
+ case STIC_CSR + STIC_CSR3:
+ logerror("Setting color_stack[%x] = %x (%x)\n", offset & (STIC_CSRS - 1),data & STIC_CSR_BG, cpu_get_pc(&space.device()));
+ break;
+ /* Border Color */
+ case STIC_BCR:
+ //logerror("***Writing a %x to the border color\n",data);
+ m_border_color = data & STIC_BCR_BC;
+ break;
+ /* Framing */
+ case STIC_HDR:
+ m_col_delay = data & STIC_HDR_DEL;
+ break;
+ case STIC_VDR:
+ m_row_delay = data & STIC_VDR_DEL;
+ break;
+ case STIC_CBR:
+ m_left_edge_inhibit = (data & STIC_CBR_COL);
+ m_top_edge_inhibit = (data & STIC_CBR_ROW) >> 1;
+ break;
+ default:
+ //logerror("unmapped write to STIC register %02X: %04X\n", offset, data);
+ break;
+ }
+
+ if (offset < sizeof(m_stic_registers) / sizeof(m_stic_registers[0]))
+ m_stic_registers[offset] = data;
+ }
+}
diff --git a/src/mess/video/stic.h b/src/mess/video/stic.h
new file mode 100644
index 00000000000..51da9b38ae1
--- /dev/null
+++ b/src/mess/video/stic.h
@@ -0,0 +1,449 @@
+/*****************************************************************************
+ *
+ * includes/stic.h
+ *
+ ****************************************************************************/
+
+#ifndef STIC_H_
+#define STIC_H_
+
+// GROM/GRAM cards are 8x8
+#define STIC_CARD_WIDTH 8
+#define STIC_CARD_HEIGHT 8
+
+// Intellivision resolution is 20x12 BACKTAB CARDs, minus the rightmost column,
+// for an effective resolution of (19 * 8 + 1 * 7) x (12 * 8) == 159x96.
+//
+// MOB scanline height can be half of a card scanline height, so y-coordinates
+// are scaled by 2.
+#define STIC_X_SCALE 1
+#define STIC_Y_SCALE 2
+
+// the Intellivision emulation scales to match the output format at the last
+// step. The Intellivision keyboard component appears to be 320x96, but can
+// also run Intellivision carts, so x-coordinates are conditionally scaled
+// by 2.
+#define INTV_X_SCALE 1
+#define INTV_Y_SCALE 1
+#define INTVKBD_X_SCALE 2
+#define INTVKBD_Y_SCALE INTV_Y_SCALE
+
+// overscan sizes in intv pixels
+// these values are approximate.
+#define STIC_OVERSCAN_LEFT_WIDTH 13
+#define STIC_OVERSCAN_RIGHT_WIDTH 17
+#define STIC_OVERSCAN_TOP_HEIGHT 12
+#define STIC_OVERSCAN_BOTTOM_HEIGHT 12
+
+//Timing constants based on Joe Zbiciak's documentation
+#define STIC_CYCLES_PER_SCANLINE 57
+#define STIC_ROW_BUSRQ 110 // CPU paused during backtab row buffering
+#define STIC_FRAME_BUSRQ 42 // CPU paused just after end of vblank and before first row fetch (approximate)
+#define STIC_VBLANK_END 3790
+#define STIC_FIRST_FETCH 3933
+
+/*** STIC registers *********************************************************/
+
+// number of STIC registers
+#define STIC_REGISTERS 0x33
+
+// STIC MOBs (Moveable OBjects)
+enum
+{
+ STIC_MOB0,
+ STIC_MOB1,
+ STIC_MOB2,
+ STIC_MOB3,
+ STIC_MOB4,
+ STIC_MOB5,
+ STIC_MOB6,
+ STIC_MOB7,
+
+ STIC_MOBS
+};
+
+// STIC Color Stack
+enum
+{
+ STIC_CSR0,
+ STIC_CSR1,
+ STIC_CSR2,
+ STIC_CSR3,
+
+ STIC_CSRS
+};
+
+/****************************************************************************
+ * *
+ * MXR 0000[..0007] MOB X REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-+-----+---+---+--+--+--+--+--+--+--+--+ *
+ * | | | | | |XSIZE|VIS|COL|X7|X6|X5|X4|X3|X2|X1|X0| *
+ * +-+-+-+-+-+-----+---+---+--+--+--+--+--+--+--+--+ *
+ * *
+ * Xn x-position [0..255] *
+ * COL collision detection [1=enable] *
+ * VIS visibility [1=visible] *
+ * XSIZE double width [1=double] *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES *
+ * *
+ * 1. If X=0, the sprite is not visible and does not register collisions. *
+ * 2. The horizontal handle is 8 pixels from the left of the sprite, *
+ * regardless of width. *
+ * *
+ ****************************************************************************/
+#define STIC_MXR 0x0000
+
+#define STIC_MXR_XSIZE 0x0400
+#define STIC_MXR_VIS 0x0200
+#define STIC_MXR_COL 0x0100
+#define STIC_MXR_X 0x00FF
+
+/****************************************************************************
+ * *
+ * MYR 0008[..000F] MOB Y REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-----+-----+-----+-----+----+--+--+--+--+--+--+--+ *
+ * | | | | |YFLIP|XFLIP|YSIZE|YFULL|YRES|Y6|Y5|Y4|Y3|Y2|Y1|Y0| *
+ * +-+-+-+-+-----+-----+-----+-----+----+--+--+--+--+--+--+--+ *
+ * *
+ * Yn y-position [0..127] *
+ * YRES y-resolution [0=8 scanlines,1=16 scanlines] *
+ * YFULL double scanline height [1=double] *
+ * YSIZE quadruple scanline height [1=quadruple] *
+ * XFLIP horizontally flip image [1=flip] *
+ * YFLIP vertically flip image [1=flip] *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES *
+ * *
+ * 1. A sprite with YRES=1 will display two cards. *
+ * 2. A sprite with YFULL=0 and YSIZE=0 will have scanlines half the *
+ * height of a background card. *
+ * 3, The minimum size of a sprite is 8x8 (XSIZE=YRES=YSIZE=YFULL=0). *
+ * 4. The maximum size of a sprite is 16x128 (XSIZE=YRES=YSIZE=YFULL=1). *
+ * 5. The Y-position is measured in double height scanlines. *
+ * 6. The vertical handle is 8 double height scanlines from the top of the *
+ * sprite, regardless of height. *
+ * *
+ ****************************************************************************/
+#define STIC_MYR 0x0008
+
+#define STIC_MYR_YFLIP 0x0800
+#define STIC_MYR_XFLIP 0x0400
+#define STIC_MYR_YSIZE 0x0200
+#define STIC_MYR_YFULL 0x0100
+#define STIC_MYR_YRES 0x0080
+#define STIC_MYR_Y 0x007F
+
+/****************************************************************************
+ * *
+ * SAR 0010[..0017] MOB ATTRIBUTE REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+---+---+---+-+-+--+--+--+--+--+--+---+---+---+ *
+ * | | |PRI|FG3|SEL| | |C5|C4|C3|C2|C1|C0|FG2|FG1|FG0| *
+ * +-+-+---+---+---+-+-+--+--+--+--+--+--+---+---+---+ *
+ * *
+ * FGn foreground color [0..15] *
+ * Cn card # [0..63] *
+ * SEL card memory select [0=GROM, 1=GRAM] *
+ * PRI sprite priority [1=behind set background bit] *
+ * *
+ ****************************************************************************/
+#define STIC_MAR 0x0010
+
+#define STIC_MAR_PRI 0x2000
+#define STIC_MAR_FG3 0x1000
+#define STIC_MAR_SEL 0x0800
+#define STIC_MAR_C 0x07F8
+#define STIC_MAR_FG20 0x0007
+
+/****************************************************************************
+ * *
+ * SCR 0018[..001F] MOB COLLISION REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-+-+----+----+----+----+----+----+----+----+----+----+ *
+ * | | | | | | |BRDR|BKGD|SPR7|SPR6|SPR5|SPR4|SPR3|SPR2|SPR1|SPR0| *
+ * +-+-+-+-+-+-+----+----+----+----+----+----+----+----+----+----+ *
+ * *
+ * SPRn 1=collision with sprite #n *
+ * BKGD 1=collsion with set background bit *
+ * BRDR 1=collision with screen border *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES *
+ * *
+ * 1. All collisions are latched. Successive reads read from the latch. *
+ * A write will reset the latch. *
+ * 2. Sprites with VIS=0 register collisions. *
+ * 3. Sprites with X=0 do not register collisions. *
+ * 4. Two overlapping sprites with different priorities, one completely *
+ * hidden behind the background, still register a collision. *
+ * *
+ ****************************************************************************/
+#define STIC_MCR 0x0018
+
+#define STIC_MCR_BRDR 0x0200
+#define STIC_MCR_BKGD 0x0100
+#define STIC_MCR_SPR7 0x0080
+#define STIC_MCR_SPR6 0x0040
+#define STIC_MCR_SPR5 0x0020
+#define STIC_MCR_SPR4 0x0010
+#define STIC_MCR_SPR3 0x0008
+#define STIC_MCR_SPR2 0x0004
+#define STIC_MCR_SPR1 0x0002
+#define STIC_MCR_SPR0 0x0001
+
+/****************************************************************************
+ * *
+ * DER 0021 DISPLAY ENABLE REGISTER W *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *
+ * | | | | | | | | | | | | | | | | | *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES *
+ * *
+ * 1. Any write during VBLANK enables STIC output. *
+ * *
+ ****************************************************************************/
+#define STIC_DER 0x0020
+
+/****************************************************************************
+ * *
+ * GMR 0021 GRAPHICS MODE REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *
+ * | | | | | | | | | | | | | | | | | *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES *
+ * *
+ * 1. Any write during VBLANK enables FOREGROUND/BACKGROUND mode. *
+ * 2. Any read during VBLANK enables COLOR STACK/COLORED SQUARES mode. *
+ * *
+ ****************************************************************************/
+#define STIC_GMR 0x0021
+
+/****************************************************************************
+ * *
+ * CSR 0028 COLOR STACK REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+---+---+---+---+ *
+ * | | | | | | | | | | | | |BG3|BG2|BG1|BG0| *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+---+---+---+---+ *
+ * *
+ * BGn background color [0..15] *
+ * *
+ ****************************************************************************/
+#define STIC_CSR 0x0028
+
+#define STIC_CSR_BG 0x000F
+
+/****************************************************************************
+ * *
+ * BCR 002C BORDER COLOR REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+---+---+---+---+ *
+ * | | | | | | | | | | | | |BC3|BC2|BC1|BC0| *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+---+---+---+---+ *
+ * *
+ * BCn border color [0..15] *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES *
+ * *
+ * 1. Affects overscan, and column and row blockouts. *
+ * *
+ ****************************************************************************/
+#define STIC_BCR 0x002C
+
+#define STIC_BCR_BC 0x000F
+
+/****************************************************************************
+ * *
+ * HDR 0030 HORIZONTAL DELAY REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+----+----+----+ *
+ * | | | | | | | | | | | | | |DEL2|DEL1|DEL0| *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+----+----+----+ *
+ * *
+ * DELn horizontal delay [0..7] *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES *
+ * *
+ * 1. Affects both BACKTAB and MOBs. *
+ * *
+ ****************************************************************************/
+#define STIC_HDR 0x0030
+
+#define STIC_HDR_DEL 0x0007
+
+/****************************************************************************
+ * *
+ * STIC_VDR 0030 VERTICAL DELAY REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+----+----+----+ *
+ * | | | | | | | | | | | | | |DEL2|DEL1|DEL0| *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+----+----+----+ *
+ * *
+ * DELn vertical delay [0..7] *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES *
+ * *
+ * 1. Affects both BACKTAB and MOBs. *
+ * *
+ ****************************************************************************/
+#define STIC_VDR 0x0031
+
+#define STIC_VDR_DEL 0x0007
+
+/****************************************************************************
+ * *
+ * STIC_CBR 0032 CARD BLOCKOUT REGISTER RW *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+---+---+ *
+ * | | | | | | | | | | | | | | |ROW|COL| *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+---+---+ *
+ * *
+ * COL blockout first card column [1=blockout] *
+ * ROW blockout first card row [1=blockout] *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES *
+ * *
+ * 1. Generally used in conjunction with HDR and VDR registers, to achieve *
+ * smooth scrolling. *
+ * *
+ ****************************************************************************/
+#define STIC_CBR 0x0032
+
+#define STIC_CBR_ROW 0x0002
+#define STIC_CBR_COL 0x0001
+
+/*** BACKTAB ****************************************************************/
+
+// BACKTAB is made up of 20x12 cards
+// (the first 19 columns are 8x8, the 20th column is 7x8)
+#define STIC_BACKTAB_WIDTH 20
+#define STIC_BACKTAB_HEIGHT 12
+
+/****************************************************************************
+ * *
+ * FOREGROUND/BACKGROUND MODE *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+---+---+---+---+---+--+--+--+--+--+--+---+---+---+ *
+ * | | |BG2|BG3|SEL|BG1|BG0|C5|C4|C3|C2|C1|C0|FG2|FG1|FG0| *
+ * +-+-+---+---+---+---+---+--+--+--+--+--+--+---+---+---+ *
+ * *
+ * FGn foreground color [0..7] *
+ * Cn card # [0..63] *
+ * SEL card memory select [0=GROM, 1=GRAM] *
+ * BGn background color [0..15] *
+ * *
+ ****************************************************************************/
+#define STIC_FBM_BG2 0x2000
+#define STIC_FBM_BG310 0x1600
+#define STIC_FBM_SEL 0x0800
+#define STIC_FBM_C 0x01F8
+#define STIC_FBM_FG 0x0007
+
+/****************************************************************************
+ * *
+ * COLOR STACK MODE *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+---+---+---+--+--+--+--+--+--+--+--+---+---+---+ *
+ * | | |ADV|FG3|SEL|C7|C6|C5|C4|C3|C2|C1|C0|FG2|FG1|FG0| *
+ * +-+-+---+---+---+--+--+--+--+--+--+--+--+---+---+---+ *
+ * *
+ * FGn foreground color [0..15] *
+ * Cn card # [GROM=0..212, GRAM=0..63] *
+ * SEL card memory select [0=GROM, 1=GRAM] *
+ * ADV advance color stack index [1=advance] *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES: *
+ * *
+ * 1. When FG3=1 and SEL=0, COLORED SQUARES MODE is enabled. *
+ * 2. When SEL=1, C7 and C6 can be used as user-defined flags. *
+ * *
+ ****************************************************************************/
+#define STIC_CSTM_ADV 0x2000
+#define STIC_CSTM_FG3 0x1000
+#define STIC_CSTM_SEL 0x0800
+#define STIC_CSTM_C7 0x0400
+#define STIC_CSTM_C6 0x0200
+#define STIC_CSTM_C50 0x01F8
+#define STIC_CSTM_FG20 0x0007
+
+#define STIC_CSTM_C (STIC_CSTM_C7|STIC_CSTM_C6|STIC_CSTM_C50)
+
+/****************************************************************************
+ * *
+ * COLORED SQUARES MODE *
+ * *
+ * (MSB) (LSB) *
+ * +-+-+--+-+-+--+--+--+--+--+--+--+--+--+--+--+ *
+ * | | |D2|1|0|D1|D0|C2|C1|C0|B2|B1|B0|A2|A1|A0| *
+ * +-+-+--+-+-+--+--+--+--+--+--+--+--+--+--+--+ *
+ * *
+ * An color a [0..7] *
+ * Bn color b [0..7] *
+ * Cn color c [0..7] *
+ * Dn color d [0..7] *
+ * *
+ ****************************************************************************
+ * *
+ * NOTES: *
+ * *
+ * 1. Each color corresponds to one of the following 4 x 4 squares: *
+ * *
+ * +---+---+ *
+ * | a | b | *
+ * +---+---+ *
+ * | c | d | *
+ * +---+---+ *
+ * *
+ * 2. When color 7 is specified, the color is taken from the color stack. *
+ * *
+ ****************************************************************************/
+#define STIC_CSQM_D2 0x2000
+#define STIC_CSQM_D10 0x0600
+#define STIC_CSQM_C 0x01C0
+#define STIC_CSQM_B 0x0038
+#define STIC_CSQM_A 0x0007
+
+#define STIC_CSQM_WIDTH (STIC_CARD_WIDTH / 2)
+#define STIC_CSQM_HEIGHT (STIC_CARD_HEIGHT / 2)
+
+#endif /* STIC_H_ */
+
diff --git a/src/mess/video/super80.c b/src/mess/video/super80.c
new file mode 100644
index 00000000000..b5749e72ab3
--- /dev/null
+++ b/src/mess/video/super80.c
@@ -0,0 +1,469 @@
+/* Super80.c written by Robbbert, 2005-2010. See the MESS wiki for documentation. */
+
+/* Notes on using MAME MC6845 Device (MMD).
+ 1. Speed of MMD is about 20% slower than pre-MMD coding
+ 2. Undocumented cursor start and end-lines is not supported by MMD, so we do it here. */
+
+
+#include "emu.h"
+#include "includes/super80.h"
+
+
+
+/**************************** PALETTES for super80m and super80v ******************************************/
+
+static const UINT8 super80_rgb_palette[16*3] =
+{
+ 0x00, 0x00, 0x00, /* 0 Black */
+ 0x00, 0x00, 0x00, /* 1 Black */
+ 0x00, 0x00, 0x7f, /* 2 Blue */
+ 0x00, 0x00, 0xff, /* 3 Light Blue */
+ 0x00, 0x7f, 0x00, /* 4 Green */
+ 0x00, 0xff, 0x00, /* 5 Bright Green */
+ 0x00, 0x7f, 0x7f, /* 6 Cyan */
+ 0x00, 0xff, 0xff, /* 7 Turquoise */
+ 0x7f, 0x00, 0x00, /* 8 Dark Red */
+ 0xff, 0x00, 0x00, /* 9 Red */
+ 0x7f, 0x00, 0x7f, /* 10 Purple */
+ 0xff, 0x00, 0xff, /* 11 Magenta */
+ 0x7f, 0x7f, 0x00, /* 12 Lime */
+ 0xff, 0xff, 0x00, /* 13 Yellow */
+ 0xbf, 0xbf, 0xbf, /* 14 Off White */
+ 0xff, 0xff, 0xff, /* 15 White */
+};
+
+static const UINT8 super80_comp_palette[16*3] =
+{
+ 0x00, 0x00, 0x00, /* 0 Black */
+ 0x80, 0x80, 0x80, /* 1 Grey */
+ 0x00, 0x00, 0xff, /* 2 Blue */
+ 0xff, 0xff, 0x80, /* 3 Light Yellow */
+ 0x00, 0xff, 0x00, /* 4 Green */
+ 0xff, 0x80, 0xff, /* 5 Light Magenta */
+ 0x00, 0xff, 0xff, /* 6 Cyan */
+ 0xff, 0x40, 0x40, /* 7 Light Red */
+ 0xff, 0x00, 0x00, /* 8 Red */
+ 0x00, 0x80, 0x80, /* 9 Dark Cyan */
+ 0xff, 0x00, 0xff, /* 10 Magenta */
+ 0x80, 0xff, 0x80, /* 11 Light Green */
+ 0xff, 0xff, 0x00, /* 12 Yellow */
+ 0x00, 0x00, 0x80, /* 13 Dark Blue */
+ 0xff, 0xff, 0xff, /* 14 White */
+ 0x00, 0x00, 0x00, /* 15 Black */
+};
+
+static void palette_set_colors_rgb(running_machine &machine, const UINT8 *colors)
+{
+ UINT8 r, b, g, color_count = 16;
+
+ while (color_count--)
+ {
+ r = *colors++; g = *colors++; b = *colors++;
+ palette_set_color(machine, 15-color_count, MAKE_RGB(r, g, b));
+ }
+}
+
+PALETTE_INIT( super80m )
+{
+ palette_set_colors_rgb(machine, super80_rgb_palette);
+}
+
+
+
+SCREEN_VBLANK( super80m )
+{
+ // rising edge
+ if (vblank_on)
+ {
+ super80_state *state = screen.machine().driver_data<super80_state>();
+ /* if we chose another palette or colour mode, enable it */
+ UINT8 chosen_palette = (screen.machine().root_device().ioport("CONFIG")->read() & 0x60)>>5; // read colour dipswitches
+
+ if (chosen_palette != state->m_current_palette) // any changes?
+ {
+ state->m_current_palette = chosen_palette; // save new palette
+ if (!state->m_current_palette)
+ palette_set_colors_rgb(screen.machine(), super80_comp_palette); // composite colour
+ else
+ palette_set_colors_rgb(screen.machine(), super80_rgb_palette); // rgb and b&w
+ }
+ }
+}
+
+SCREEN_UPDATE_IND16( super80 )
+{
+ super80_state *state = screen.machine().driver_data<super80_state>();
+ UINT8 y,ra,chr=32,gfx,screen_on=0;
+ UINT16 sy=0,ma=state->m_vidpg,x;
+ UINT8 *RAM = state->memregion("maincpu")->base();
+
+ output_set_value("cass_led",(state->m_shared & 0x20) ? 1 : 0);
+
+ if ((state->m_shared & 4) || (!(screen.machine().root_device().ioport("CONFIG")->read() & 4))) /* bit 2 of port F0 is high, OR user turned on config switch */
+ screen_on++;
+
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 10; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = 0; x < 32; x++) // done this way to avoid x overflowing on page FF
+ {
+ if (screen_on)
+ chr = RAM[ma | x] & 0x3f;
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[(chr<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)];
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=32;
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( super80d )
+{
+ super80_state *state = screen.machine().driver_data<super80_state>();
+ UINT8 y,ra,chr=32,gfx,screen_on=0;
+ UINT16 sy=0,ma=state->m_vidpg,x;
+ UINT8 *RAM = state->memregion("maincpu")->base();
+
+ output_set_value("cass_led",(state->m_shared & 0x20) ? 1 : 0);
+
+ if ((state->m_shared & 4) || (!(screen.machine().root_device().ioport("CONFIG")->read() & 4))) /* bit 2 of port F0 is high, OR user turned on config switch */
+ screen_on++;
+
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 10; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = 0; x < 32; x++)
+ {
+ if (screen_on)
+ chr = RAM[ma | x];
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[((chr & 0x7f)<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)] ^ ((chr & 0x80) ? 0xff : 0);
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=32;
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( super80e )
+{
+ super80_state *state = screen.machine().driver_data<super80_state>();
+ UINT8 y,ra,chr=32,gfx,screen_on=0;
+ UINT16 sy=0,ma=state->m_vidpg,x;
+ UINT8 *RAM = state->memregion("maincpu")->base();
+
+ output_set_value("cass_led",(state->m_shared & 0x20) ? 1 : 0);
+
+ if ((state->m_shared & 4) || (!(screen.machine().root_device().ioport("CONFIG")->read() & 4))) /* bit 2 of port F0 is high, OR user turned on config switch */
+ screen_on++;
+
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 10; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = 0; x < 32; x++)
+ {
+ if (screen_on)
+ chr = RAM[ma | x];
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[(chr<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)];
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=32;
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( super80m )
+{
+ super80_state *state = screen.machine().driver_data<super80_state>();
+ UINT8 y,ra,chr=32,gfx,screen_on=0;
+ UINT16 sy=0,ma=state->m_vidpg,x;
+ UINT8 col, bg=0, fg=0, options=screen.machine().root_device().ioport("CONFIG")->read();
+ UINT8 *RAM = state->memregion("maincpu")->base();
+
+ /* get selected character generator */
+ UINT8 cgen = state->m_current_charset ^ ((options & 0x10)>>4); /* bit 0 of port F1 and cgen config switch */
+
+ output_set_value("cass_led",(state->m_shared & 0x20) ? 1 : 0);
+
+ if ((state->m_shared & 4) || (!(options & 4))) /* bit 2 of port F0 is high, OR user turned on config switch */
+ screen_on++;
+
+ if (screen_on)
+ {
+ if ((options & 0x60) == 0x60)
+ fg = 15; /* b&w */
+ else
+ fg = 5; /* green */
+ }
+
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 10; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = 0; x < 32; x++)
+ {
+ if (screen_on)
+ chr = RAM[ma | x];
+
+ if (!(options & 0x40))
+ {
+ col = RAM[0xfe00 | ma | x]; /* byte of colour to display */
+ fg = col & 0x0f;
+ bg = (col & 0xf0) >> 4;
+ }
+
+ /* get pattern of pixels for that character scanline */
+ if (cgen)
+ gfx = state->m_p_chargen[(chr<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)];
+ else
+ gfx = state->m_p_chargen[0x1000 | ((chr & 0x7f)<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)] ^ ((chr & 0x80) ? 0xff : 0);
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7) ? fg : bg;
+ *p++ = BIT(gfx, 6) ? fg : bg;
+ *p++ = BIT(gfx, 5) ? fg : bg;
+ *p++ = BIT(gfx, 4) ? fg : bg;
+ *p++ = BIT(gfx, 3) ? fg : bg;
+ *p++ = BIT(gfx, 2) ? fg : bg;
+ *p++ = BIT(gfx, 1) ? fg : bg;
+ *p++ = BIT(gfx, 0) ? fg : bg;
+ }
+ }
+ ma+=32;
+ }
+ return 0;
+}
+
+VIDEO_START( super80 )
+{
+ super80_state *state = machine.driver_data<super80_state>();
+ state->m_vidpg = 0xfe00;
+ state->m_p_chargen = state->memregion("chargen")->base();
+}
+
+/**************************** I/O PORTS *****************************************************************/
+
+WRITE8_MEMBER( super80_state::super80_f1_w )
+{
+ m_vidpg = (data & 0xfe) << 8;
+ m_current_charset = data & 1;
+}
+
+/*---------------------------------------------------------------
+
+ Super-80R and Super-80V
+
+---------------------------------------------------------------*/
+
+static const UINT8 mc6845_mask[32]={0xff,0xff,0xff,0x0f,0x7f,0x1f,0x7f,0x7f,3,0x1f,0x7f,0x1f,0x3f,0xff,0x3f,0xff,0,0};
+
+READ8_MEMBER( super80_state::super80v_low_r )
+{
+ if (m_shared & 4)
+ return m_p_videoram[offset];
+ else
+ return m_p_colorram[offset];
+}
+
+WRITE8_MEMBER( super80_state::super80v_low_w )
+{
+ if (m_shared & 4)
+ m_p_videoram[offset] = data;
+ else
+ m_p_colorram[offset] = data;
+}
+
+READ8_MEMBER( super80_state::super80v_high_r )
+{
+ if (~m_shared & 4)
+ return m_p_colorram[0x800 | offset];
+ else
+ if (m_shared & 0x10)
+ return m_p_pcgram[0x800 | offset];
+ else
+ return m_p_pcgram[offset];
+}
+
+WRITE8_MEMBER( super80_state::super80v_high_w )
+{
+ if (~m_shared & 4)
+ m_p_colorram[0x800 | offset] = data;
+ else
+ {
+ m_p_videoram[0x800 | offset] = data;
+
+ if (m_shared & 0x10)
+ m_p_pcgram[0x800 | offset] = data;
+ }
+}
+
+/* The 6845 can produce a variety of cursor shapes - all are emulated here - remove when mame fixed */
+void super80_state::mc6845_cursor_configure()
+{
+ UINT8 i,curs_type=0,r9,r10,r11;
+
+ /* curs_type holds the general cursor shape to be created
+ 0 = no cursor
+ 1 = partial cursor (only shows on a block of scan lines)
+ 2 = full cursor
+ 3 = two-part cursor (has a part at the top and bottom with the middle blank) */
+
+ for ( i = 0; i < ARRAY_LENGTH(m_mc6845_cursor); i++) m_mc6845_cursor[i] = 0; // prepare cursor by erasing old one
+
+ r9 = m_mc6845_reg[9]; // number of scan lines - 1
+ r10 = m_mc6845_reg[10] & 0x1f; // cursor start line = last 5 bits
+ r11 = m_mc6845_reg[11]+1; // cursor end line incremented to suit for-loops below
+
+ /* decide the curs_type by examining the registers */
+ if (r10 < r11) curs_type=1; // start less than end, show start to end
+ else
+ if (r10 == r11) curs_type=2; // if equal, show full cursor
+ else curs_type=3; // if start greater than end, it's a two-part cursor
+
+ if ((r11 - 1) > r9) curs_type=2; // if end greater than scan-lines, show full cursor
+ if (r10 > r9) curs_type=0; // if start greater than scan-lines, then no cursor
+ if (r11 > 16) r11=16; // truncate 5-bit register to fit our 4-bit hardware
+
+ /* create the new cursor */
+ if (curs_type > 1) for (i = 0;i < ARRAY_LENGTH(m_mc6845_cursor);i++) m_mc6845_cursor[i]=0xff; // turn on full cursor
+
+ if (curs_type == 1) for (i = r10;i < r11;i++) m_mc6845_cursor[i]=0xff; // for each line that should show, turn on that scan line
+
+ if (curs_type == 3) for (i = r11; i < r10;i++) m_mc6845_cursor[i]=0; // now take a bite out of the middle
+}
+
+VIDEO_START( super80v )
+{
+ super80_state *state = machine.driver_data<super80_state>();
+ state->m_p_pcgram = machine.root_device().memregion("maincpu")->base()+0xf000;
+ state->m_p_videoram = machine.root_device().memregion("videoram")->base();
+ state->m_p_colorram = state->memregion("colorram")->base();
+}
+
+SCREEN_UPDATE_RGB32( super80v )
+{
+ super80_state *state = screen.machine().driver_data<super80_state>();
+ state->m_framecnt++;
+ state->m_speed = state->m_mc6845_reg[10]&0x20, state->m_flash = state->m_mc6845_reg[10]&0x40; // cursor modes
+ state->m_cursor = (state->m_mc6845_reg[14]<<8) | state->m_mc6845_reg[15]; // get cursor position
+ state->m_s_options=screen.machine().root_device().ioport("CONFIG")->read();
+ output_set_value("cass_led",(state->m_shared & 0x20) ? 1 : 0);
+ state->m_6845->screen_update(screen, bitmap, cliprect);
+ return 0;
+}
+
+MC6845_UPDATE_ROW( super80v_update_row )
+{
+ super80_state *state = device->machine().driver_data<super80_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 chr,col,gfx,fg,bg=0;
+ UINT16 mem,x;
+ UINT32 *p = &bitmap.pix32(y);
+
+ for (x = 0; x < x_count; x++) // for each character
+ {
+ UINT8 inv=0;
+ // if (x == cursor_x) inv=0xff; /* uncomment when mame fixed */
+ mem = (ma + x) & 0xfff;
+ chr = state->m_p_videoram[mem];
+
+ /* get colour or b&w */
+ fg = 5; /* green */
+ if ((state->m_s_options & 0x60) == 0x60) fg = 15; /* b&w */
+
+ if (~state->m_s_options & 0x40)
+ {
+ col = state->m_p_colorram[mem]; /* byte of colour to display */
+ fg = col & 0x0f;
+ bg = (col & 0xf0) >> 4;
+ }
+
+ /* if inverse mode, replace any pcgram chrs with inverse chrs */
+ if ((~state->m_shared & 0x10) && (chr & 0x80)) // is it a high chr in inverse mode
+ {
+ inv ^= 0xff; // invert the chr
+ chr &= 0x7f; // and drop bit 7
+ }
+
+ /* process cursor - remove when mame fixed */
+ if ((((!state->m_flash) && (!state->m_speed)) ||
+ ((state->m_flash) && (state->m_speed) && (state->m_framecnt & 0x10)) ||
+ ((state->m_flash) && (!state->m_speed) && (state->m_framecnt & 8))) &&
+ (mem == state->m_cursor))
+ inv ^= state->m_mc6845_cursor[ra];
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_pcgram[(chr<<4) | ra] ^ inv;
+
+ /* Display a scanline of a character */
+ *p++ = palette[BIT(gfx, 7) ? fg : bg];
+ *p++ = palette[BIT(gfx, 6) ? fg : bg];
+ *p++ = palette[BIT(gfx, 5) ? fg : bg];
+ *p++ = palette[BIT(gfx, 4) ? fg : bg];
+ *p++ = palette[BIT(gfx, 3) ? fg : bg];
+ *p++ = palette[BIT(gfx, 2) ? fg : bg];
+ *p++ = palette[BIT(gfx, 1) ? fg : bg];
+ }
+}
+
+/**************************** I/O PORTS *****************************************************************/
+
+WRITE8_MEMBER( super80_state::super80v_10_w )
+{
+ data &= 0x1f;
+ m_mc6845_ind = data;
+ m_6845->address_w( space, 0, data );
+}
+
+WRITE8_MEMBER( super80_state::super80v_11_w )
+{
+ m_mc6845_reg[m_mc6845_ind] = data & mc6845_mask[m_mc6845_ind]; /* save data in register */
+ m_6845->register_w( space, 0, data );
+ if ((m_mc6845_ind > 8) && (m_mc6845_ind < 12)) mc6845_cursor_configure(); /* adjust cursor shape - remove when mame fixed */
+}
diff --git a/src/mess/video/t6a04.c b/src/mess/video/t6a04.c
new file mode 100644
index 00000000000..f2810fd4737
--- /dev/null
+++ b/src/mess/video/t6a04.c
@@ -0,0 +1,260 @@
+/***************************************************************************
+
+ Toshiba T6A04 LCD controller
+
+ TODO:
+ - busy flag
+ - contrast
+ - slave mode
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/t6a04.h"
+
+// devices
+const device_type T6A04 = &device_creator<t6a04_device>;
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void t6a04_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const t6a04_interface *intf = reinterpret_cast<const t6a04_interface *>(static_config());
+
+ if (intf != NULL)
+ {
+ *static_cast<t6a04_interface *>(this) = *intf;
+ }
+ // or initialize to defaults if none provided
+ else
+ {
+ height = width = 0;
+ }
+}
+
+//-------------------------------------------------
+// device_validity_check - perform validity checks
+// on this device
+//-------------------------------------------------
+
+void t6a04_device::device_validity_check(validity_checker &valid) const
+{
+ if (height == 0 || width == 0)
+ mame_printf_error("Configured with invalid parameter\n");
+}
+
+//**************************************************************************
+// live device
+//**************************************************************************
+
+//-------------------------------------------------
+// t6a04_device - constructor
+//-------------------------------------------------
+
+t6a04_device::t6a04_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, T6A04, "T6A04", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void t6a04_device::device_start()
+{
+ save_item(NAME(m_busy_flag));
+ save_item(NAME(m_display_on));
+ save_item(NAME(m_contrast));
+ save_item(NAME(m_xpos));
+ save_item(NAME(m_ypos));
+ save_item(NAME(m_zpos));
+ save_item(NAME(m_active_counter));
+ save_item(NAME(m_direction));
+ save_item(NAME(m_word_len));
+ save_item(NAME(m_opa1));
+ save_item(NAME(m_opa2));
+ save_item(NAME(m_output_reg));
+ save_item(NAME(m_lcd_ram));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void t6a04_device::device_reset()
+{
+ //values taken from the datasheet
+ memset(m_lcd_ram, 0x00, sizeof(m_lcd_ram));
+ m_busy_flag = 0;
+ m_display_on = 0;
+ m_contrast = 0;
+ m_xpos = 0;
+ m_ypos = 0;
+ m_zpos = 0;
+ m_direction = 1;
+ m_active_counter = 1;
+ m_word_len = 1; //8bit mode
+ m_opa1 = 0;
+ m_opa2 = 0;
+ m_output_reg = 0;
+}
+
+
+//**************************************************************************
+// device interface
+//**************************************************************************
+
+UINT32 t6a04_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT8 ypages = width>>3;
+ UINT8 last_line = m_zpos + height;
+
+ if (m_display_on)
+ {
+ for (int y=0; y<ypages; y++)
+ for (int x=m_zpos; x<last_line; x++)
+ {
+ UINT8 data = m_lcd_ram[(x&0x3f)*15 + y];
+
+ for (int b=7; b>=0; b--)
+ {
+ bitmap.pix16(x&0x3f, y*8+b) = data & 1;
+ data>>=1;
+ }
+ }
+ }
+ else
+ {
+ bitmap.fill(0, cliprect);
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(t6a04_device::control_write)
+{
+ if ((data & 0xc0) == 0xc0) // SCE (set contrast)
+ {
+ m_contrast = data&0x3f;
+ }
+ else if ((data & 0xc0) == 0x80) // SXE (set x address)
+ {
+ m_xpos = data&0x3f;
+ }
+ else if ((data & 0xc0) == 0x40) // SZE (set z address)
+ {
+ m_zpos = data&0x3f;
+ }
+ else if ((data & 0xe0) == 0x20) // SYE (set y address)
+ {
+ m_ypos = data&0x1f;
+ }
+ else if ((data & 0xf8) == 0x18) // CHE (test mode)
+ {
+ //???
+ }
+ else if ((data & 0xf8) == 0x10) // OPA1 (op-amp control 1)
+ {
+ m_opa1 = data & 3;
+ }
+ else if ((data & 0xf8) == 0x08) // OPA2 (op-amp control 2)
+ {
+ m_opa2 = data & 3;
+ }
+ else if ((data & 0xfc) == 0x04) // UDE (up/down mode)
+ {
+ m_active_counter = (data & 0x02) >> 1;
+ m_direction = (data & 0x01) ? +1 : -1;
+ }
+ else if ((data & 0xfe) == 0x02) // DPE (display on/off)
+ {
+ m_display_on = data & 1;
+ }
+ else if ((data & 0xfe) == 0x00) // 86E (word length)
+ {
+ m_word_len = data & 1;
+ }
+}
+
+READ8_MEMBER(t6a04_device::control_read)
+{
+ /*
+ status read
+ x--- ---- busy
+ -x-- ---- 8/6 mode
+ --x- ---- display on/off
+ ---x ---- reset state
+ ---- xx-- unused (always 0)
+ ---- --x- x/y counter
+ ---- ---x up/down mode
+ */
+
+ return (m_busy_flag<<7) | (m_word_len<<6) | (m_display_on<<5) | (m_active_counter<<1) | (m_direction == 1 ? 1 : 0);
+}
+
+WRITE8_MEMBER(t6a04_device::data_write)
+{
+ if (m_word_len)
+ {
+ //8bit mode
+ m_lcd_ram[m_xpos*15 + m_ypos] = data;
+ }
+ else
+ {
+ //6bit mode
+ data = data<<0x02;
+ UINT8 start_bit = m_ypos * 6;
+ UINT8 pos_bit = start_bit & 0x07;
+ UINT8 *ti82_video = &m_lcd_ram[(m_xpos*15)+(start_bit>>3)];
+
+ ti82_video[0] = (ti82_video[0] & ~(0xFC>>pos_bit)) | (data>>pos_bit);
+ if(pos_bit>0x02)
+ ti82_video[1] = (ti82_video[1] & ~(0xFC<<(8-pos_bit))) | (data<<(8-pos_bit));
+ }
+
+ if (m_active_counter)
+ m_ypos = (m_ypos + m_direction) & 0x1f;
+ else
+ m_xpos = (m_xpos + m_direction) & 0x3f;
+
+}
+
+READ8_MEMBER(t6a04_device::data_read)
+{
+ UINT8 data = m_output_reg;
+ UINT8 output_reg;
+
+ if (m_word_len)
+ {
+ //8bit mode
+ output_reg = m_lcd_ram[m_xpos*15 + m_ypos];
+ }
+ else
+ {
+ //6bit mode
+ UINT8 start_bit = m_ypos * 6;
+ UINT8 pos_bit = start_bit & 7;
+ UINT8 *ti82_video = &m_lcd_ram[(m_xpos*15)+(start_bit>>3)];
+
+ output_reg = ((((*ti82_video)<<8)+ti82_video[1])>>(10-pos_bit));
+ }
+
+ if (!space.debugger_access())
+ {
+ m_output_reg = output_reg;
+
+ if (m_active_counter)
+ m_ypos = (m_ypos + m_direction) & 0x1f;
+ else
+ m_xpos = (m_xpos + m_direction) & 0x3f;
+ }
+
+ return data;
+}
diff --git a/src/mess/video/t6a04.h b/src/mess/video/t6a04.h
new file mode 100644
index 00000000000..9f469e2535b
--- /dev/null
+++ b/src/mess/video/t6a04.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+
+ Toshiba T6A04 LCD controller
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __T6A04_H__
+#define __T6A04_H__
+
+#define MCFG_T6A04_ADD( _tag, _config ) \
+ MCFG_DEVICE_ADD( _tag, T6A04, 0 ) \
+ MCFG_DEVICE_CONFIG(_config)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> t6a04_interface
+
+struct t6a04_interface
+{
+ UINT8 height; // number of lines
+ UINT8 width; // pixels for line
+};
+
+// ======================> t6a04_device
+
+class t6a04_device : public device_t,
+ public t6a04_interface
+{
+public:
+ // construction/destruction
+ t6a04_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device interface
+ DECLARE_WRITE8_MEMBER(control_write);
+ DECLARE_READ8_MEMBER(control_read);
+ DECLARE_WRITE8_MEMBER(data_write);
+ DECLARE_READ8_MEMBER(data_read);
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+ virtual void device_validity_check(validity_checker &valid) const;
+
+private:
+ UINT8 m_busy_flag;
+ UINT8 m_lcd_ram[960]; //7680 bit (64*120)
+ UINT8 m_display_on;
+ UINT8 m_contrast;
+ UINT8 m_xpos;
+ UINT8 m_ypos;
+ UINT8 m_zpos;
+ INT8 m_direction;
+ UINT8 m_active_counter;
+ UINT8 m_word_len;
+ UINT8 m_opa1;
+ UINT8 m_opa2;
+ UINT8 m_output_reg;
+};
+
+// device type definition
+extern const device_type T6A04;
+
+#endif
diff --git a/src/mess/video/thomson.c b/src/mess/video/thomson.c
new file mode 100644
index 00000000000..94bb3f8f54d
--- /dev/null
+++ b/src/mess/video/thomson.c
@@ -0,0 +1,1344 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Thomson 8-bit computers
+
+**********************************************************************/
+
+#include <math.h>
+#include "includes/thomson.h"
+
+
+#define VERBOSE 0
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+/* One GPL is what is drawn in 1 us by the video system in the active window.
+ Most of the time, it corresponds to a 8-pixel wide horizontal span.
+ For some TO8/9/9+/MO6 modes, it can be 4-pixel or 16-pixel wide.
+ There are always 40 GPLs in an active row, and it is always defined by
+ two bytes in video memory (0x2000 bytes appart).
+*/
+
+#define THOM_GPL_PER_LINE 40
+
+
+/****************** dynamic screen size *****************/
+
+/* We allow choosing dynamically:
+ - the border size
+ - whether we use 640 pixels or 320 pixels in an active row
+ (now this is automatically choosen by default for each frame)
+*/
+
+
+
+static UINT16 thom_bwidth;
+static UINT16 thom_bheight;
+/* border size */
+
+
+static UINT8 thom_hires;
+/* 0 = low res: 320x200 active area (faster)
+ 1 = hi res: 640x200 active area (can represent all video modes)
+*/
+
+
+static UINT8 thom_hires_better;
+/* 1 = a 640 mode was used in the last frame */
+
+
+
+static int thom_update_screen_size( running_machine &machine )
+{
+ screen_device *screen = machine.first_screen();
+ const rectangle &visarea = screen->visible_area();
+ UINT8 p = machine.root_device().ioport("vconfig")->read();
+ int new_w, new_h, changed = 0;
+
+ switch ( p & 3 )
+ {
+ case 0: thom_bwidth = 56; thom_bheight = 47; break; /* as in original (?) */
+ case 1: thom_bwidth = 16; thom_bheight = 16; break; /* small */
+ default: thom_bwidth = 0; thom_bheight = 0; break; /* none */
+ }
+
+ switch ( p & 0xc )
+ {
+ case 0: thom_hires = 0; break; /* low */
+ case 4: thom_hires = 1; break; /* high */
+ default: thom_hires = thom_hires_better; break; /* auto */
+ }
+
+ new_w = ( 320 + thom_bwidth * 2 ) * ( thom_hires + 1 ) - 1;
+ new_h = ( 200 + thom_bheight * 2 ) /** (thom_hires + 1 )*/ - 1;
+ if ( ( visarea.max_x != new_w ) || ( visarea.max_y != new_h ) )
+ {
+ changed = 1;
+ machine.primary_screen->set_visible_area(0, new_w, 0, new_h );
+ }
+
+ return changed;
+}
+
+
+
+/*********************** video timing ******************************/
+
+/* we use our own video timing to precisely cope with VBLANK and HBLANK */
+
+
+
+static emu_timer* thom_video_timer; /* time elapsed from beginning of frame */
+
+
+
+/* elapsed time from beginning of frame, in us */
+INLINE unsigned thom_video_elapsed ( running_machine &machine )
+{
+ unsigned u;
+ attotime elapsed = thom_video_timer ->elapsed( );
+ u = (elapsed * 1000000 ).seconds;
+ if ( u >= 19968 )
+ u = 19968;
+ return u;
+}
+
+
+
+struct thom_vsignal thom_get_vsignal ( running_machine &machine )
+{
+ struct thom_vsignal v;
+ int gpl = thom_video_elapsed( machine ) - 64 * THOM_BORDER_HEIGHT - 7;
+ if ( gpl < 0 )
+ gpl += 19968;
+
+ v.inil = ( gpl & 63 ) <= 40;
+
+ v.init = gpl < (64 * THOM_ACTIVE_HEIGHT - 24);
+
+ v.lt3 = ( gpl & 8 ) ? 1 : 0;
+
+ v.line = gpl >> 6;
+
+ v.count = v.line * 320 + ( gpl & 63 ) * 8;
+
+ return v;
+}
+
+
+
+/************************** lightpen *******************************/
+
+
+
+static void thom_get_lightpen_pos( running_machine &machine, int*x, int* y )
+{
+ *x = machine.root_device().ioport("lightpen_x")->read();
+ *y = machine.root_device().ioport("lightpen_y")->read();
+
+ if ( *x < 0 )
+ *x = 0;
+
+ if ( *y < 0 )
+ *y = 0;
+
+ if ( *x > 2 * thom_bwidth + 319 )
+ *x = 2 * thom_bwidth + 319;
+
+ if ( *y > 2 * thom_bheight + 199 )
+ *y = 2 * thom_bheight + 199;
+}
+
+
+
+struct thom_vsignal thom_get_lightpen_vsignal ( running_machine &machine, int xdec, int ydec, int xdec2 )
+{
+ struct thom_vsignal v;
+ int x, y;
+ int gpl;
+
+ thom_get_lightpen_pos( machine, &x, &y );
+ x += xdec - thom_bwidth;
+ y += ydec - thom_bheight;
+
+ gpl = (x >> 3) + y * 64;
+ if ( gpl < 0 )
+ gpl += 19968;
+
+ v.inil = (gpl & 63) <= 41;
+
+ v.init = (gpl <= 64 * THOM_ACTIVE_HEIGHT - 24);
+
+ v.lt3 = ( gpl & 8 ) ? 1 : 0;
+
+ v.line = y;
+
+ if ( v.inil && v.init )
+ v.count =
+ ( gpl >> 6 ) * 320 + /* line */
+ ( gpl & 63 ) * 8 + /* gpl inside line */
+ ( (x + xdec2) & 7 ); /* pixel inside gpl */
+ else
+ v.count = 0;
+
+ return v;
+}
+
+
+
+/* number of lightpen call-backs per frame */
+static int thom_lightpen_nb;
+
+
+/* called thom_lightpen_nb times */
+static emu_timer *thom_lightpen_timer;
+
+
+/* lightpen callback function to call from timer */
+static void (*thom_lightpen_cb) ( running_machine &machine, int );
+
+
+
+void thom_set_lightpen_callback ( running_machine &machine, int nb, void (*cb) ( running_machine &machine, int step ) )
+{
+ LOG (( "%f thom_set_lightpen_callback called\n", machine.time().as_double()));
+ thom_lightpen_nb = nb;
+ thom_lightpen_cb = cb;
+}
+
+static TIMER_CALLBACK( thom_lightpen_step )
+{
+ int step = param;
+
+ if ( thom_lightpen_cb )
+ thom_lightpen_cb( machine, step );
+
+ if ( step < thom_lightpen_nb )
+ thom_lightpen_timer->adjust(attotime::from_usec( 64 ), step + 1);
+}
+
+
+
+/***************** scan-line oriented engine ***********************/
+
+/* This code, common for all Thomson machines, emulates the TO8
+ video hardware, with its 16-colors chosen among 4096, 9 video modes,
+ and 4 video pages. Moreover, it emulates changing the palette several times
+ per frame to simulate more than 16 colors per frame (and the same for mode
+ and page switchs) and cooper effects (distinguishing the left and right
+ border color of each row).
+
+ TO7, TO7/70 and MO5 video hardware are much simpler (8 or 16 fixed colors,
+ one mode and one video page). Although the three are different, they can all
+ be emulated by the TO8 video hardware.
+ Thus, we use the same TO8-emulation code to deal with these simpler
+ hardware (although it is somewhat of an overkill).
+*/
+
+
+
+/* ---------------- state & state changes ---------------- */
+
+
+
+UINT8* thom_vram; /* pointer to video memory */
+
+static emu_timer* thom_scanline_timer; /* scan-line udpate */
+
+static UINT16 thom_last_pal[16]; /* palette at last scanline start */
+static UINT16 thom_pal[16]; /* current palette */
+static UINT8 thom_pal_changed; /* whether pal != old_pal */
+static UINT8 thom_border_index; /* current border color index */
+
+/* the left and right border color for each row (including top and bottom
+ border rows); -1 means unchanged wrt last scanline
+*/
+static INT16 thom_border_l[THOM_TOTAL_HEIGHT+1];
+static INT16 thom_border_r[THOM_TOTAL_HEIGHT+1];
+
+
+/* active area, updated one scan-line at a time every 64us,
+ then blitted in SCREEN_UPDATE_IND16
+*/
+static UINT16 thom_vbody[640*200];
+
+static UINT8 thom_vmode; /* current vide mode */
+static UINT8 thom_vpage; /* current video page */
+
+/* this stores the video mode & page at each GPL in the current line
+ (-1 means unchanged)
+*/
+static INT16 thom_vmodepage[41];
+static UINT8 thom_vmodepage_changed;
+
+/* one dirty flag for each video memory line */
+static UINT8 thom_vmem_dirty[205];
+
+/* set to 1 if undirty scanlines need to be redrawn due to other video state
+ changes */
+static UINT8 thom_vstate_dirty;
+static UINT8 thom_vstate_last_dirty;
+
+
+
+/* returns 1 if the mode is 640 pixel wide, 0 if it is 160 or 320 */
+static int thom_mode_is_hires( int mode )
+{
+ return ( mode == THOM_VMODE_80 ) || ( mode == THOM_VMODE_80_TO9 );
+}
+
+
+
+/* either the border index or its palette entry has changed */
+static void thom_border_changed( running_machine &machine )
+{
+ unsigned l = thom_video_elapsed( machine );
+ unsigned y = l >> 6;
+ unsigned x = l & 63;
+ unsigned color = thom_pal[ thom_border_index ];
+
+ if ( y >= THOM_TOTAL_HEIGHT )
+ {
+ /* end of page */
+ thom_border_r[ THOM_TOTAL_HEIGHT ] = color;
+ }
+ else if ( ! x )
+ {
+ /* start of line */
+ thom_border_l[ y ] = color;
+ thom_border_r[ y ] = color;
+ }
+ else if ( x <= 19 )
+ {
+ /* between left and right border */
+ /* NOTE: this makes the lower right part of the color picker blink
+ in the TO8/TO9/TO9+, which actually happens on the real computer!
+ */
+ thom_border_r[ y ] = color;
+ thom_border_l[ y + 1 ] = color;
+ }
+ else
+ {
+ /* end of line */
+ thom_border_l[ y + 1 ] = color;
+ thom_border_r[ y + 1 ] = color;
+ }
+ thom_vstate_dirty = 1;
+}
+
+
+
+/* the video mode or page has changed */
+static void thom_gplinfo_changed( running_machine &machine )
+{
+ unsigned l = thom_video_elapsed( machine ) - THOM_BORDER_HEIGHT * 64 - 7;
+ unsigned y = l >> 6;
+ unsigned x = l & 63;
+ int modepage = ((int)thom_vmode << 8) | thom_vpage;
+ if ( y >= 200 || x>= 40 )
+ thom_vmodepage[ 40 ] = modepage;
+ else
+ thom_vmodepage[ x ] = modepage;
+ thom_vmodepage_changed = 1;
+}
+
+
+
+void thom_set_border_color ( running_machine &machine, unsigned index )
+{
+ assert( index < 16 );
+ if ( index != thom_border_index )
+ {
+ LOG (( "thom_set_border_color: %i at line %i col %i\n", index, thom_video_elapsed( machine ) / 64, thom_video_elapsed( machine ) % 64 ));
+ thom_border_index = index;
+ thom_border_changed( machine );
+ }
+}
+
+
+
+void thom_set_palette ( running_machine &machine, unsigned index, UINT16 color )
+{
+ assert( index < 16 );
+
+ if ( color != 0x1000 )
+ color &= 0xfff;
+
+ if ( thom_pal[ index ] == color )
+ return;
+
+ LOG (( "thom_set_palette: %i to %03x at line %i col %i\n", index, color, thom_video_elapsed( machine ) / 64, thom_video_elapsed( machine ) % 64 ));
+
+ thom_pal[ index ] = color;
+ if ( index == thom_border_index )
+ thom_border_changed( machine );
+ thom_pal_changed = 1;
+ thom_vstate_dirty = 1;
+}
+
+
+
+void thom_set_video_mode ( running_machine &machine, unsigned mode )
+{
+ assert( mode < THOM_VMODE_NB );
+
+ if ( mode != thom_vmode )
+ {
+ LOG (( "thom_set_video_mode: %i at line %i, col %i\n", mode, thom_video_elapsed( machine ) / 64, thom_video_elapsed( machine ) % 64 ));
+ thom_vmode = mode;
+ thom_gplinfo_changed( machine );
+ thom_vstate_dirty = 1;
+ thom_hires_better |= thom_mode_is_hires( mode );
+ }
+}
+
+
+
+void thom_set_video_page ( running_machine &machine, unsigned page )
+{
+ assert( page < THOM_NB_PAGES )
+ ;
+ if ( page != thom_vpage ) {
+ LOG (( "thom_set_video_page: %i at line %i col %i\n", page, thom_video_elapsed( machine ) / 64, thom_video_elapsed( machine ) % 64 ));
+ thom_vpage = page;
+ thom_gplinfo_changed( machine );
+ thom_vstate_dirty = 1;
+ }
+}
+
+
+
+/* -------------- drawing --------------- */
+
+
+
+typedef void ( *thom_scandraw ) ( running_machine &machine, UINT8* vram, UINT16* dst, UINT16* pal,
+ int org, int len );
+
+
+
+#define UPDATE( name, res ) \
+ static void name##_scandraw_##res ( running_machine &machine, \
+ UINT8* vram, UINT16* dst, UINT16* pal, \
+ int org, int len ) \
+ { \
+ unsigned gpl; \
+ vram += org; \
+ dst += org * res; \
+ for ( gpl = 0; gpl < len; gpl++, dst += res, vram++ ) { \
+ UINT8 rama = vram[ 0 ]; \
+ UINT8 ramb = vram[ 0x2000 ];
+
+#define END_UPDATE \
+ } \
+ }
+
+#define UPDATE_HI( name ) UPDATE( name, 16 )
+#define UPDATE_LOW( name ) UPDATE( name, 8 )
+
+
+
+/* 320x200, 16-colors, constraints: 2 distinct colors per GPL (8 pixels) */
+/* this also works for TO7, assuming the 2 top bits of each color byte are 1 */
+
+UPDATE_HI( to770 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ ((ramb & 7) | ((ramb>>4) & 8)) ^ 8 ];
+ c[1] = pal[ ((ramb >> 3) & 15) ^ 8 ];
+ for ( i = 0; i < 16; i += 2, rama >>= 1 )
+ dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ];
+}
+END_UPDATE
+
+UPDATE_LOW( to770 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ ((ramb & 7) | ((ramb>>4) & 8)) ^ 8 ];
+ c[1] = pal[ ((ramb >> 3) & 15) ^ 8 ];
+ for ( i = 0; i < 8; i++, rama >>= 1 )
+ dst[ 7 - i ] = c[ rama & 1 ];
+}
+END_UPDATE
+
+
+
+/* as above, different (more logical but TO7-incompatible) color encoding */
+
+UPDATE_HI( mo5 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ ramb & 15 ];
+ c[1] = pal[ ramb >> 4 ];
+ for ( i = 0; i < 16; i += 2, rama >>= 1 )
+ dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ];
+}
+END_UPDATE
+
+UPDATE_LOW( mo5 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ ramb & 15 ];
+ c[1] = pal[ ramb >> 4 ];
+ for ( i = 0; i < 8; i++, rama >>= 1 )
+ dst[ 7 - i ] = c[ rama & 1 ];
+}
+END_UPDATE
+
+
+
+/* as to770, but with pastel color bit unswitched */
+
+UPDATE_HI( to9 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ (ramb & 7) | ((ramb>>4) & 8) ];
+ c[1] = pal[ (ramb >> 3) & 15 ];
+ for ( i = 0; i < 16; i += 2, rama >>= 1 )
+ dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ];
+}
+END_UPDATE
+
+UPDATE_LOW( to9 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ (ramb & 7) | ((ramb>>4) & 8) ];
+ c[1] = pal[ (ramb >> 3) & 15 ];
+ for ( i = 0; i < 8; i++, rama >>= 1 )
+ dst[ 7 - i ] = c[ rama & 1 ];
+}
+END_UPDATE
+
+
+
+/* 320x200, 4-colors, no constraint */
+
+UPDATE_HI( bitmap4 )
+{
+ int i;
+ pen_t c[2][2];
+ c[0][0] = pal[ 0 ];
+ c[0][1] = pal[ 1 ];
+ c[1][0] = pal[ 2 ];
+ c[1][1] = pal[ 3 ];
+ for ( i = 0; i < 16; i += 2, rama >>= 1, ramb >>= 1 )
+ dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ] [ ramb & 1 ];
+}
+END_UPDATE
+
+UPDATE_LOW( bitmap4 )
+{
+ int i;
+ pen_t c[2][2];
+ c[0][0] = pal[ 0 ];
+ c[0][1] = pal[ 1 ];
+ c[1][0] = pal[ 2 ];
+ c[1][1] = pal[ 3 ];
+ for ( i = 0; i < 8; i++, rama >>= 1, ramb >>= 1 )
+ dst[ 7 - i ] = c[ rama & 1 ] [ ramb & 1 ];
+}
+END_UPDATE
+
+
+
+/* as above, but using 2-bit pixels instead of 2 planes of 1-bit pixels */
+
+UPDATE_HI( bitmap4alt )
+{
+ int i;
+ pen_t c[4];
+ c[0] = pal[ 0 ];
+ c[1] = pal[ 1 ];
+ c[2] = pal[ 2 ];
+ c[3] = pal[ 3 ];
+ for ( i = 0; i < 8; i += 2, ramb >>= 2 )
+ dst[ 15 - i ] = dst[ 14 - i ] = c[ ramb & 3 ];
+ for ( i = 0; i < 8; i += 2, rama >>= 2 )
+ dst[ 7 - i ] = dst[ 6 - i ] = c[ rama & 3 ];
+}
+END_UPDATE
+
+UPDATE_LOW( bitmap4alt )
+{
+ int i;
+ pen_t c[4];
+ c[0] = pal[ 0 ];
+ c[1] = pal[ 1 ];
+ c[2] = pal[ 2 ];
+ c[3] = pal[ 3 ];
+ for ( i = 0; i < 4; i++, ramb >>= 2 )
+ dst[ 7 - i ] = c[ ramb & 3 ];
+ for ( i = 0; i < 4; i++, rama >>= 2 )
+ dst[ 3 - i ] = c[ rama & 3 ];
+}
+END_UPDATE
+
+
+
+/* 160x200, 16-colors, no constraint */
+
+UPDATE_HI( bitmap16 )
+{
+ dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = pal[ rama >> 4 ];
+ dst[ 4] = dst[ 5] = dst[ 6] = dst[ 7] = pal[ rama & 15 ];
+ dst[ 8] = dst[ 9] = dst[10] = dst[11] = pal[ ramb >> 4 ];
+ dst[12] = dst[13] = dst[14] = dst[15] = pal[ ramb & 15 ];
+}
+END_UPDATE
+
+UPDATE_LOW( bitmap16 )
+{
+ dst[0] = dst[1] = pal[ rama >> 4 ];
+ dst[2] = dst[3] = pal[ rama & 15 ];
+ dst[4] = dst[5] = pal[ ramb >> 4 ];
+ dst[6] = dst[7] = pal[ ramb & 15 ];
+}
+END_UPDATE
+
+
+
+/* 640x200 (80 text column), 2-colors, no constraint */
+
+UPDATE_HI( mode80 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ 0 ];
+ c[1] = pal[ 1 ];
+ for ( i = 0; i < 8; i++, ramb >>= 1 )
+ dst[ 15 - i ] = c[ ramb & 1 ];
+ for ( i = 0; i < 8; i++, rama >>= 1 )
+ dst[ 7 - i ] = c[ rama & 1 ];
+}
+END_UPDATE
+
+UPDATE_LOW( mode80 )
+{
+ /* 640-pixel mode but 320 pixels emulated => we merge pixels */
+ int i;
+ pen_t c[4];
+ c[0] = pal[ 0 ];
+ c[1] = c[2] = c[3] = pal[ 1 ];
+ for ( i = 0; i < 4; i++, ramb >>= 2 )
+ dst[ 7 - i ] = c[ ramb & 3 ];
+ for ( i = 0; i < 4; i++, rama >>= 2 )
+ dst[ 3 - i ] = c[ rama & 3 ];
+}
+END_UPDATE
+
+
+
+/* as above, but TO9 flavor */
+
+UPDATE_HI( mode80_to9 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ 0 ];
+ c[1] = pal[ 6 ];
+ for ( i = 0; i < 8; i++, ramb >>= 1 )
+ dst[ 15 - i ] = c[ ramb & 1 ];
+ for ( i = 0; i < 8; i++, rama >>= 1 )
+ dst[ 7 - i ] = c[ rama & 1 ];
+}
+END_UPDATE
+
+UPDATE_LOW( mode80_to9 )
+{
+ int i;
+ pen_t c[4];
+ c[0] = pal[ 0 ];
+ c[1] = c[2] = c[3] = pal[ 6 ];
+ for ( i = 0; i < 4; i++, ramb >>= 2 )
+ dst[ 7 - i ] = c[ ramb & 3 ];
+ for ( i = 0; i < 4; i++, rama >>= 2 )
+ dst[ 3 - i ] = c[ rama & 3 ];
+}
+END_UPDATE
+
+
+
+/* 320x200, 2-colors, two pages (untested) */
+
+UPDATE_HI( page1 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ 0 ];
+ c[1] = pal[ 1 ];
+ for ( i = 0; i < 16; i += 2, rama >>= 1 )
+ dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ];
+ (void)ramb;
+}
+END_UPDATE
+
+UPDATE_LOW( page1 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ 0 ];
+ c[1] = pal[ 1 ];
+ for ( i = 0; i < 8; i++, rama >>= 1 )
+ dst[ 7 - i ] = c[ rama & 1 ];
+ (void)ramb;
+}
+END_UPDATE
+
+UPDATE_HI( page2 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ 0 ];
+ c[1] = pal[ 2 ];
+ for ( i = 0; i < 16; i += 2, ramb >>= 1 )
+ dst[ 15 - i ] = dst[ 14 - i ] = c[ ramb & 1 ];
+ (void)rama;
+}
+END_UPDATE
+
+UPDATE_LOW( page2 )
+{
+ int i;
+ pen_t c[2];
+ c[0] = pal[ 0 ];
+ c[1] = pal[ 2 ];
+ for ( i = 0; i < 8; i++, ramb >>= 1 )
+ dst[ 7 - i ] = c[ ramb & 1 ];
+ (void)rama;
+}
+END_UPDATE
+
+
+
+/* 320x200, 2-colors, two overlaid pages (untested) */
+
+UPDATE_HI( overlay )
+{
+ int i;
+ pen_t c[2][2];
+ c[0][0] = pal[ 0 ];
+ c[0][1] = c[1][1] = pal[ 1 ];
+ c[1][0] = pal[ 2 ];
+ for ( i = 0; i < 16; i += 2, rama >>= 1, ramb >>= 1 )
+ dst[ 15 - i ] = dst[ 14 - i ] = c[ ramb & 1 ] [ rama & 1 ];
+}
+END_UPDATE
+
+UPDATE_LOW( overlay )
+{
+ int i;
+ pen_t c[2][2];
+ c[0][0] = pal[ 0 ];
+ c[0][1] = c[1][1] = pal[ 1 ];
+ c[1][0] = pal[ 2 ];
+ for ( i = 0; i < 8; i++, rama >>= 1, ramb >>= 1 )
+ dst[ 7 - i ] = c[ ramb & 1 ] [ rama & 1 ];
+}
+END_UPDATE
+
+
+
+/* 160x200, 4-colors, four overlaid pages (untested) */
+
+UPDATE_HI( overlay3 )
+{
+ static const int p[2][2][2][2] = {
+ { { { 0, 1 }, { 2, 1 }, }, { { 4, 1 }, { 2, 1 } } },
+ { { { 8, 1 }, { 2, 1 }, }, { { 4, 1 }, { 2, 1 } } }
+ };
+ int i;
+ for ( i = 0; i < 16; i += 4, rama >>= 1, ramb >>= 1 )
+ dst[ 15 - i ] = dst[ 14 - i ] = dst[ 13 - i ] = dst[ 12 - i ] =
+ pal[ p[ ramb & 1 ] [ (ramb >> 4) & 1 ]
+ [ rama & 1 ] [ (rama >> 4) & 1 ] ];
+}
+END_UPDATE
+
+UPDATE_LOW( overlay3 )
+{
+ static const int p[2][2][2][2] = {
+ { { { 0, 1 }, { 2, 1 }, }, { { 4, 1 }, { 2, 1 } } },
+ { { { 8, 1 }, { 2, 1 }, }, { { 4, 1 }, { 2, 1 } } }
+ };
+ int i;
+ for ( i = 0; i < 8; i += 2, rama >>= 1, ramb >>= 1 )
+ dst[ 7 - i ] = dst[ 6 - i ] =
+ pal[ p[ ramb & 1 ] [ (ramb >> 4) & 1 ]
+ [ rama & 1 ] [ (rama >> 4) & 1 ] ];
+}
+END_UPDATE
+
+
+
+#define FUN(x) { x##_scandraw_8, x##_scandraw_16 }
+
+
+static const thom_scandraw thom_scandraw_funcs[THOM_VMODE_NB][2] =
+{
+ FUN(to770), FUN(mo5), FUN(bitmap4), FUN(bitmap4alt), FUN(mode80),
+ FUN(bitmap16), FUN(page1), FUN(page2), FUN(overlay), FUN(overlay3),
+ FUN(to9), FUN(mode80_to9),
+};
+
+
+
+/* called at the start of each scanline in the active area, just after
+ left border (-1<=y<199), and also after the last scanline (y=199)
+*/
+static TIMER_CALLBACK( thom_scanline_start )
+{
+ int y = param;
+
+ /* update active-area */
+ if ( y >= 0 && (thom_vstate_dirty || thom_vstate_last_dirty || thom_vmem_dirty[y]) )
+ {
+ int x = 0;
+ while ( x < 40 )
+ {
+ int xx = x;
+ unsigned mode = thom_vmodepage[x] >> 8;
+ unsigned page = thom_vmodepage[x] & 0xff;
+ assert( mode < THOM_VMODE_NB );
+ assert( page < 4 );
+ if ( thom_vmodepage_changed )
+ {
+ do
+ {
+ xx++;
+ }
+ while ( xx < 40 && thom_vmodepage[xx] == -1 );
+ }
+ else
+ {
+ xx = 40;
+ }
+ thom_scandraw_funcs[ mode ][ thom_hires ]
+ ( machine,
+ thom_vram + y * 40 + page * 0x4000,
+ thom_vbody + y * 320 * (thom_hires+1),
+ thom_last_pal, x, xx-x );
+ x = xx;
+ }
+ thom_vmem_dirty[y] = 0;
+ }
+
+ /* prepare for next scanline */
+ if ( y == 199 )
+ thom_scanline_timer->adjust(attotime::never);
+ else
+ {
+
+ if ( thom_vmodepage_changed )
+ {
+ int x, m = 0;
+ for ( x = 0; x <= 40; x++ )
+ {
+ if ( thom_vmodepage[x] !=-1 )
+ {
+ m = thom_vmodepage[x];
+ thom_vmodepage[x] = -1;
+ }
+ }
+ thom_vmodepage[0] = m;
+ thom_vmodepage_changed = 0;
+ }
+
+ if ( thom_pal_changed )
+ {
+ memcpy( thom_last_pal, thom_pal, 32 );
+ thom_pal_changed = 0;
+ }
+
+ thom_scanline_timer->adjust(attotime::from_usec(64), y + 1);
+ }
+}
+
+
+
+/* -------------- misc --------------- */
+
+
+
+static UINT32 thom_mode_point;
+
+static UINT32 thom_floppy_wcount;
+static UINT32 thom_floppy_rcount;
+
+#define FLOP_STATE (thom_floppy_wcount ? 2 : thom_floppy_rcount ? 1 : 0)
+
+
+
+void thom_set_mode_point ( running_machine &machine, int point )
+{
+ assert( point >= 0 && point <= 1 );
+ thom_mode_point = ( ! point ) * 0x2000;
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( ! point );
+}
+
+
+
+void thom_floppy_active ( running_machine &machine, int write )
+{
+ int fold = FLOP_STATE, fnew;
+
+ /* stays up for a few frames */
+ if ( write )
+ thom_floppy_wcount = 25;
+ else
+ thom_floppy_rcount = 25;
+
+ /* update icon */
+ fnew = FLOP_STATE;
+ if ( fold != fnew )
+ output_set_value( "floppy", fnew );
+}
+
+
+
+/* -------------- main update function --------------- */
+
+
+
+SCREEN_UPDATE_IND16 ( thom )
+{
+ int y, ypos;
+ const int scale = thom_hires ? 2 : 1;
+ const int xbleft = thom_bwidth * scale;
+ const int xbright = ( thom_bwidth + THOM_ACTIVE_WIDTH ) * scale;
+ const int xright = ( thom_bwidth * 2 + THOM_ACTIVE_WIDTH ) * scale;
+ const int xwidth = THOM_ACTIVE_WIDTH * scale;
+ const int yup = THOM_BORDER_HEIGHT + THOM_ACTIVE_HEIGHT;
+ const int ybot = THOM_BORDER_HEIGHT + thom_bheight + 200;
+ UINT16* v = thom_vbody;
+ pen_t border = 0;
+ rectangle wrect(0, xright - 1, 0, 0);
+ rectangle lrect(0, xbleft - 1, 0, 0);
+ rectangle rrect(xbright, xright - 1, 0, 0);
+
+ //LOG (( "%f thom: video update called\n", machine.time().as_double()));
+
+ /* upper border */
+ for ( y = 0; y < THOM_BORDER_HEIGHT - thom_bheight; y++ )
+ {
+ if ( thom_border_l[ y ] != -1 )
+ border = thom_border_l[ y ];
+ }
+ ypos = 0;
+ while ( y < THOM_BORDER_HEIGHT )
+ {
+ if ( thom_border_l[ y ] != -1 )
+ border = thom_border_l[ y ];
+ wrect.min_y = ypos;
+ do
+ {
+ y++;
+ ypos ++ /* += scale */;
+ }
+ while ( y < THOM_BORDER_HEIGHT && thom_border_l[ y ] == -1 );
+ wrect.max_y = ypos - 1;
+ bitmap.fill(border, wrect );
+ }
+
+ /* left border */
+ while ( y < yup )
+ {
+ if ( thom_border_l[ y ] != -1 )
+ border = thom_border_l[ y ];
+ lrect.min_y = ypos;
+ do
+ {
+ y++;
+ ypos ++ /* += scale */;
+ }
+ while ( y < yup && thom_border_l[ y ] == -1 );
+ lrect.max_y = ypos - 1;
+ bitmap.fill(border, lrect );
+ }
+
+ /* lower border */
+ while (y < ybot )
+ {
+ if ( thom_border_l[ y ] != -1 )
+ border = thom_border_l[ y ];
+ wrect.min_y = ypos;
+ do
+ {
+ y++;
+ ypos ++ /* += scale */;
+ } while ( y < ybot && thom_border_l[ y ] == -1 );
+ wrect.max_y = ypos - 1;
+ bitmap.fill(border, wrect );
+ }
+
+ /* right border */
+ for ( y = 0; y < THOM_BORDER_HEIGHT; y++ ) {
+ if ( thom_border_r[ y ] != -1 )
+ border = thom_border_r[ y ];
+ }
+ ypos = thom_bheight /* * scale */;
+ while ( y < yup )
+ {
+ if ( thom_border_r[ y ] != -1 )
+ border = thom_border_r[ y ];
+ rrect.min_y = ypos;
+ do
+ {
+ y++;
+ ypos ++ /* += scale */;
+ }
+ while ( y < yup && thom_border_r[ y ] == -1 );
+ rrect.max_y = ypos - 1;
+ bitmap.fill(border, rrect );
+ }
+
+ /* active area */
+ ypos = thom_bheight /* * scale */;
+ for ( y = 0; y < 200; v += xwidth, y++ , ypos ++ /* += scale */ )
+ {
+ draw_scanline16( bitmap, xbleft, ypos, xwidth, v, NULL );
+#if 0
+ if ( thom_hires )
+ draw_scanline16( bitmap, xbleft, ypos+1, xwidth, v, NULL );
+#endif
+ }
+
+ return 0;
+}
+
+
+
+/* -------------- frame start ------------------ */
+
+
+
+static emu_timer *thom_init_timer;
+
+static void (*thom_init_cb) ( running_machine &machine, int init );
+
+
+
+void thom_set_init_callback ( running_machine &machine, void (*cb) ( running_machine &machine, int init ) )
+{
+ thom_init_cb = cb;
+}
+
+
+
+static TIMER_CALLBACK( thom_set_init )
+{
+ int init = param;
+ LOG (( "%f thom_set_init: %i, at line %i col %i\n", machine.time().as_double(), init, thom_video_elapsed( machine ) / 64, thom_video_elapsed( machine ) % 64 ));
+
+ if ( thom_init_cb )
+ thom_init_cb( machine, init );
+ if ( ! init )
+ thom_init_timer->adjust(attotime::from_usec( 64 * THOM_ACTIVE_HEIGHT - 24 ), 1-init);
+}
+
+/* call this at the very beginning of each new frame */
+SCREEN_VBLANK ( thom )
+{
+ // rising edge
+ if (vblank_on)
+ {
+ int fnew, fold = FLOP_STATE;
+ int i;
+ UINT16 b = 0;
+ struct thom_vsignal l = thom_get_lightpen_vsignal( screen.machine(), 0, -1, 0 );
+
+ LOG (( "%f thom: video eof called\n", screen.machine().time().as_double() ));
+
+ /* floppy indicator count */
+ if ( thom_floppy_wcount )
+ thom_floppy_wcount--;
+ if ( thom_floppy_rcount )
+ thom_floppy_rcount--;
+ fnew = FLOP_STATE;
+ if ( fnew != fold )
+ output_set_value( "floppy", fnew );
+
+ /* prepare state for next frame */
+ for ( i = 0; i <= THOM_TOTAL_HEIGHT; i++ )
+ {
+ if ( thom_border_l[ i ] != -1 )
+ b = thom_border_l[ i ];
+ if ( thom_border_r[ i ] != -1 )
+ b = thom_border_r[ i ];
+ }
+ memset( thom_border_l, 0xff, sizeof( thom_border_l ) );
+ memset( thom_border_r, 0xff, sizeof( thom_border_r ) );
+ thom_border_l[ 0 ] = b;
+ thom_border_r[ 0 ] = b;
+ thom_vstate_last_dirty = thom_vstate_dirty;
+ thom_vstate_dirty = 0;
+
+ /* schedule first init signal */
+ thom_init_timer->adjust(attotime::from_usec( 64 * THOM_BORDER_HEIGHT + 7 ));
+
+ /* schedule first lightpen signal */
+ l.line &= ~1; /* hack (avoid lock in MO6 palette selection) */
+ thom_lightpen_timer->adjust(
+ attotime::from_usec( 64 * ( THOM_BORDER_HEIGHT + l.line - 2 ) + 16 ), 0);
+
+ /* schedule first active-area scanline call-back */
+ thom_scanline_timer->adjust(attotime::from_usec( 64 * THOM_BORDER_HEIGHT + 7), -1);
+
+ /* reset video frame time */
+ thom_video_timer->adjust(attotime::zero);
+
+ /* update screen size according to user options */
+ if ( thom_update_screen_size( screen.machine() ) )
+ thom_vstate_dirty = 1;
+
+ /* hi-res automatic */
+ thom_hires_better = thom_mode_is_hires( thom_vmode );
+ }
+}
+
+
+
+/* -------------- initialization --------------- */
+
+
+
+static const UINT16 thom_pal_init[16] =
+{
+ 0x1000, /* 0: black */ 0x000f, /* 1: red */
+ 0x00f0, /* 2: geen */ 0x00ff, /* 3: yellow */
+ 0x0f00, /* 4: blue */ 0x0f0f, /* 5: purple */
+ 0x0ff0, /* 6: cyan */ 0x0fff, /* 7: white */
+ 0x0777, /* 8: gray */ 0x033a, /* 9: pink */
+ 0x03a3, /* a: light green */ 0x03aa, /* b: light yellow */
+ 0x0a33, /* c: light blue */ 0x0a3a, /* d: redish pink */
+ 0x0ee7, /* e: light cyan */ 0x003b, /* f: orange */
+};
+
+
+
+VIDEO_START ( thom )
+{
+ LOG (( "thom: video start called\n" ));
+
+ /* scan-line state */
+ memcpy( thom_last_pal, thom_pal_init, 32 );
+ memcpy( thom_pal, thom_pal_init, 32 );
+ memset( thom_border_l, 0xff, sizeof( thom_border_l ) );
+ memset( thom_border_r, 0xff, sizeof( thom_border_r ) );
+ memset( thom_vbody, 0, sizeof( thom_vbody ) );
+ memset( thom_vmodepage, 0xffff, sizeof( thom_vmodepage ) );
+ memset( thom_vmem_dirty, 0, sizeof( thom_vmem_dirty ) );
+ thom_border_l[ 0 ] = 0;
+ thom_border_r[ 0 ] = 0;
+ thom_vmodepage[ 0 ] = 0;
+ thom_vmodepage_changed = 0;
+ thom_vmode = 0;
+ thom_vpage = 0;
+ thom_border_index = 0;
+ thom_vstate_dirty = 1;
+ thom_vstate_last_dirty = 1;
+ state_save_register_global_array(machine, thom_last_pal );
+ state_save_register_global_array(machine, thom_pal );
+ state_save_register_global_array(machine, thom_border_l );
+ state_save_register_global_array(machine, thom_border_r );
+ state_save_register_global_array(machine, thom_vbody );
+ state_save_register_global_array(machine, thom_vmodepage );
+ state_save_register_global_array(machine, thom_vmem_dirty );
+ state_save_register_global(machine, thom_pal_changed );
+ state_save_register_global(machine, thom_vmodepage_changed );
+ state_save_register_global(machine, thom_vmode );
+ state_save_register_global(machine, thom_vpage );
+ state_save_register_global(machine, thom_border_index );
+ state_save_register_global(machine, thom_vstate_dirty );
+ state_save_register_global(machine, thom_vstate_last_dirty );
+
+ thom_mode_point = 0;
+ state_save_register_global(machine, thom_mode_point );
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( 0 );
+
+ thom_floppy_rcount = 0;
+ thom_floppy_wcount = 0;
+ state_save_register_global(machine, thom_floppy_wcount );
+ state_save_register_global(machine, thom_floppy_rcount );
+ output_set_value( "floppy", 0 );
+
+ thom_video_timer = machine.scheduler().timer_alloc(FUNC_NULL);
+
+ thom_scanline_timer = machine.scheduler().timer_alloc(FUNC(thom_scanline_start));
+
+ thom_lightpen_nb = 0;
+ thom_lightpen_cb = NULL;
+ thom_lightpen_timer = machine.scheduler().timer_alloc(FUNC(thom_lightpen_step));
+ state_save_register_global(machine, thom_lightpen_nb );
+
+ thom_init_cb = NULL;
+ thom_init_timer = machine.scheduler().timer_alloc(FUNC(thom_set_init));
+
+ state_save_register_global(machine, thom_bwidth );
+ state_save_register_global(machine, thom_bheight );
+ state_save_register_global(machine, thom_hires );
+ state_save_register_global(machine, thom_hires_better );
+}
+
+
+
+PALETTE_INIT ( thom )
+{
+ double gamma = 0.6f;
+ unsigned i;
+
+ LOG (( "thom: palette init called\n" ));
+
+ for ( i = 0; i < 4097; i++ )
+ {
+ UINT8 r = 255. * pow( (i & 15) / 15., gamma );
+ UINT8 g = 255. * pow( ((i>> 4) & 15) / 15., gamma );
+ UINT8 b = 255. * pow( ((i >> 8) & 15) / 15., gamma );
+ /* UINT8 alpha = i & 0x1000 ? 0 : 255; TODO: transparency */
+ palette_set_color_rgb(machine, i, r, g, b );
+ }
+}
+
+
+
+/***************************** TO7 / T9000 *************************/
+
+
+
+/* write to video memory through addresses 0x4000-0x5fff */
+WRITE8_HANDLER ( to7_vram_w )
+{
+ assert( offset >= 0 && offset < 0x2000 );
+ /* force two topmost color bits to 1 */
+ if ( thom_mode_point )
+ data |= 0xc0;
+ if ( thom_vram[ offset + thom_mode_point ] == data )
+ return;
+ thom_vram[ offset + thom_mode_point ] = data;
+ /* dirty whole scanline */
+ thom_vmem_dirty[ offset / 40 ] = 1;
+}
+
+
+
+/* bits 0-13 : latched gpl of lightpen position */
+/* bit 14: latched INIT */
+/* bit 15: latched INIL */
+unsigned to7_lightpen_gpl ( running_machine &machine, int decx, int decy )
+{
+ int x,y;
+ thom_get_lightpen_pos( machine, &x, &y );
+ x -= thom_bwidth;
+ y -= thom_bheight;
+ if ( x < 0 || y < 0 || x >= 320 || y >= 200 )
+ return 0;
+ x += decx;
+ y += decy;
+ return y*40 + x/8 + (x < 320 ? 0x4000 : 0) + 0x8000;
+}
+
+
+
+/************************** TO7/70 / MO5 ****************************/
+
+
+
+/* write to video memory through addresses 0x4000-0x5fff (TO)
+ or 0x0000-0x1fff (MO) */
+WRITE8_HANDLER ( to770_vram_w )
+{
+ assert( offset >= 0 && offset < 0x2000 );
+ if ( thom_vram[ offset + thom_mode_point ] == data )
+ return;
+ thom_vram[ offset + thom_mode_point ] = data;
+ /* dirty whole scanline */
+ thom_vmem_dirty[ offset / 40 ] = 1;
+}
+
+
+
+
+/***************************** TO8 ******************************/
+
+
+
+/* write to video memory through system space (always page 1) */
+
+WRITE8_HANDLER ( to8_sys_lo_w )
+{
+ UINT8* dst = thom_vram + offset + 0x6000;
+ assert( offset >= 0 && offset < 0x2000 );
+ if ( *dst == data )
+ return;
+ *dst = data;
+ /* dirty whole scanline */
+ thom_vmem_dirty[ offset / 40 ] = 1;
+}
+
+
+
+WRITE8_HANDLER ( to8_sys_hi_w )
+{
+ UINT8* dst = thom_vram + offset + 0x4000;
+ assert( offset >= 0 && offset < 0x2000 );
+ if ( *dst == data ) return;
+ *dst = data;
+ /* dirty whole scanline */
+ thom_vmem_dirty[ offset / 40 ] = 1;
+}
+
+
+
+/* write to video memory through data space */
+
+WRITE8_HANDLER ( to8_data_lo_w )
+{
+ UINT8* dst = thom_vram + offset + 0x4000 * to8_data_vpage + 0x2000;
+ assert( offset >= 0 && offset < 0x2000 );
+ if ( *dst == data )
+ return;
+ *dst = data;
+ /* dirty whole scanline */
+ if ( to8_data_vpage >= 4 )
+ return;
+ thom_vmem_dirty[ offset / 40 ] = 1;
+}
+
+
+
+WRITE8_HANDLER ( to8_data_hi_w )
+{
+ UINT8* dst = thom_vram + offset + 0x4000 * to8_data_vpage;
+ assert( offset >= 0 && offset < 0x2000 );
+ if ( *dst == data )
+ return;
+ *dst = data;
+ /* dirty whole scanline */
+ if ( to8_data_vpage >= 4 )
+ return;
+ thom_vmem_dirty[ offset / 40 ] = 1;
+}
+
+
+
+/* write to video memory page through cartridge addresses space */
+WRITE8_HANDLER ( to8_vcart_w )
+{
+ UINT8* dst = thom_vram + offset + 0x4000 * to8_cart_vpage;
+ assert( offset>=0 && offset < 0x4000 );
+ if ( *dst == data )
+ return;
+ *dst = data;
+ /* dirty whole scanline */
+ if ( to8_cart_vpage >= 4 )
+ return;
+ thom_vmem_dirty[ (offset & 0x1fff) / 40 ] = 1;
+}
+
diff --git a/src/mess/video/ti85.c b/src/mess/video/ti85.c
new file mode 100644
index 00000000000..135283053c0
--- /dev/null
+++ b/src/mess/video/ti85.c
@@ -0,0 +1,196 @@
+/***************************************************************************
+ TI-85 driver by Krzysztof Strzecha
+
+ Functions to emulate the video hardware of the TI-85
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/ti85.h"
+
+#define TI81_VIDEO_MEMORY_SIZE 768
+#define TI81_SCREEN_X_SIZE 12
+#define TI81_SCREEN_Y_SIZE 64
+#define TI81_NUMBER_OF_FRAMES 6
+
+#define TI85_VIDEO_MEMORY_SIZE 1024
+#define TI85_SCREEN_X_SIZE 16
+#define TI85_SCREEN_Y_SIZE 64
+#define TI85_NUMBER_OF_FRAMES 6
+
+#define TI86_VIDEO_MEMORY_SIZE 1024
+#define TI86_SCREEN_X_SIZE 16
+#define TI86_SCREEN_Y_SIZE 64
+#define TI86_NUMBER_OF_FRAMES 6
+
+
+
+static const unsigned char ti85_colors[32*7][3] =
+{
+ { 0xae, 0xcd, 0xb0 }, { 0xaa, 0xc9, 0xae }, { 0xa6, 0xc5, 0xad }, { 0xa3, 0xc1, 0xab }, { 0x9f, 0xbd, 0xaa }, { 0x9b, 0xb9, 0xa8 }, { 0x98, 0xb5, 0xa7 }, //0x00
+ { 0xae, 0xcd, 0xb0 }, { 0xa9, 0xc8, 0xae }, { 0xa4, 0xc3, 0xac }, { 0xa0, 0xbe, 0xaa }, { 0x9b, 0xb9, 0xa8 }, { 0x96, 0xb4, 0xa6 }, { 0x92, 0xaf, 0xa4 }, //0x01
+ { 0xae, 0xcd, 0xb0 }, { 0xa8, 0xc7, 0xad }, { 0xa2, 0xc1, 0xab }, { 0x9d, 0xbb, 0xa9 }, { 0x97, 0xb5, 0xa6 }, { 0x91, 0xaf, 0xa4 }, { 0x8c, 0xa9, 0xa2 }, //0x02
+ { 0xae, 0xcd, 0xb0 }, { 0xa7, 0xc6, 0xad }, { 0xa0, 0xbf, 0xaa }, { 0x9a, 0xb8, 0xa7 }, { 0x93, 0xb1, 0xa4 }, { 0x8c, 0xaa, 0xa1 }, { 0x86, 0xa3, 0x9f }, //0x03
+ { 0xae, 0xcd, 0xb0 }, { 0xa6, 0xc5, 0xac }, { 0x9f, 0xbd, 0xa9 }, { 0x97, 0xb5, 0xa6 }, { 0x90, 0xad, 0xa3 }, { 0x88, 0xa5, 0xa0 }, { 0x81, 0x9d, 0x9d }, //0x04
+ { 0xae, 0xcd, 0xb0 }, { 0xa5, 0xc4, 0xac }, { 0x9d, 0xbb, 0xa8 }, { 0x94, 0xb2, 0xa5 }, { 0x8c, 0xa9, 0xa1 }, { 0x83, 0xa0, 0x9d }, { 0x7b, 0x97, 0x9a }, //0x05
+ { 0xae, 0xcd, 0xb0 }, { 0xa4, 0xc3, 0xac }, { 0x9b, 0xb9, 0xa8 }, { 0x91, 0xaf, 0xa4 }, { 0x88, 0xa5, 0xa0 }, { 0x7e, 0x9b, 0x9c }, { 0x75, 0x92, 0x98 }, //0x06
+ { 0xae, 0xcd, 0xb0 }, { 0xa3, 0xc2, 0xab }, { 0x99, 0xb7, 0xa7 }, { 0x8e, 0xac, 0xa3 }, { 0x84, 0xa1, 0x9e }, { 0x79, 0x96, 0x9a }, { 0x6f, 0x8c, 0x96 }, //0x07
+ { 0xae, 0xcd, 0xb0 }, { 0xa2, 0xc1, 0xab }, { 0x97, 0xb5, 0xa6 }, { 0x8c, 0xa9, 0xa1 }, { 0x80, 0x9d, 0x9c }, { 0x75, 0x91, 0x97 }, { 0x6a, 0x86, 0x93 }, //0x08
+ { 0xae, 0xcd, 0xb0 }, { 0xa1, 0xc0, 0xaa }, { 0x95, 0xb3, 0xa5 }, { 0x89, 0xa6, 0xa0 }, { 0x7c, 0x99, 0x9b }, { 0x70, 0x8c, 0x96 }, { 0x64, 0x80, 0x91 }, //0x09
+ { 0xae, 0xcd, 0xb0 }, { 0xa0, 0xbf, 0xaa }, { 0x93, 0xb1, 0xa4 }, { 0x86, 0xa3, 0x9f }, { 0x78, 0x95, 0x99 }, { 0x6b, 0x87, 0x93 }, { 0x5e, 0x7a, 0x8e }, //0x0a
+ { 0xae, 0xcd, 0xb0 }, { 0x9f, 0xbe, 0xaa }, { 0x91, 0xaf, 0xa4 }, { 0x83, 0xa0, 0x9e }, { 0x74, 0x91, 0x98 }, { 0x66, 0x82, 0x92 }, { 0x58, 0x74, 0x8c }, //0x0b
+ { 0xae, 0xcd, 0xb0 }, { 0x9e, 0xbd, 0xa9 }, { 0x8f, 0xad, 0xa3 }, { 0x80, 0x9e, 0x9d }, { 0x71, 0x8e, 0x96 }, { 0x62, 0x7e, 0x90 }, { 0x53, 0x6f, 0x8a }, //0x0c
+ { 0xa9, 0xc8, 0xae }, { 0x9a, 0xb9, 0xa8 }, { 0x8c, 0xaa, 0xa2 }, { 0x7e, 0x9b, 0x9c }, { 0x6f, 0x8c, 0x96 }, { 0x61, 0x7d, 0x90 }, { 0x53, 0x6f, 0x8a }, //0x0d
+ { 0xa4, 0xc3, 0xac }, { 0x96, 0xb5, 0xa6 }, { 0x89, 0xa7, 0xa0 }, { 0x7b, 0x99, 0x9b }, { 0x6e, 0x8b, 0x95 }, { 0x60, 0x7d, 0x8f }, { 0x53, 0x6f, 0x8a }, //0x0e
+ { 0xa0, 0xbe, 0xaa }, { 0x93, 0xb0, 0xa4 }, { 0x86, 0xa3, 0x9f }, { 0x79, 0x96, 0x9a }, { 0x6c, 0x89, 0x94 }, { 0x5f, 0x7c, 0x8f }, { 0x53, 0x6f, 0x8a }, //0x0f
+ { 0x9b, 0xba, 0xa8 }, { 0x8f, 0xad, 0xa3 }, { 0x83, 0xa1, 0x9e }, { 0x77, 0x94, 0x99 }, { 0x6b, 0x88, 0x94 }, { 0x5f, 0x7b, 0x8f }, { 0x53, 0x6f, 0x8a }, //0x10
+ { 0x97, 0xb5, 0xa6 }, { 0x8b, 0xa9, 0xa1 }, { 0x80, 0x9d, 0x9c }, { 0x75, 0x92, 0x98 }, { 0x69, 0x86, 0x93 }, { 0x5e, 0x7a, 0x8e }, { 0x53, 0x6f, 0x8a }, //0x11
+ { 0x92, 0xb0, 0xa4 }, { 0x87, 0xa5, 0x9f }, { 0x7d, 0x9a, 0x9b }, { 0x72, 0x8f, 0x97 }, { 0x68, 0x84, 0x92 }, { 0x5d, 0x79, 0x8e }, { 0x53, 0x6f, 0x8a }, //0x12
+ { 0x8e, 0xac, 0xa2 }, { 0x84, 0xa1, 0x9e }, { 0x7a, 0x97, 0x9a }, { 0x70, 0x8d, 0x96 }, { 0x66, 0x83, 0x92 }, { 0x5c, 0x79, 0x8e }, { 0x53, 0x6f, 0x8a }, //0x13
+ { 0x89, 0xa7, 0xa0 }, { 0x80, 0x9d, 0x9c }, { 0x77, 0x94, 0x98 }, { 0x6e, 0x8b, 0x95 }, { 0x65, 0x81, 0x91 }, { 0x5c, 0x78, 0x8d }, { 0x53, 0x6f, 0x8a }, //0x14
+ { 0x85, 0xa2, 0x9e }, { 0x7c, 0x99, 0x9a }, { 0x74, 0x91, 0x97 }, { 0x6c, 0x88, 0x94 }, { 0x63, 0x80, 0x90 }, { 0x5b, 0x77, 0x8d }, { 0x53, 0x6f, 0x8a }, //0x15
+ { 0x80, 0x9e, 0x9d }, { 0x78, 0x96, 0x99 }, { 0x71, 0x8e, 0x96 }, { 0x69, 0x86, 0x93 }, { 0x62, 0x7e, 0x90 }, { 0x5a, 0x76, 0x8d }, { 0x53, 0x6f, 0x8a }, //0x16
+ { 0x7c, 0x99, 0x9b }, { 0x75, 0x92, 0x98 }, { 0x6e, 0x8b, 0x95 }, { 0x67, 0x84, 0x92 }, { 0x60, 0x7d, 0x8f }, { 0x59, 0x76, 0x8c }, { 0x53, 0x6f, 0x8a }, //0x17
+ { 0x77, 0x94, 0x99 }, { 0x71, 0x8d, 0x96 }, { 0x6b, 0x87, 0x94 }, { 0x65, 0x81, 0x91 }, { 0x5f, 0x7b, 0x8f }, { 0x59, 0x75, 0x8c }, { 0x53, 0x6f, 0x8a }, //0x18
+ { 0x73, 0x90, 0x97 }, { 0x6d, 0x8a, 0x94 }, { 0x68, 0x85, 0x92 }, { 0x63, 0x7f, 0x90 }, { 0x5d, 0x7a, 0x8e }, { 0x58, 0x74, 0x8c }, { 0x53, 0x6f, 0x8a }, //0x19
+ { 0x6e, 0x8b, 0x95 }, { 0x69, 0x86, 0x93 }, { 0x65, 0x81, 0x91 }, { 0x60, 0x7d, 0x8f }, { 0x5c, 0x78, 0x8d }, { 0x57, 0x73, 0x8b }, { 0x53, 0x6f, 0x8a }, //0x1a
+ { 0x6a, 0x86, 0x93 }, { 0x66, 0x82, 0x91 }, { 0x62, 0x7e, 0x90 }, { 0x5e, 0x7a, 0x8e }, { 0x5a, 0x76, 0x8d }, { 0x56, 0x72, 0x8b }, { 0x53, 0x6f, 0x8a }, //0x1b
+ { 0x65, 0x82, 0x91 }, { 0x62, 0x7e, 0x8f }, { 0x5f, 0x7b, 0x8e }, { 0x5c, 0x78, 0x8d }, { 0x59, 0x75, 0x8c }, { 0x56, 0x72, 0x8b }, { 0x53, 0x6f, 0x8a }, //0x1c
+ { 0x61, 0x7d, 0x8f }, { 0x5e, 0x7a, 0x8e }, { 0x5c, 0x78, 0x8d }, { 0x5a, 0x76, 0x8c }, { 0x57, 0x73, 0x8b }, { 0x55, 0x71, 0x8a }, { 0x53, 0x6f, 0x8a }, //0x1d
+ { 0x5c, 0x78, 0x8d }, { 0x5a, 0x76, 0x8c }, { 0x59, 0x75, 0x8c }, { 0x57, 0x73, 0x8b }, { 0x56, 0x72, 0x8b }, { 0x54, 0x70, 0x8a }, { 0x53, 0x6f, 0x8a }, //0x1e
+ { 0x57, 0x74, 0x8c }, { 0x56, 0x73, 0x8b }, { 0x55, 0x72, 0x8b }, { 0x55, 0x71, 0x8b }, { 0x54, 0x70, 0x8a }, { 0x53, 0x6f, 0x8a }, { 0x53, 0x6f, 0x8a } //0x1f
+};
+
+static const unsigned short ti85_palette[32][7] =
+{
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 },
+ { 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d },
+ { 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 },
+ { 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b },
+ { 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22 },
+ { 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29 },
+ { 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30 },
+ { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 },
+ { 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e },
+ { 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45 },
+ { 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c },
+ { 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53 },
+ { 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a },
+ { 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61 },
+ { 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68 },
+ { 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f },
+ { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76 },
+ { 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d },
+ { 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84 },
+ { 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b },
+ { 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92 },
+ { 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99 },
+ { 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0 },
+ { 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7 },
+ { 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae },
+ { 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 },
+ { 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc },
+ { 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3 },
+ { 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca },
+ { 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1 },
+ { 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 },
+ { 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf }
+};
+
+PALETTE_INIT( ti85 )
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ UINT8 i, j, r, g, b;
+
+ machine.colortable = colortable_alloc(machine, 224);
+
+ for ( i = 0; i < 224; i++ )
+ {
+ r = ti85_colors[i][0]; g = ti85_colors[i][1]; b = ti85_colors[i][2];
+ colortable_palette_set_color(machine.colortable, i, MAKE_RGB(r, g, b));
+ }
+
+ for (i=0; i < 32; i++)
+ for (j=0; j < 7; j++)
+ colortable_entry_set_value(machine.colortable, i*7+j, ti85_palette[i][j]);
+
+ if (!strncmp(machine.system().name, "ti81", 4))
+ {
+ state->m_ti_video_memory_size = TI81_VIDEO_MEMORY_SIZE;
+ state->m_ti_screen_x_size = TI81_SCREEN_X_SIZE;
+ state->m_ti_screen_y_size = TI81_SCREEN_Y_SIZE;
+ state->m_ti_number_of_frames = TI81_NUMBER_OF_FRAMES;
+ }
+ else if (!strncmp(machine.system().name, "ti85", 4))
+ {
+ state->m_ti_video_memory_size = TI85_VIDEO_MEMORY_SIZE;
+ state->m_ti_screen_x_size = TI85_SCREEN_X_SIZE;
+ state->m_ti_screen_y_size = TI85_SCREEN_Y_SIZE;
+ state->m_ti_number_of_frames = TI85_NUMBER_OF_FRAMES;
+ }
+ else if (!strncmp(machine.system().name, "ti86", 4))
+ {
+ state->m_ti_video_memory_size = TI86_VIDEO_MEMORY_SIZE;
+ state->m_ti_screen_x_size = TI86_SCREEN_X_SIZE;
+ state->m_ti_screen_y_size = TI86_SCREEN_Y_SIZE;
+ state->m_ti_number_of_frames = TI86_NUMBER_OF_FRAMES;
+ }
+ else
+ {
+ /* don't allocate memory for the others drivers */
+ return;
+ }
+
+ state->m_frames = auto_alloc_array_clear(machine, UINT8, state->m_ti_number_of_frames*state->m_ti_video_memory_size);
+}
+
+VIDEO_START( ti85 )
+{
+}
+
+SCREEN_UPDATE_IND16( ti85 )
+{
+ ti85_state *state = screen.machine().driver_data<ti85_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ int x,y,b;
+ int brightnes;
+ int lcdmem;
+
+ if (!state->m_LCD_status || !state->m_timer_interrupt_mask)
+ {
+ for (y=0; y<state->m_ti_screen_y_size; y++)
+ for (x=0; x<state->m_ti_screen_x_size; x++)
+ for (b=0; b<8; b++)
+ bitmap.pix16(y, x*8+b) = ti85_palette[state->m_LCD_contrast&0x1f][6];
+ return 0;
+ }
+
+ lcdmem = ((state->m_LCD_memory_base & 0x3F) + 0xc0) << 0x08;
+
+ memcpy (state->m_frames, state->m_frames+state->m_ti_video_memory_size, sizeof (UINT8) * (state->m_ti_number_of_frames-1) * state->m_ti_video_memory_size);
+
+ for (y=0; y<state->m_ti_screen_y_size; y++)
+ for (x=0; x<state->m_ti_screen_x_size; x++)
+ *(state->m_frames+(state->m_ti_number_of_frames-1)*state->m_ti_video_memory_size+y*state->m_ti_screen_x_size+x) = space->read_byte(lcdmem+y*state->m_ti_screen_x_size+x);
+
+ for (y=0; y<state->m_ti_screen_y_size; y++)
+ for (x=0; x<state->m_ti_screen_x_size; x++)
+ for (b=0; b<8; b++)
+ {
+ brightnes = ((*(state->m_frames+0*state->m_ti_video_memory_size+y*state->m_ti_screen_x_size+x)>>(7-b)) & 0x01)
+ + ((*(state->m_frames+1*state->m_ti_video_memory_size+y*state->m_ti_screen_x_size+x)>>(7-b)) & 0x01)
+ + ((*(state->m_frames+2*state->m_ti_video_memory_size+y*state->m_ti_screen_x_size+x)>>(7-b)) & 0x01)
+ + ((*(state->m_frames+3*state->m_ti_video_memory_size+y*state->m_ti_screen_x_size+x)>>(7-b)) & 0x01)
+ + ((*(state->m_frames+4*state->m_ti_video_memory_size+y*state->m_ti_screen_x_size+x)>>(7-b)) & 0x01)
+ + ((*(state->m_frames+5*state->m_ti_video_memory_size+y*state->m_ti_screen_x_size+x)>>(7-b)) & 0x01);
+
+ bitmap.pix16(y, x*8+b) = ti85_palette[state->m_LCD_contrast&0x1f][brightnes];
+ }
+ return 0;
+}
+
+PALETTE_INIT( ti82 )
+{
+ palette_set_color(machine, 0, MAKE_RGB(160, 190, 170));
+ palette_set_color(machine, 1, MAKE_RGB(83, 111, 138));
+}
diff --git a/src/mess/video/timex.c b/src/mess/video/timex.c
new file mode 100644
index 00000000000..79455ee29fd
--- /dev/null
+++ b/src/mess/video/timex.c
@@ -0,0 +1,262 @@
+/***************************************************************************
+
+ timex.c
+
+ Functions to emulate the video hardware of the Timex ZX Spectrum clones.
+
+ Changes:
+
+ DJR 08/02/00 - Added support for FLASH 1.
+ DJR 16/05/00 - Support for TS2068/TC2048 hires and 64 column modes.
+ DJR 19/05/00 - Speeded up Spectrum 128 screen refresh.
+ DJR 23/05/00 - Preliminary support for border colour emulation.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/spectrum.h"
+#include "machine/ram.h"
+
+INLINE void spectrum_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = (UINT16)color;
+}
+
+/* Update FLASH status for ts2068. Assumes flash update every 1/2s. */
+VIDEO_START( ts2068 )
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ VIDEO_START_CALL( spectrum );
+ state->m_frame_invert_count = 30;
+}
+
+
+/*******************************************************************
+ *
+ * Update the TS2068 display.
+ *
+ * Port ff is used to set the display mode.
+ *
+ * bits 2..0 Video Mode Select
+ * 000 = Primary DFILE active (at 0x4000-0x5aff)
+ * 001 = Secondary DFILE active (at 0x6000-0x7aff)
+ * 010 = Extended Colour Mode (chars at 0x4000-0x57ff, colors 0x6000-0x7aff)
+ * 110 = 64 column mode (columns 0,2,4,...62 from DFILE 1
+ * columns 1,3,5,...63 from DFILE 2)
+ * other = unpredictable results
+ *
+ * bits 5..3 64 column mode ink/paper selection (attribute value in brackets)
+ * 000 = Black/White (56) 100 = Green/Magenta (28)
+ * 001 = Blue/Yellow (49) 101 = Cyan/Red (21)
+ * 010 = Red/Cyan (42) 110 = Yellow/Blue (14)
+ * 011 = Magenta/Green (35) 111 = White/Black (7)
+ *
+ *******************************************************************/
+
+/* Draw a scanline in TS2068/TC2048 hires mode (code modified from COUPE.C) */
+static void ts2068_hires_scanline(running_machine &machine,bitmap_ind16 &bitmap, int y, int borderlines)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ int x,b,scrx,scry;
+ unsigned short ink,pap;
+ unsigned char *attr, *scr;
+
+ scrx=TS2068_LEFT_BORDER;
+ scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0);
+
+ scr=machine.device<ram_device>(RAM_TAG)->pointer() + y*32;
+ attr=scr + 0x2000;
+
+ for (x=0;x<32;x++)
+ {
+ /* Get ink and paper colour with bright */
+ if (state->m_flash_invert && (*attr & 0x80))
+ {
+ ink=((*attr)>>3) & 0x0f;
+ pap=((*attr) & 0x07) + (((*attr)>>3) & 0x08);
+ }
+ else
+ {
+ ink=((*attr) & 0x07) + (((*attr)>>3) & 0x08);
+ pap=((*attr)>>3) & 0x0f;
+ }
+
+ for (b=0x80;b!=0;b>>=1)
+ {
+ if (*scr&b)
+ {
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,ink);
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,ink);
+ }
+ else
+ {
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,pap);
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,pap);
+ }
+ }
+ scr++;
+ attr++;
+ }
+}
+
+/* Draw a scanline in TS2068/TC2048 64-column mode */
+static void ts2068_64col_scanline(running_machine &machine,bitmap_ind16 &bitmap, int y, int borderlines, unsigned short inkcolor)
+{
+ int x,b,scrx,scry;
+ unsigned char *scr1, *scr2;
+
+ scrx=TS2068_LEFT_BORDER;
+ scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0);
+
+ scr1=machine.device<ram_device>(RAM_TAG)->pointer() + y*32;
+ scr2=scr1 + 0x2000;
+
+ for (x=0;x<32;x++)
+ {
+ for (b=0x80;b!=0;b>>=1)
+ {
+ if (*scr1&b)
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,inkcolor);
+ else
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,7-inkcolor);
+ }
+ scr1++;
+
+ for (b=0x80;b!=0;b>>=1)
+ {
+ if (*scr2&b)
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,inkcolor);
+ else
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,7-inkcolor);
+ }
+ scr2++;
+ }
+}
+
+/* Draw a scanline in TS2068/TC2048 lores (normal Spectrum) mode */
+static void ts2068_lores_scanline(running_machine &machine,bitmap_ind16 &bitmap, int y, int borderlines, int screen)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ int x,b,scrx,scry;
+ unsigned short ink,pap;
+ unsigned char *attr, *scr;
+
+ scrx=TS2068_LEFT_BORDER;
+ scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0);
+
+ scr = machine.device<ram_device>(RAM_TAG)->pointer() + y*32 + screen*0x2000;
+ attr = machine.device<ram_device>(RAM_TAG)->pointer() + ((scry>>3)*32) + screen*0x2000 + 0x1800;
+
+ for (x=0;x<32;x++)
+ {
+ /* Get ink and paper colour with bright */
+ if (state->m_flash_invert && (*attr & 0x80))
+ {
+ ink=((*attr)>>3) & 0x0f;
+ pap=((*attr) & 0x07) + (((*attr)>>3) & 0x08);
+ }
+ else
+ {
+ ink=((*attr) & 0x07) + (((*attr)>>3) & 0x08);
+ pap=((*attr)>>3) & 0x0f;
+ }
+
+ for (b=0x80;b!=0;b>>=1)
+ {
+ if (*scr&b)
+ {
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,ink);
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,ink);
+ }
+ else
+ {
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,pap);
+ spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,pap);
+ }
+ }
+ scr++;
+ attr++;
+ }
+}
+
+SCREEN_UPDATE_IND16( ts2068 )
+{
+ /* for now TS2068 will do a full-refresh */
+ spectrum_state *state = screen.machine().driver_data<spectrum_state>();
+ int count;
+ int full_refresh = 1;
+
+ if ((state->m_port_ff_data & 7) == 6)
+ {
+ /* 64 Column mode */
+ unsigned short inkcolor = (state->m_port_ff_data & 0x38) >> 3;
+ for (count = 0; count < 192; count++)
+ ts2068_64col_scanline(screen.machine(),bitmap, count, TS2068_TOP_BORDER, inkcolor);
+ }
+ else if ((state->m_port_ff_data & 7) == 2)
+ {
+ /* Extended Color mode */
+ for (count = 0; count < 192; count++)
+ ts2068_hires_scanline(screen.machine(),bitmap, count, TS2068_TOP_BORDER);
+ }
+ else if ((state->m_port_ff_data & 7) == 1)
+ {
+ /* Screen 6000-7aff */
+ for (count = 0; count < 192; count++)
+ ts2068_lores_scanline(screen.machine(),bitmap, count, TS2068_TOP_BORDER, 1);
+ }
+ else
+ {
+ /* Screen 4000-5aff */
+ for (count = 0; count < 192; count++)
+ ts2068_lores_scanline(screen.machine(),bitmap, count, TS2068_TOP_BORDER, 0);
+ }
+
+ spectrum_border_draw(screen.machine(), bitmap, full_refresh,
+ TS2068_TOP_BORDER, SPEC_DISPLAY_YSIZE, TS2068_BOTTOM_BORDER,
+ TS2068_LEFT_BORDER, TS2068_DISPLAY_XSIZE, TS2068_RIGHT_BORDER,
+ SPEC_LEFT_BORDER_CYCLES, SPEC_DISPLAY_XSIZE_CYCLES,
+ SPEC_RIGHT_BORDER_CYCLES, SPEC_RETRACE_CYCLES, 200, 0xfe);
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( tc2048 )
+{
+ /* for now TS2068 will do a full-refresh */
+ spectrum_state *state = screen.machine().driver_data<spectrum_state>();
+ int count;
+ int full_refresh = 1;
+
+ if ((state->m_port_ff_data & 7) == 6)
+ {
+ /* 64 Column mode */
+ unsigned short inkcolor = (state->m_port_ff_data & 0x38) >> 3;
+ for (count = 0; count < 192; count++)
+ ts2068_64col_scanline(screen.machine(),bitmap, count, SPEC_TOP_BORDER, inkcolor);
+ }
+ else if ((state->m_port_ff_data & 7) == 2)
+ {
+ /* Extended Color mode */
+ for (count = 0; count < 192; count++)
+ ts2068_hires_scanline(screen.machine(),bitmap, count, SPEC_TOP_BORDER);
+ }
+ else if ((state->m_port_ff_data & 7) == 1)
+ {
+ /* Screen 6000-7aff */
+ for (count = 0; count < 192; count++)
+ ts2068_lores_scanline(screen.machine(),bitmap, count, SPEC_TOP_BORDER, 1);
+ }
+ else
+ {
+ /* Screen 4000-5aff */
+ for (count = 0; count < 192; count++)
+ ts2068_lores_scanline(screen.machine(),bitmap, count, SPEC_TOP_BORDER, 0);
+ }
+
+ spectrum_border_draw(screen.machine(), bitmap, full_refresh,
+ SPEC_TOP_BORDER, SPEC_DISPLAY_YSIZE, SPEC_BOTTOM_BORDER,
+ TS2068_LEFT_BORDER, TS2068_DISPLAY_XSIZE, TS2068_RIGHT_BORDER,
+ SPEC_LEFT_BORDER_CYCLES, SPEC_DISPLAY_XSIZE_CYCLES,
+ SPEC_RIGHT_BORDER_CYCLES, SPEC_RETRACE_CYCLES, 200, 0xfe);
+ return 0;
+}
diff --git a/src/mess/video/tmc1800.c b/src/mess/video/tmc1800.c
new file mode 100644
index 00000000000..f71a97689f7
--- /dev/null
+++ b/src/mess/video/tmc1800.c
@@ -0,0 +1,123 @@
+#include "emu.h"
+#include "includes/tmc1800.h"
+#include "cpu/cosmac/cosmac.h"
+#include "video/cdp1861.h"
+#include "sound/cdp1864.h"
+#include "machine/rescap.h"
+
+/* Telmac 1800 */
+
+static CDP1861_INTERFACE( tmc1800_cdp1861_intf )
+{
+ CDP1802_TAG,
+ SCREEN_TAG,
+ DEVCB_CPU_INPUT_LINE(CDP1802_TAG, COSMAC_INPUT_LINE_INT),
+ DEVCB_CPU_INPUT_LINE(CDP1802_TAG, COSMAC_INPUT_LINE_DMAOUT),
+ DEVCB_CPU_INPUT_LINE(CDP1802_TAG, COSMAC_INPUT_LINE_EF1)
+};
+
+/* Telmac 2000 */
+
+READ_LINE_MEMBER( tmc2000_state::rdata_r )
+{
+ return BIT(m_color, 2);
+}
+
+READ_LINE_MEMBER( tmc2000_state::bdata_r )
+{
+ return BIT(m_color, 1);
+}
+
+READ_LINE_MEMBER( tmc2000_state::gdata_r )
+{
+ return BIT(m_color, 0);
+}
+
+static CDP1864_INTERFACE( tmc2000_cdp1864_intf )
+{
+ CDP1802_TAG,
+ SCREEN_TAG,
+ CDP1864_INTERLACED,
+ DEVCB_DRIVER_LINE_MEMBER(tmc2000_state, rdata_r),
+ DEVCB_DRIVER_LINE_MEMBER(tmc2000_state, bdata_r),
+ DEVCB_DRIVER_LINE_MEMBER(tmc2000_state, gdata_r),
+ DEVCB_CPU_INPUT_LINE(CDP1802_TAG, COSMAC_INPUT_LINE_INT),
+ DEVCB_CPU_INPUT_LINE(CDP1802_TAG, COSMAC_INPUT_LINE_DMAOUT),
+ DEVCB_CPU_INPUT_LINE(CDP1802_TAG, COSMAC_INPUT_LINE_EF1),
+ DEVCB_NULL,
+ RES_K(1.21), // RL64
+ RES_K(2.05), // RL63
+ RES_K(2.26), // RL61
+ RES_K(3.92) // RL65 (also RH62 (2K pot) in series, but ignored here)
+};
+
+/* OSCOM Nano */
+
+static CDP1864_INTERFACE( nano_cdp1864_intf )
+{
+ CDP1802_TAG,
+ SCREEN_TAG,
+ CDP1864_INTERLACED,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_CPU_INPUT_LINE(CDP1802_TAG, COSMAC_INPUT_LINE_INT),
+ DEVCB_CPU_INPUT_LINE(CDP1802_TAG, COSMAC_INPUT_LINE_DMAOUT),
+ DEVCB_CPU_INPUT_LINE(CDP1802_TAG, COSMAC_INPUT_LINE_EF1),
+ DEVCB_NULL,
+ RES_K(1.21), // R18 unconfirmed
+ 0, // not connected
+ 0, // not connected
+ 0 // not connected
+};
+
+/* OSM-200 */
+
+UINT32 osc1000b_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ return 0;
+}
+
+/* Machine Drivers */
+
+MACHINE_CONFIG_FRAGMENT( tmc1800_video )
+ MCFG_CDP1861_SCREEN_ADD(CDP1861_TAG, SCREEN_TAG, XTAL_1_75MHz)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(black_and_white)
+
+ MCFG_CDP1861_ADD(CDP1861_TAG, XTAL_1_75MHz, tmc1800_cdp1861_intf)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( osc1000b_video )
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(osc1000b_state, screen_update)
+ MCFG_SCREEN_REFRESH_RATE(50)
+ MCFG_SCREEN_SIZE(320, 200)
+ MCFG_SCREEN_VISIBLE_AREA(0, 319, 0, 199)
+
+ MCFG_PALETTE_LENGTH(2)
+ MCFG_PALETTE_INIT(black_and_white)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( tmc2000_video )
+ MCFG_CDP1864_SCREEN_ADD(SCREEN_TAG, XTAL_1_75MHz)
+ MCFG_SCREEN_UPDATE_DEVICE(CDP1864_TAG, cdp1864_device, screen_update)
+
+ MCFG_PALETTE_LENGTH(8+8)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_CDP1864_ADD(CDP1864_TAG, XTAL_1_75MHz, tmc2000_cdp1864_intf)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( nano_video )
+ MCFG_CDP1864_SCREEN_ADD(SCREEN_TAG, XTAL_1_75MHz)
+ MCFG_SCREEN_UPDATE_DEVICE(CDP1864_TAG, cdp1864_device, screen_update)
+
+ MCFG_PALETTE_LENGTH(8+8)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_CDP1864_ADD(CDP1864_TAG, XTAL_1_75MHz, nano_cdp1864_intf)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/tmc600.c b/src/mess/video/tmc600.c
new file mode 100644
index 00000000000..0db03796f85
--- /dev/null
+++ b/src/mess/video/tmc600.c
@@ -0,0 +1,156 @@
+#include "emu.h"
+#include "sound/cdp1869.h"
+#include "includes/tmc600.h"
+
+WRITE8_MEMBER( tmc600_state::vismac_register_w )
+{
+ m_vismac_reg_latch = data;
+}
+
+WRITE8_MEMBER( tmc600_state::vismac_data_w )
+{
+ UINT16 ma = m_maincpu->get_memory_address();
+
+ switch (m_vismac_reg_latch)
+ {
+ case 0x20:
+ // character color latch
+ m_vismac_color_latch = data;
+ break;
+
+ case 0x30:
+ // background color latch
+ m_vismac_bkg_latch = data & 0x07;
+
+ m_vis->out3_w(space, ma, data);
+ break;
+
+ case 0x40:
+ m_vis->out4_w(space, ma, data);
+ break;
+
+ case 0x50:
+ m_vis->out5_w(space, ma, data);
+ break;
+
+ case 0x60:
+ m_vis->out6_w(space, ma, data);
+ break;
+
+ case 0x70:
+ m_vis->out7_w(space, ma, data);
+ break;
+ }
+}
+
+static TIMER_DEVICE_CALLBACK( blink_tick )
+{
+ tmc600_state *state = timer.machine().driver_data<tmc600_state>();
+
+ state->m_blink = !state->m_blink;
+}
+
+UINT8 tmc600_state::get_color(UINT16 pma)
+{
+ UINT16 pageaddr = pma & TMC600_PAGE_RAM_MASK;
+ UINT8 color = m_color_ram[pageaddr];
+
+ if (BIT(color, 3) && m_blink)
+ {
+ color = m_vismac_bkg_latch;
+ }
+
+ return color;
+}
+
+WRITE8_MEMBER( tmc600_state::page_ram_w )
+{
+ m_page_ram[offset] = data;
+ m_color_ram[offset] = m_vismac_color_latch;
+}
+
+static ADDRESS_MAP_START( cdp1869_page_ram, AS_0, 8, tmc600_state )
+ AM_RANGE(0x000, 0x3ff) AM_MIRROR(0x400) AM_RAM AM_SHARE("page_ram") AM_WRITE(page_ram_w)
+ADDRESS_MAP_END
+
+static CDP1869_CHAR_RAM_READ( tmc600_char_ram_r )
+{
+ tmc600_state *state = device->machine().driver_data<tmc600_state>();
+
+ UINT16 pageaddr = pma & TMC600_PAGE_RAM_MASK;
+ UINT8 color = state->get_color(pageaddr);
+ UINT16 charaddr = ((cma & 0x08) << 8) | (pmd << 3) | (cma & 0x07);
+ UINT8 cdb = state->m_char_rom[charaddr] & 0x3f;
+
+ int ccb0 = BIT(color, 2);
+ int ccb1 = BIT(color, 1);
+
+ return (ccb1 << 7) | (ccb0 << 6) | cdb;
+}
+
+static CDP1869_PCB_READ( tmc600_pcb_r )
+{
+ tmc600_state *state = device->machine().driver_data<tmc600_state>();
+
+ UINT16 pageaddr = pma & TMC600_PAGE_RAM_MASK;
+ UINT8 color = state->get_color(pageaddr);
+
+ return BIT(color, 0);
+}
+
+static CDP1869_INTERFACE( vis_intf )
+{
+ SCREEN_TAG,
+ CDP1869_COLOR_CLK_PAL,
+ CDP1869_PAL,
+ tmc600_pcb_r,
+ tmc600_char_ram_r,
+ NULL,
+ DEVCB_NULL // ?
+};
+
+void tmc600_state::video_start()
+{
+ // allocate memory
+ m_color_ram = auto_alloc_array(machine(), UINT8, TMC600_PAGE_RAM_SIZE);
+
+ // find memory regions
+ m_char_rom = memregion("chargen")->base();
+
+ // register for state saving
+ save_pointer(NAME(m_color_ram), TMC600_PAGE_RAM_SIZE);
+
+ save_item(NAME(m_vismac_reg_latch));
+ save_item(NAME(m_vismac_color_latch));
+ save_item(NAME(m_vismac_bkg_latch));
+ save_item(NAME(m_blink));
+}
+
+static const gfx_layout tmc600_charlayout =
+{
+ 6, 9, // 6 x 9 characters
+ 256, // 256 characters
+ 1, // 1 bits per pixel
+ { 0 }, // no bitplanes
+ // x offsets
+ { 2, 3, 4, 5, 6, 7 },
+ // y offsets
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 2048*8 },
+ 8*8 // every char takes 8 x 8 bytes
+};
+
+static GFXDECODE_START( tmc600 )
+ GFXDECODE_ENTRY( "chargen", 0x0000, tmc600_charlayout, 0, 36 )
+GFXDECODE_END
+
+MACHINE_CONFIG_FRAGMENT( tmc600_video )
+ // video hardware
+ MCFG_CDP1869_SCREEN_PAL_ADD(CDP1869_TAG, SCREEN_TAG, CDP1869_DOT_CLK_PAL)
+ MCFG_TIMER_ADD_PERIODIC("blink", blink_tick, attotime::from_hz(2))
+ MCFG_GFXDECODE(tmc600)
+
+ // sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_CDP1869_ADD(CDP1869_TAG, CDP1869_DOT_CLK_PAL, vis_intf, cdp1869_page_ram)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/tms3556.c b/src/mess/video/tms3556.c
new file mode 100644
index 00000000000..e7a0e10a8c0
--- /dev/null
+++ b/src/mess/video/tms3556.c
@@ -0,0 +1,584 @@
+/*
+ tms3556 emulation
+
+ TODO:
+ * implement remaining flags in control registers
+ * test the whole thing
+ * find the bloody tms3556 manual. I mean the register and VRAM interfaces
+ are mostly guesswork full of hacks, and I'd like to compare it with
+ documentation.
+
+ Raphael Nabet, 2004
+*/
+
+#include "emu.h"
+#include "tms3556.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type TMS3556 = &device_creator<tms3556_device>;
+
+
+// default address map
+static ADDRESS_MAP_START( tms3556, AS_0, 8, tms3556_device )
+ AM_RANGE(0x0000, 0xffff) AM_RAM
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *tms3556_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 tms3556_device::readbyte(offs_t address)
+{
+ return space()->read_byte(address);
+}
+
+
+//-------------------------------------------------
+// writebyte - write a byte at the given address
+//-------------------------------------------------
+
+inline void tms3556_device::writebyte(offs_t address, UINT8 data)
+{
+ space()->write_byte(address, data);
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// tms3556_device - constructor
+//-------------------------------------------------
+
+tms3556_device::tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, TMS3556, "Texas Instruments VDP TMS3556", tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(tms3556)),
+ m_write_ptr(0),
+ m_reg_ptr(0),
+ m_reg_access_phase(0),
+ m_magical_mystery_flag(0),
+ m_scanline(0)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ m_control_regs[i] = 0;
+ m_address_regs[i] = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void tms3556_device::device_start()
+{
+ // register for state saving
+ save_item(NAME(m_control_regs));
+ save_item(NAME(m_address_regs));
+ save_item(NAME(m_write_ptr));
+ save_item(NAME(m_reg_ptr));
+ save_item(NAME(m_reg_access_phase));
+ save_item(NAME(m_magical_mystery_flag));
+ save_item(NAME(m_scanline));
+ save_item(NAME(m_blink));
+ save_item(NAME(m_blink_count));
+ save_item(NAME(m_bg_color));
+ save_item(NAME(m_name_offset));
+ save_item(NAME(m_cg_flag));
+ save_item(NAME(m_char_line_counter));
+ save_item(NAME(m_dbl_h_phase));
+
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+}
+
+
+/*static const char *const tms3556_mode_names[] = { "DISPLAY OFF", "TEXT", "GRAPHIC", "MIXED" };*/
+
+
+UINT32 tms3556_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+
+//-------------------------------------------------
+// vram_r - VRAM read
+//-------------------------------------------------
+
+READ8_MEMBER( tms3556_device::vram_r )
+{
+ if (LOG) logerror("TMS3556 VRAM Read: %06x\n", offset);
+
+ if (m_magical_mystery_flag)
+ {
+ m_write_ptr = ((m_control_regs[2] << 8) | m_control_regs[1]) + 1;
+ m_magical_mystery_flag = 0;
+ }
+
+ return readbyte(m_address_regs[1]++);
+}
+
+//-------------------------------------------------
+// vram_w - VRAM write
+//-------------------------------------------------
+
+WRITE8_MEMBER( tms3556_device::vram_w )
+{
+ if (LOG) logerror("TMS3556 VRAM Write: %06x = %02x\n", offset, data);
+
+ if (m_magical_mystery_flag)
+ {
+ m_write_ptr = (m_control_regs[2] << 8) | m_control_regs[1];
+ m_magical_mystery_flag = 0;
+ }
+
+ writebyte(m_write_ptr++, data);
+}
+
+
+//-------------------------------------------------
+// reg_r - read from register port
+//-------------------------------------------------
+
+READ8_MEMBER( tms3556_device::reg_r )
+{
+ if (LOG) logerror("TMS3556 Reg Read: %06x\n", offset);
+
+ int reply = 0;
+
+ if (m_reg_ptr < 8)
+ {
+ reply = m_control_regs[m_reg_ptr];
+ m_reg_access_phase = 0;
+ }
+ else
+ {
+ // ???
+ }
+
+ return reply;
+}
+
+//-------------------------------------------------
+// reg_w - write to register port
+//-------------------------------------------------
+
+WRITE8_MEMBER( tms3556_device::reg_w )
+{
+ if (LOG) logerror("TMS3556 Reg Write: %06x = %02x\n", offset, data);
+
+ if ((m_reg_access_phase == 3) && (data))
+ m_reg_access_phase = 0; /* ???????????? */
+
+ switch (m_reg_access_phase)
+ {
+ case 0:
+ m_reg_ptr = data & 0x0f;
+ m_reg_access_phase = 1;
+ break;
+
+ case 1:
+ if (m_reg_ptr < 8)
+ {
+ m_control_regs[m_reg_ptr] = data;
+ m_reg_access_phase = 0;
+ if (m_reg_ptr == 2)
+ m_magical_mystery_flag = 1;
+ }
+ else if (m_reg_ptr == 9)
+ { /* I don't understand what is going on, but it is the only way to
+ get this to work */
+ m_address_regs[m_reg_ptr - 8] = ((m_control_regs[2] << 8) | m_control_regs[1]) + 1;
+ m_reg_access_phase = 0;
+ m_magical_mystery_flag = 0;
+ }
+ else
+ {
+ m_address_regs[m_reg_ptr - 8] = (m_control_regs[m_reg_ptr - 8] & 0xff00) | m_control_regs[1];
+ m_reg_access_phase = 2;
+ m_magical_mystery_flag = 0;
+ }
+ break;
+
+ case 2:
+ m_address_regs[m_reg_ptr - 8] = (m_control_regs[m_reg_ptr - 8] & 0x00ff) | (m_control_regs[2] << 8);
+ if ((m_reg_ptr <= 10) || (m_reg_ptr == 15))
+ m_address_regs[m_reg_ptr - 8]++;
+ else
+ m_address_regs[m_reg_ptr - 8] += 2;
+ m_reg_access_phase = 3;
+ break;
+
+ case 3:
+ m_reg_access_phase = 0;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// redraw code
+//-------------------------------------------------
+
+
+//-------------------------------------------------
+// draw_line_empty - draw an empty line (used for
+// top and bottom borders, and screen off mode)
+//-------------------------------------------------
+
+void tms3556_device::draw_line_empty(UINT16 *ln)
+{
+ int i;
+
+ for (i = 0; i < TMS3556_TOTAL_WIDTH; i++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+}
+
+
+//-------------------------------------------------
+// draw_line_text_common - draw a line of text
+// (called by draw_line_text and draw_line_mixed)
+//-------------------------------------------------
+
+void tms3556_device::draw_line_text_common(UINT16 *ln)
+{
+ int pattern, x, xx, i, name_offset;
+ UINT16 fg, bg;
+ offs_t nametbl_base;
+ offs_t patterntbl_base[4];
+ int name_hi, name_lo;
+ int pattern_ix;
+ int alphanumeric_mode, dbl_w, dbl_h, dbl_w_phase = 0;
+
+ nametbl_base = m_address_regs[2];
+ for (i = 0; i < 4; i++)
+ patterntbl_base[i] = m_address_regs[i + 3];
+
+ for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+
+ name_offset = m_name_offset;
+
+ for (x = 0; x < 40; x++)
+ {
+ name_hi = readbyte(nametbl_base + name_offset);
+ name_lo = readbyte(nametbl_base + name_offset + 1);
+ pattern_ix = ((name_hi >> 2) & 2) | ((name_hi >> 4) & 1);
+ alphanumeric_mode = (pattern_ix < 2) || ((pattern_ix == 3) && !(m_control_regs[7] & 0x08));
+ fg = (name_hi >> 5) & 0x7;
+ if (alphanumeric_mode)
+ {
+ if (name_hi & 4)
+ { /* inverted color */
+ bg = fg;
+ fg = m_bg_color;
+ }
+ else
+ bg = m_bg_color;
+ dbl_w = name_hi & 0x2;
+ dbl_h = name_hi & 0x1;
+ }
+ else
+ {
+ bg = name_hi & 0x7;
+ dbl_w = 0;
+ dbl_h = 0;
+ }
+ if ((name_lo & 0x80) && m_blink)
+ fg = bg; /* blink off time */
+ if (! dbl_h)
+ { /* single height */
+ pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * m_char_line_counter);
+ if (m_char_line_counter == 0)
+ m_dbl_h_phase[x] = 0;
+ }
+ else
+ { /* double height */
+ if (! m_dbl_h_phase[x])
+ /* first phase: pattern from upper half */
+ pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (5 + (m_char_line_counter >> 1)));
+ else
+ /* second phase: pattern from lower half */
+ pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (m_char_line_counter >> 1));
+ if (m_char_line_counter == 0)
+ m_dbl_h_phase[x] = !m_dbl_h_phase[x];
+ }
+ if (!dbl_w)
+ { /* single width */
+ for (xx = 0; xx < 8; xx++)
+ {
+ UINT16 color = (pattern & 0x80) ? fg : bg;
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = color;
+#endif
+ *ln++ = color;
+ pattern <<= 1;
+ }
+ dbl_w_phase = 0;
+ }
+ else
+ { /* double width */
+ if (dbl_w_phase)
+ /* second phase: display right half */
+ pattern <<= 4;
+ for (xx = 0; xx < 4; xx++)
+ {
+ UINT16 color = (pattern & 0x80) ? fg : bg;
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = color; *ln++ = color;
+#endif
+ *ln++ = color; *ln++ = color;
+ pattern <<= 1;
+ }
+ dbl_w_phase = !dbl_w_phase;
+ }
+ name_offset += 2;
+ }
+
+ for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+
+ if (m_char_line_counter == 0)
+ m_name_offset = name_offset;
+}
+
+
+//-------------------------------------------------
+// draw_line_bitmap_common - draw a line of bitmap
+// (called by draw_line_bitmap and draw_line_mixed)
+//-------------------------------------------------
+
+void tms3556_device::draw_line_bitmap_common(UINT16 *ln)
+{
+ int x, xx;
+ offs_t nametbl_base;
+ int name_b, name_g, name_r;
+
+ nametbl_base = m_address_regs[2];
+
+ for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+
+ for (x = 0; x < 40; x++)
+ {
+ name_b = readbyte(nametbl_base + m_name_offset);
+ name_g = readbyte(nametbl_base + m_name_offset + 1);
+ name_r = readbyte(nametbl_base + m_name_offset + 2);
+ for (xx = 0; xx < 8; xx++)
+ {
+ UINT16 color = ((name_b >> 5) & 0x4) | ((name_g >> 6) & 0x2) | ((name_r >> 7) & 0x1);
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = color;
+#endif
+ *ln++ = color;
+ name_b <<= 1;
+ name_g <<= 1;
+ name_r <<= 1;
+ }
+ m_name_offset += 3;
+ }
+
+ for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++)
+#if TMS3556_DOUBLE_WIDTH
+ *ln++ = m_bg_color;
+#endif
+ *ln++ = m_bg_color;
+}
+
+
+//-------------------------------------------------
+// draw_line_text - draw a line in text mode
+//-------------------------------------------------
+
+void tms3556_device::draw_line_text(UINT16 *ln)
+{
+ if (m_char_line_counter == 0)
+ m_char_line_counter = 10;
+ m_char_line_counter--;
+ draw_line_text_common(ln);
+}
+
+
+//-------------------------------------------------
+// draw_line_bitmap - draw a line in bitmap mode
+//-------------------------------------------------
+
+void tms3556_device::draw_line_bitmap(UINT16 *ln)
+{
+ draw_line_bitmap_common(ln);
+ m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7;
+ m_name_offset += 2;
+}
+
+
+//-------------------------------------------------
+// draw_line_mixed - draw a line in mixed mode
+//-------------------------------------------------
+
+void tms3556_device::draw_line_mixed(UINT16 *ln)
+{
+ if (m_cg_flag)
+ { /* bitmap line */
+ draw_line_bitmap_common(ln);
+ m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7;
+ m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1;
+ m_name_offset += 2;
+ }
+ else
+ { /* text line */
+ if (m_char_line_counter == 0)
+ m_char_line_counter = 10;
+ m_char_line_counter--;
+ draw_line_text_common(ln);
+ if (m_char_line_counter == 0)
+ {
+ m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7;
+ m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1;
+ m_name_offset += 2;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// draw_line - draw a line. If non-interlaced mode,
+// duplicate the line.
+//-------------------------------------------------
+
+void tms3556_device::draw_line(bitmap_ind16 &bmp, int line)
+{
+ int double_lines = 0;
+ UINT16 *ln, *ln2 = NULL;
+
+// if (m_control_regs[4] & 0x??)
+// { // interlaced mode
+// ln = &bmp->pix16(line, m_field);
+// }
+// else
+ { /* non-interlaced mode */
+ ln = &bmp.pix16(line);
+ ln2 = &bmp.pix16(line, 1);
+ double_lines = 1;
+ }
+
+ if ((line < TMS3556_TOP_BORDER) || (line >= (TMS3556_TOP_BORDER + 250)))
+ {
+ /* draw top and bottom borders */
+ draw_line_empty(ln);
+ }
+ else
+ {
+ /* draw useful area */
+ switch (m_control_regs[6] >> 6)
+ {
+ case TMS3556_MODE_OFF:
+ draw_line_empty(ln);
+ break;
+ case TMS3556_MODE_TEXT:
+ draw_line_text(ln);
+ break;
+ case TMS3556_MODE_BITMAP:
+ draw_line_bitmap(ln);
+ break;
+ case TMS3556_MODE_MIXED:
+ draw_line_mixed(ln);
+ break;
+ }
+ }
+
+ if (double_lines)
+ memcpy (ln2, ln, TMS3556_TOTAL_WIDTH * (TMS3556_DOUBLE_WIDTH ? 2 : 1) * 2);
+}
+
+
+//-------------------------------------------------
+// interrupt_start_vblank - Do vblank-time tasks
+//-------------------------------------------------
+
+void tms3556_device::interrupt_start_vblank(void)
+{
+ /* at every frame, vdp switches fields */
+ //m_field = !m_field;
+
+ /* color blinking */
+ if (m_blink_count)
+ m_blink_count--;
+ if (!m_blink_count)
+ {
+ m_blink = !m_blink;
+ m_blink_count = 60; /*no idea what the real value is*/
+ }
+ /* reset background color */
+ m_bg_color = (m_control_regs[7] >> 5) & 0x7;
+ /* reset name offset */
+ m_name_offset = 0;
+ /* reset character line counter */
+ m_char_line_counter = 0;
+ /* reset c/g flag */
+ m_cg_flag = 0;
+ /* reset double height phase flags */
+ memset(m_dbl_h_phase, 0, sizeof(m_dbl_h_phase));
+}
+
+
+//-------------------------------------------------
+// interrupt - scanline handler
+//-------------------------------------------------
+
+void tms3556_device::interrupt(running_machine &machine)
+{
+ /* check for start of vblank */
+ if (m_scanline == 310) /*no idea what the real value is*/
+ interrupt_start_vblank();
+
+ /* render the current line */
+ if ((m_scanline >= 0) && (m_scanline < TMS3556_TOTAL_HEIGHT))
+ {
+ //if (!video_skip_this_frame())
+ draw_line(m_bitmap, m_scanline);
+ }
+
+ if (++m_scanline == 313)
+ m_scanline = 0;
+}
diff --git a/src/mess/video/tms3556.h b/src/mess/video/tms3556.h
new file mode 100644
index 00000000000..1aa78b524e6
--- /dev/null
+++ b/src/mess/video/tms3556.h
@@ -0,0 +1,113 @@
+/***************************************************************************
+
+ Texas Instruments TMS3556 Video Display Processor
+
+ ***************************************************************************/
+
+
+#pragma once
+
+#ifndef __TMS3556_H__
+#define __TMS3556_H__
+
+///*************************************************************************
+// MACROS / CONSTANTS
+///*************************************************************************
+
+#define TMS3556_TOP_BORDER 1
+#define TMS3556_BOTTOM_BORDER 1
+#define TMS3556_LEFT_BORDER 8
+#define TMS3556_RIGHT_BORDER 8
+#define TMS3556_TOTAL_WIDTH (320 + TMS3556_LEFT_BORDER + TMS3556_RIGHT_BORDER)
+#define TMS3556_TOTAL_HEIGHT (250 + TMS3556_TOP_BORDER + TMS3556_BOTTOM_BORDER)
+
+/* if DOUBLE_WIDTH set, the horizontal resolution is doubled */
+#define TMS3556_DOUBLE_WIDTH 1
+
+#define TMS3556_MODE_OFF 0
+#define TMS3556_MODE_TEXT 1
+#define TMS3556_MODE_BITMAP 2
+#define TMS3556_MODE_MIXED 3
+
+
+///*************************************************************************
+// INTERFACE CONFIGURATION MACROS
+///*************************************************************************
+
+#define MCFG_TMS3556_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, TMS3556, 0) \
+
+
+///*************************************************************************
+// TYPE DEFINITIONS
+///*************************************************************************
+
+// ======================> tms3556_device
+
+class tms3556_device : public device_t,
+ public device_memory_interface
+{
+public:
+ // construction/destruction
+ tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( vram_r );
+ DECLARE_WRITE8_MEMBER( vram_w );
+ DECLARE_READ8_MEMBER( reg_r );
+ DECLARE_WRITE8_MEMBER( reg_w );
+
+ void interrupt(running_machine &machine);
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+
+ inline UINT8 readbyte(offs_t address);
+ inline void writebyte(offs_t address, UINT8 data);
+
+ void draw_line_empty(UINT16 *ln);
+ void draw_line_text_common(UINT16 *ln);
+ void draw_line_bitmap_common(UINT16 *ln);
+ void draw_line_text(UINT16 *ln);
+ void draw_line_bitmap(UINT16 *ln);
+ void draw_line_mixed(UINT16 *ln);
+ void draw_line(bitmap_ind16 &bmp, int line);
+ void interrupt_start_vblank(void);
+
+private:
+ // registers
+ UINT8 m_control_regs[8];
+ UINT16 m_address_regs[8];
+ UINT16 m_write_ptr;
+
+ // register interface
+ int m_reg_ptr;
+ int m_reg_access_phase;
+ int m_magical_mystery_flag;
+
+ int m_scanline; // scanline counter
+ int m_blink, m_blink_count; // blinking
+ int m_bg_color; // background color for current line
+ int m_name_offset; // current offset in name table
+ int m_cg_flag; // c/g flag (mixed mode only)
+ int m_char_line_counter; // character line counter (decrements from 10, 0 when we have reached
+ // last line of character row)
+ int m_dbl_h_phase[40]; // double height phase flags (one per horizontal character position)
+
+ bitmap_ind16 m_bitmap;
+};
+
+
+// device type definition
+extern const device_type TMS3556;
+
+
+#endif
diff --git a/src/mess/video/trs80.c b/src/mess/video/trs80.c
new file mode 100644
index 00000000000..2e7fa694a8d
--- /dev/null
+++ b/src/mess/video/trs80.c
@@ -0,0 +1,593 @@
+/***************************************************************************
+
+ trs80.c
+
+ Functions to emulate the video hardware of the TRS80.
+
+***************************************************************************/
+
+#include "includes/trs80.h"
+
+/* Bit assignment for "state->m_mode"
+ d7 Page select
+ d6 LNW80 switch to graphics ram
+ d5 LNW80 colour or monochrome (1=colour)
+ d4 LNW80 lores or hires (1=hires) also does 64 or 80 chars per line
+ d3 LNW80 invert entire screen / Model III/4 Invert characters with bit 7 set (1=invert)
+ d2 80/40 or 64/32 characters per line (1=80)
+ d1 7 or 8 bit video (1=requires 7-bit, 0=don't care)
+ d0 80/64 or 40/32 characters per line (1=32) */
+
+
+WRITE8_MEMBER( trs80_state::trs80m4_88_w )
+{
+/* This is for the programming of the CRTC registers.
+ However this CRTC is mask-programmed, and only the
+ start address register can be used. The cursor and
+ light-pen facilities are ignored. The character clock
+ is changed depending on the screen size chosen.
+ Therefore it is easier to use normal
+ coding rather than the mc6845 device. */
+
+ if (!offset) m_crtc_reg = data & 0x1f;
+
+ if (offset) switch (m_crtc_reg)
+ {
+ case 12:
+ m_start_address = (m_start_address & 0x00ff) | (data << 8);
+ break;
+ case 13:
+ m_start_address = (m_start_address & 0xff00) | data;
+ }
+}
+
+
+VIDEO_START( trs80 )
+{
+ trs80_state *state = machine.driver_data<trs80_state>();
+ state->m_p_chargen = state->memregion("chargen")->base();
+ state->m_size_store = 0xff;
+ state->m_mode &= 2;
+}
+
+
+/* 7 or 8-bit video, 32/64 characters per line = trs80, trs80l2, sys80 */
+SCREEN_UPDATE_IND16( trs80 )
+{
+ trs80_state *state = screen.machine().driver_data<trs80_state>();
+ UINT8 y,ra,chr,gfx,gfxbit;
+ UINT16 sy=0,ma=0,x;
+ UINT8 cols = BIT(state->m_mode, 0) ? 32 : 64;
+ UINT8 skip = BIT(state->m_mode, 0) ? 2 : 1;
+
+ if (state->m_mode != state->m_size_store)
+ {
+ state->m_size_store = state->m_mode & 1;
+ screen.set_visible_area(0, cols*6-1, 0, 16*12-1);
+ }
+
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 12; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 64; x+=skip)
+ {
+ chr = state->m_p_videoram[x];
+
+ if (chr & 0x80)
+ {
+ gfxbit = (ra & 0x0c)>>1;
+ /* Display one line of a lores character (6 pixels) */
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ gfxbit++;
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ }
+ else
+ {
+ if (BIT(state->m_mode, 1) & (chr < 32)) chr+=64;
+
+ // if g,j,p,q,y; lower the descender
+ if ((chr==0x2c)||(chr==0x3b)||(chr==0x67)||(chr==0x6a)||(chr==0x70)||(chr==0x71)||(chr==0x79))
+ {
+ if ((ra < 10) && (ra > 1))
+ gfx = state->m_p_chargen[(chr<<3) | (ra-2) ];
+ else
+ gfx = 0;
+ }
+ else
+ {
+ if (ra < 8)
+ gfx = state->m_p_chargen[(chr<<3) | ra ];
+ else
+ gfx = 0;
+ }
+
+ /* Display a scanline of a character (6 pixels) */
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ }
+ ma+=64;
+ }
+ return 0;
+}
+
+/* 8-bit video, 32/64/40/80 characters per line = trs80m3, trs80m4. */
+SCREEN_UPDATE_IND16( trs80m4 )
+{
+ trs80_state *state = screen.machine().driver_data<trs80_state>();
+ UINT8 y,ra,chr,gfx,gfxbit;
+ UINT16 sy=0,ma=0,x;
+ UINT8 skip=1;
+ UINT8 cols = BIT(state->m_mode, 2) ? 80 : 64;
+ UINT8 rows = BIT(state->m_mode, 2) ? 24 : 16;
+ UINT8 lines = BIT(state->m_mode, 2) ? 10 : 12;
+ UINT8 s_cols = cols;
+ UINT8 mask = BIT(state->m_mode, 5) ? 0xff : 0xbf; /* Select Japanese or extended chars */
+
+ if (state->m_mode & 1)
+ {
+ s_cols >>= 1;
+ skip = 2;
+ }
+
+ if ((state->m_mode & 0x7f) != state->m_size_store)
+ {
+ state->m_size_store = state->m_mode & 5;
+ screen.set_visible_area(0, s_cols*8-1, 0, rows*lines-1);
+ }
+
+ for (y = 0; y < rows; y++)
+ {
+ for (ra = 0; ra < lines; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + cols; x+=skip)
+ {
+ chr = state->m_p_videoram[x+state->m_start_address];
+
+ if (((chr & 0xc0) == 0xc0) && (~state->m_mode & 8))
+ {
+ if (ra < 8)
+ gfx = state->m_p_chargen[((chr&mask)<<3) | ra ];
+ else
+ gfx = 0;
+
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ else
+ if ((chr & 0x80) && (~state->m_mode & 8))
+ {
+ gfxbit = (ra & 0x0c)>>1;
+ /* Display one line of a lores character */
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ gfxbit++;
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ }
+ else
+ {
+ /* get pattern of pixels for that character scanline */
+ if (ra < 8)
+ gfx = state->m_p_chargen[((chr&0x7f)<<3) | ra ];
+ else
+ gfx = 0;
+
+ /* if inverse mode, and bit 7 set, invert gfx */
+ if (BIT(state->m_mode, 3) & BIT(chr, 7))
+ gfx ^= 0xff;
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ }
+ ma+=cols;
+ }
+ return 0;
+}
+
+/* 7 or 8-bit video, 64/32 characters per line = ht1080z, ht1080z2, ht108064 */
+SCREEN_UPDATE_IND16( ht1080z )
+{
+ trs80_state *state = screen.machine().driver_data<trs80_state>();
+ UINT8 y,ra,chr,gfx,gfxbit;
+ UINT16 sy=0,ma=0,x;
+ UINT8 cols = BIT(state->m_mode, 0) ? 32 : 64;
+ UINT8 skip = BIT(state->m_mode, 0) ? 2 : 1;
+
+ if (state->m_mode != state->m_size_store)
+ {
+ state->m_size_store = state->m_mode & 1;
+ screen.set_visible_area(0, cols*6-1, 0, 16*12-1);
+ }
+
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 12; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 64; x+=skip)
+ {
+ chr = state->m_p_videoram[x];
+
+ if (chr & 0x80)
+ {
+ gfxbit = (ra & 0x0c)>>1;
+ /* Display one line of a lores character (6 pixels) */
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ gfxbit++;
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ *p++ = BIT(chr, gfxbit);
+ }
+ else
+ {
+ if ((state->m_mode & 2) && (chr < 32)) chr+=64;
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[(chr<<4) | ra ];
+
+ /* Display a scanline of a character (6 pixels) */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = 0; /* fix for ht108064 */
+ }
+ }
+ }
+ ma+=64;
+ }
+ return 0;
+}
+
+/* 8-bit video, 64/80 characters per line = lnw80 */
+SCREEN_UPDATE_IND16( lnw80 )
+{
+ trs80_state *state = screen.machine().driver_data<trs80_state>();
+ static const UINT16 rows[] = { 0, 0x200, 0x100, 0x300, 1, 0x201, 0x101, 0x301 };
+ UINT8 chr,gfx,gfxbit,bg=7,fg=0;
+ UINT16 sy=0,ma=0,x,y,ra;
+ UINT8 cols = BIT(state->m_mode, 4) ? 80 : 64;
+
+ /* Although the OS can select 32-character mode, it is not supported by hardware */
+ if (state->m_mode != state->m_size_store)
+ {
+ state->m_size_store = state->m_mode & 0x10;
+ screen.set_visible_area(0, cols*6-1, 0, 16*12-1);
+ }
+
+ if (state->m_mode & 8)
+ {
+ bg = 0;
+ fg = 7;
+ }
+
+ switch (state->m_mode & 0x30)
+ {
+ case 0: // MODE 0
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 12; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 64; x++)
+ {
+ chr = state->m_p_videoram[x];
+
+ if (chr & 0x80)
+ {
+ gfxbit = (ra & 0x0c)>>1;
+ /* Display one line of a lores character (6 pixels) */
+ *p++ = BIT(chr, gfxbit) ? fg : bg;
+ *p++ = BIT(chr, gfxbit) ? fg : bg;
+ *p++ = BIT(chr, gfxbit) ? fg : bg;
+ gfxbit++;
+ *p++ = BIT(chr, gfxbit) ? fg : bg;
+ *p++ = BIT(chr, gfxbit) ? fg : bg;
+ *p++ = BIT(chr, gfxbit) ? fg : bg;
+ }
+ else
+ {
+ /* get pattern of pixels for that character scanline */
+ if (ra < 8)
+ gfx = state->m_p_chargen[(chr<<1) | rows[ra] ];
+ else
+ gfx = 0;
+
+ /* Display a scanline of a character (6 pixels) */
+ *p++ = BIT(gfx, 2) ? fg : bg;
+ *p++ = BIT(gfx, 1) ? fg : bg;
+ *p++ = BIT(gfx, 6) ? fg : bg;
+ *p++ = BIT(gfx, 7) ? fg : bg;
+ *p++ = BIT(gfx, 5) ? fg : bg;
+ *p++ = BIT(gfx, 3) ? fg : bg;
+ }
+ }
+ }
+ ma+=64;
+ }
+ break;
+
+ case 0x10: // MODE 1
+ for (y = 0; y < 0x400; y+=0x40)
+ {
+ for (ra = 0; ra < 0x3000; ra+=0x400)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = 0; x < 0x40; x++)
+ {
+ gfx = state->m_p_gfxram[ y | x | ra];
+ /* Display 6 pixels in normal region */
+ *p++ = BIT(gfx, 0) ? fg : bg;
+ *p++ = BIT(gfx, 1) ? fg : bg;
+ *p++ = BIT(gfx, 2) ? fg : bg;
+ *p++ = BIT(gfx, 3) ? fg : bg;
+ *p++ = BIT(gfx, 4) ? fg : bg;
+ *p++ = BIT(gfx, 5) ? fg : bg;
+ }
+
+ for (x = 0; x < 0x10; x++)
+ {
+ gfx = state->m_p_gfxram[ 0x3000 | x | (ra & 0xc00) | ((ra & 0x3000) >> 8)];
+ /* Display 6 pixels in extended region */
+ *p++ = BIT(gfx, 0) ? fg : bg;
+ *p++ = BIT(gfx, 1) ? fg : bg;
+ *p++ = BIT(gfx, 2) ? fg : bg;
+ *p++ = BIT(gfx, 3) ? fg : bg;
+ *p++ = BIT(gfx, 4) ? fg : bg;
+ *p++ = BIT(gfx, 5) ? fg : bg;
+ }
+ }
+ }
+ break;
+
+ case 0x20: // MODE 2
+ /* it seems the text video ram can have an effect in this mode,
+ not explained clearly, so not emulated */
+ for (y = 0; y < 0x400; y+=0x40)
+ {
+ for (ra = 0; ra < 0x3000; ra+=0x400)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = 0; x < 0x40; x++)
+ {
+ gfx = state->m_p_gfxram[ y | x | ra];
+ /* Display 6 pixels in normal region */
+ fg = (gfx & 0x38) >> 3;
+ *p++ = fg;
+ *p++ = fg;
+ *p++ = fg;
+ fg = gfx & 0x07;
+ *p++ = fg;
+ *p++ = fg;
+ *p++ = fg;
+ }
+ }
+ }
+ break;
+
+ case 0x30: // MODE 3
+ /* the manual does not explain at all how colour is determined
+ for the extended area. Further, the background colour
+ is not mentioned anywhere. Black is assumed. */
+ for (y = 0; y < 0x400; y+=0x40)
+ {
+ for (ra = 0; ra < 0x3000; ra+=0x400)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = 0; x < 0x40; x++)
+ {
+ gfx = state->m_p_gfxram[ y | x | ra];
+ fg = (state->m_p_videoram[ 0x3c00 | x | y ] & 0x38) >> 3;
+ /* Display 6 pixels in normal region */
+ *p++ = BIT(gfx, 0) ? fg : bg;
+ *p++ = BIT(gfx, 1) ? fg : bg;
+ *p++ = BIT(gfx, 2) ? fg : bg;
+ fg = state->m_p_videoram[ 0x3c00 | x | y ] & 0x07;
+ *p++ = BIT(gfx, 3) ? fg : bg;
+ *p++ = BIT(gfx, 4) ? fg : bg;
+ *p++ = BIT(gfx, 5) ? fg : bg;
+ }
+
+ for (x = 0; x < 0x10; x++)
+ {
+ gfx = state->m_p_gfxram[ 0x3000 | x | (ra & 0xc00) | ((ra & 0x3000) >> 8)];
+ fg = (state->m_p_gfxram[ 0x3c00 | x | y ] & 0x38) >> 3;
+ /* Display 6 pixels in extended region */
+ *p++ = BIT(gfx, 0) ? fg : bg;
+ *p++ = BIT(gfx, 1) ? fg : bg;
+ *p++ = BIT(gfx, 2) ? fg : bg;
+ fg = state->m_p_gfxram[ 0x3c00 | x | y ] & 0x07;
+ *p++ = BIT(gfx, 3) ? fg : bg;
+ *p++ = BIT(gfx, 4) ? fg : bg;
+ *p++ = BIT(gfx, 5) ? fg : bg;
+ }
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+/* lores characters are in the character generator. Each character is 8x16. */
+SCREEN_UPDATE_IND16( radionic )
+{
+ trs80_state *state = screen.machine().driver_data<trs80_state>();
+ UINT8 y,ra,chr,gfx;
+ UINT16 sy=0,ma=0,x;
+ UINT8 cols = BIT(state->m_mode, 0) ? 32 : 64;
+ UINT8 skip = BIT(state->m_mode, 0) ? 2 : 1;
+
+ if (state->m_mode != state->m_size_store)
+ {
+ state->m_size_store = state->m_mode & 1;
+ screen.set_visible_area(0, cols*8-1, 0, 16*16-1);
+ }
+
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 16; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 64; x+=skip)
+ {
+ chr = state->m_p_videoram[x];
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[(chr<<3) | (ra & 7) | (ra & 8) << 8];
+
+ /* Display a scanline of a character (8 pixels) */
+ *p++ = BIT(gfx, 0);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 7);
+ }
+ }
+ ma+=64;
+ }
+ return 0;
+}
+
+SCREEN_UPDATE_IND16( meritum )
+/* lores characters are in the character generator. Each character is 6x11. */
+{
+ trs80_state *state = screen.machine().driver_data<trs80_state>();
+ UINT8 y,ra,chr,gfx;
+ UINT16 sy=0,ma=0,x;
+ UINT8 cols = BIT(state->m_mode, 0) ? 32 : 64;
+ UINT8 skip = BIT(state->m_mode, 0) ? 2 : 1;
+
+ if (state->m_mode != state->m_size_store)
+ {
+ state->m_size_store = state->m_mode;
+ screen.set_visible_area(0, cols*6-1, 0, 16*11-1);
+ }
+
+ for (y = 0; y < 16; y++)
+ {
+ for (ra = 0; ra < 11; ra++)
+ {
+ UINT16 *p = &bitmap.pix16(sy++);
+
+ for (x = ma; x < ma + 64; x+=skip)
+ {
+ chr = state->m_p_videoram[x];
+
+ /* get pattern of pixels for that character scanline */
+ gfx = state->m_p_chargen[(chr<<4) | ra];
+
+ /* Display a scanline of a character (6 pixels) */
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
+ }
+ }
+ ma+=64;
+ }
+ return 0;
+}
+
+
+
+/***************************************************************************
+ Write to video ram
+***************************************************************************/
+
+READ8_MEMBER( trs80_state::trs80_videoram_r )
+{
+ if ((m_mode & 0x80) && (~m_model4 & 1)) offset |= 0x400;
+ return m_p_videoram[offset];
+}
+
+WRITE8_MEMBER( trs80_state::trs80_videoram_w )
+{
+ if ((m_mode & 0x80) && (~m_model4 & 1)) offset |= 0x400;
+ m_p_videoram[offset] = data;
+}
+
+
+/***************************************************************************
+ Write to graphics ram
+***************************************************************************/
+
+READ8_MEMBER( trs80_state::trs80_gfxram_r )
+{
+ return m_p_gfxram[offset];
+}
+
+WRITE8_MEMBER( trs80_state::trs80_gfxram_w )
+{
+ m_p_gfxram[offset] = data;
+}
+
+
+/***************************************************************************
+ Palettes
+***************************************************************************/
+
+/* Levels are unknown - guessing */
+static const rgb_t lnw80_palette[] =
+{
+ MAKE_RGB(220, 220, 220), // white
+ MAKE_RGB(0, 175, 0), // green
+ MAKE_RGB(200, 200, 0), // yellow
+ MAKE_RGB(255, 0, 0), // red
+ MAKE_RGB(255, 0, 255), // magenta
+ MAKE_RGB(0, 0, 175), // blue
+ MAKE_RGB(0, 255, 255), // cyan
+ MAKE_RGB(0, 0, 0), // black
+};
+
+PALETTE_INIT( lnw80 )
+{
+ palette_set_colors(machine, 0, lnw80_palette, ARRAY_LENGTH(lnw80_palette));
+}
diff --git a/src/mess/video/tx0.c b/src/mess/video/tx0.c
new file mode 100644
index 00000000000..750893aec91
--- /dev/null
+++ b/src/mess/video/tx0.c
@@ -0,0 +1,484 @@
+/*
+ TX-0
+
+ Raphael Nabet, 2004
+*/
+
+#include "emu.h"
+
+#include "cpu/pdp1/tx0.h"
+#include "includes/tx0.h"
+#include "video/crt.h"
+
+
+
+
+INLINE void tx0_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = color;
+}
+
+
+static void tx0_draw_panel_backdrop(running_machine &machine, bitmap_ind16 &bitmap);
+static void tx0_draw_panel(running_machine &machine, bitmap_ind16 &bitmap);
+
+
+
+/*
+ video init
+*/
+VIDEO_START( tx0 )
+{
+ tx0_state *state = machine.driver_data<tx0_state>();
+ state->m_typewriter_color = color_typewriter_black;
+
+ /* alloc bitmaps for our private fun */
+ state->m_panel_bitmap.allocate(panel_window_width, panel_window_height, BITMAP_FORMAT_IND16);
+ state->m_typewriter_bitmap.allocate(typewriter_window_width, typewriter_window_height, BITMAP_FORMAT_IND16);
+
+ /* set up out bitmaps */
+ tx0_draw_panel_backdrop(machine, state->m_panel_bitmap);
+
+ const rectangle typewriter_bitmap_bounds(0, typewriter_window_width-1, 0, typewriter_window_height-1);
+ state->m_typewriter_bitmap.fill(pen_typewriter_bg, typewriter_bitmap_bounds);
+
+ state->m_crt = machine.device("crt");
+}
+
+
+SCREEN_VBLANK( tx0 )
+{
+ // rising edge
+ if (vblank_on)
+ {
+ tx0_state *state = screen.machine().driver_data<tx0_state>();
+
+ crt_eof(state->m_crt);
+ }
+}
+
+
+/*
+ schedule a pixel to be plotted
+*/
+void tx0_plot(running_machine &machine, int x, int y)
+{
+ tx0_state *state = machine.driver_data<tx0_state>();
+
+ /* compute pixel coordinates and plot */
+ x = x*crt_window_width/0777;
+ y = y*crt_window_height/0777;
+ crt_plot(state->m_crt, x, y);
+}
+
+
+/*
+ SCREEN_UPDATE_IND16( tx0 ): effectively redraw the screen
+*/
+SCREEN_UPDATE_IND16( tx0 )
+{
+ tx0_state *state = screen.machine().driver_data<tx0_state>();
+ crt_update(state->m_crt, bitmap);
+
+ tx0_draw_panel(screen.machine(), state->m_panel_bitmap);
+ copybitmap(bitmap, state->m_panel_bitmap, 0, 0, panel_window_offset_x, panel_window_offset_y, cliprect);
+
+ copybitmap(bitmap, state->m_typewriter_bitmap, 0, 0, typewriter_window_offset_x, typewriter_window_offset_y, cliprect);
+ return 0;
+}
+
+
+
+/*
+ Operator control panel code
+*/
+
+enum
+{
+ x_panel_col1a_offset = 0,
+ x_panel_col1b_offset = 24,
+ x_panel_col2_offset = x_panel_col1a_offset+184+8
+};
+
+enum
+{
+ /* column 1: registers, test accumulator, test buffer, toggle switch storage */
+ y_panel_pc_offset = 0,
+ y_panel_mar_offset = y_panel_pc_offset+2*8,
+ y_panel_mbr_offset = y_panel_mar_offset+2*8,
+ y_panel_ac_offset = y_panel_mbr_offset+2*8,
+ y_panel_lr_offset = y_panel_ac_offset+2*8,
+ y_panel_xr_offset = y_panel_lr_offset+2*8,
+ y_panel_tbr_offset = y_panel_xr_offset+2*8,
+ y_panel_tac_offset = y_panel_tbr_offset+2*8,
+ y_panel_tss_offset = y_panel_tac_offset+2*8,
+
+ /* column 2: stop c0, stop c1, cm sel, 1-bit indicators, instr, flags */
+ y_panel_stop_c0_offset = 8,
+ y_panel_stop_c1_offset = y_panel_stop_c0_offset+8,
+ y_panel_gbl_cm_sel_offset = y_panel_stop_c1_offset+8,
+ y_panel_run_offset = y_panel_gbl_cm_sel_offset+8,
+ y_panel_cycle1_offset = y_panel_run_offset+8,
+ y_panel_cycle2_offset = y_panel_cycle1_offset+8,
+ y_panel_rim_offset = y_panel_cycle2_offset+8,
+ y_panel_ioh_offset = y_panel_rim_offset+8,
+ y_panel_ios_offset = y_panel_ioh_offset+8,
+ y_panel_ir_offset = y_panel_ios_offset+8,
+ y_panel_pf_offset = y_panel_ir_offset+2*8
+};
+
+/* draw a small 8*8 LED (or is this a lamp? ) */
+static void tx0_draw_led(running_machine &machine, bitmap_ind16 &bitmap, int x, int y, int state)
+{
+ int xx, yy;
+
+ for (yy=1; yy<7; yy++)
+ for (xx=1; xx<7; xx++)
+ tx0_plot_pixel(bitmap, x+xx, y+yy, state ? pen_lit_lamp : pen_unlit_lamp);
+}
+
+/* draw nb_bits leds which represent nb_bits bits in value */
+static void tx0_draw_multipleled(running_machine &machine, bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits)
+{
+ while (nb_bits)
+ {
+ nb_bits--;
+
+ tx0_draw_led(machine, bitmap, x, y, (value >> nb_bits) & 1);
+
+ x += 8;
+ }
+}
+
+
+/* draw a small 8*8 switch */
+static void tx0_draw_switch(running_machine &machine, bitmap_ind16 &bitmap, int x, int y, int state)
+{
+ int xx, yy;
+ int i;
+
+ /* erase area */
+ for (yy=0; yy<8; yy++)
+ for (xx=0; xx<8; xx++)
+ tx0_plot_pixel(bitmap, x+xx, y+yy, pen_panel_bg);
+
+
+ /* draw nut (-> circle) */
+ for (i=0; i<4;i++)
+ {
+ tx0_plot_pixel(bitmap, x+2+i, y+1, pen_switch_nut);
+ tx0_plot_pixel(bitmap, x+2+i, y+6, pen_switch_nut);
+ tx0_plot_pixel(bitmap, x+1, y+2+i, pen_switch_nut);
+ tx0_plot_pixel(bitmap, x+6, y+2+i, pen_switch_nut);
+ }
+ tx0_plot_pixel(bitmap, x+2, y+2, pen_switch_nut);
+ tx0_plot_pixel(bitmap, x+5, y+2, pen_switch_nut);
+ tx0_plot_pixel(bitmap, x+2, y+5, pen_switch_nut);
+ tx0_plot_pixel(bitmap, x+5, y+5, pen_switch_nut);
+
+ /* draw button (->disc) */
+ if (! state)
+ y += 4;
+ for (i=0; i<2;i++)
+ {
+ tx0_plot_pixel(bitmap, x+3+i, y, pen_switch_button);
+ tx0_plot_pixel(bitmap, x+3+i, y+3, pen_switch_button);
+ }
+ for (i=0; i<4;i++)
+ {
+ tx0_plot_pixel(bitmap, x+2+i, y+1, pen_switch_button);
+ tx0_plot_pixel(bitmap, x+2+i, y+2, pen_switch_button);
+ }
+}
+
+
+/* draw nb_bits switches which represent nb_bits bits in value */
+static void tx0_draw_multipleswitch(running_machine &machine, bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits)
+{
+ while (nb_bits)
+ {
+ nb_bits--;
+
+ tx0_draw_switch(machine, bitmap, x, y, (value >> nb_bits) & 1);
+
+ x += 8;
+ }
+}
+
+
+/* write a single char on screen */
+static void tx0_draw_char(running_machine &machine, bitmap_ind16 &bitmap, char character, int x, int y, int color)
+{
+ drawgfx_transpen(bitmap, bitmap.cliprect(), machine.gfx[0], character-32, color, 0, 0,
+ x+1, y, 0);
+}
+
+/* write a string on screen */
+static void tx0_draw_string(running_machine &machine, bitmap_ind16 &bitmap, const char *buf, int x, int y, int color)
+{
+ while (* buf)
+ {
+ tx0_draw_char(machine, bitmap, *buf, x, y, color);
+
+ x += 8;
+ buf++;
+ }
+}
+
+
+/* draw a vertical line */
+static void tx0_draw_vline(bitmap_ind16 &bitmap, int x, int y, int height, int color)
+{
+ while (height--)
+ tx0_plot_pixel(bitmap, x, y++, color);
+}
+
+#ifdef UNUSED_FUNCTION
+/* draw a horizontal line */
+static void tx0_draw_hline(bitmap_ind16 &bitmap, int x, int y, int width, int color)
+{
+ while (width--)
+ tx0_plot_pixel(bitmap, x++, y, color);
+}
+#endif
+
+/*
+ draw the operator control panel (fixed backdrop)
+*/
+static void tx0_draw_panel_backdrop(running_machine &machine, bitmap_ind16 &bitmap)
+{
+ tx0_state *state = machine.driver_data<tx0_state>();
+ int i;
+ char buf[3];
+
+ /* fill with black */
+ const rectangle panel_bitmap_bounds(0, panel_window_width-1, 0, panel_window_height-1);
+ state->m_panel_bitmap.fill(pen_panel_bg, panel_bitmap_bounds);
+
+ /* column 1: registers, test accumulator, test buffer, toggle switch storage */
+ tx0_draw_string(machine, bitmap, "program counter", x_panel_col1b_offset, y_panel_pc_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "memory address reg.", x_panel_col1b_offset, y_panel_mar_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "memory buffer reg.", x_panel_col1b_offset, y_panel_mbr_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "accumulator", x_panel_col1b_offset, y_panel_ac_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "live register", x_panel_col1b_offset, y_panel_lr_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "index register", x_panel_col1b_offset, y_panel_xr_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "TBR", x_panel_col1b_offset, y_panel_tbr_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "TAC", x_panel_col1b_offset, y_panel_tac_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "cm", x_panel_col1a_offset+8, y_panel_tss_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "TSS", x_panel_col1a_offset+24, y_panel_tss_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "lr", x_panel_col1a_offset+168, y_panel_tss_offset, color_panel_caption);
+ for (i=0; i<16; i++)
+ {
+ sprintf(buf, "%2o", i);
+ tx0_draw_string(machine, bitmap, buf, x_panel_col1a_offset, y_panel_tss_offset+8+i*8, color_panel_caption);
+ }
+
+ /* column separator */
+ tx0_draw_vline(bitmap, x_panel_col2_offset-4, 8, 248, pen_panel_caption);
+
+ /* column 2: stop c0, stop c1, cm sel, 1-bit indicators, instr, flags */
+ tx0_draw_string(machine, bitmap, "stop c0", x_panel_col2_offset+8, y_panel_stop_c0_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "stop c1", x_panel_col2_offset+8, y_panel_stop_c1_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "cm select", x_panel_col2_offset+8, y_panel_gbl_cm_sel_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "run", x_panel_col2_offset+8, y_panel_run_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "cycle1", x_panel_col2_offset+8, y_panel_cycle1_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "cycle2", x_panel_col2_offset+8, y_panel_cycle2_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "read in", x_panel_col2_offset+8, y_panel_rim_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "i-o halt", x_panel_col2_offset+8, y_panel_ioh_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "i-o sync", x_panel_col2_offset+8, y_panel_ios_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "instr", x_panel_col2_offset+8, y_panel_ir_offset, color_panel_caption);
+ tx0_draw_string(machine, bitmap, "pgm flags", x_panel_col2_offset+8, y_panel_pf_offset, color_panel_caption);
+}
+
+
+/*
+ draw the operator control panel (dynamic elements)
+*/
+static void tx0_draw_panel(running_machine &machine, bitmap_ind16 &bitmap)
+{
+ int cm_sel, lr_sel;
+ int i;
+
+ /* column 1: registers, test accumulator, test buffer, toggle switch storage */
+ tx0_draw_multipleled(machine, bitmap, x_panel_col1b_offset+2*8, y_panel_pc_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_PC), 16);
+ tx0_draw_multipleled(machine, bitmap, x_panel_col1b_offset+2*8, y_panel_mar_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_MAR), 16);
+ tx0_draw_multipleled(machine, bitmap, x_panel_col1b_offset, y_panel_mbr_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_MBR), 18);
+ tx0_draw_multipleled(machine, bitmap, x_panel_col1b_offset, y_panel_ac_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_AC), 18);
+ tx0_draw_multipleled(machine, bitmap, x_panel_col1b_offset, y_panel_lr_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_LR), 18);
+ tx0_draw_multipleled(machine, bitmap, x_panel_col1b_offset+4*8, y_panel_xr_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_XR), 14);
+ tx0_draw_multipleswitch(machine, bitmap, x_panel_col1b_offset, y_panel_tbr_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_TBR), 18);
+ tx0_draw_multipleswitch(machine, bitmap, x_panel_col1b_offset, y_panel_tac_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_TAC), 18);
+ cm_sel = cpu_get_reg(machine.device("maincpu"), TX0_CM_SEL);
+ lr_sel = cpu_get_reg(machine.device("maincpu"), TX0_LR_SEL);
+ for (i=0; i<16; i++)
+ {
+ tx0_draw_switch(machine, bitmap, x_panel_col1a_offset+16, y_panel_tss_offset+8+i*8, (cm_sel >> i) & 1);
+ tx0_draw_multipleswitch(machine, bitmap, x_panel_col1a_offset+24, y_panel_tss_offset+8+i*8, cpu_get_reg(machine.device("maincpu"), TX0_TSS00+i), 18);
+ tx0_draw_switch(machine, bitmap, x_panel_col1a_offset+168, y_panel_tss_offset+8+i*8, (lr_sel >> i) & 1);
+ }
+
+ /* column 2: stop c0, stop c1, cm sel, 1-bit indicators, instr, flags */
+ tx0_draw_switch(machine, bitmap, x_panel_col2_offset, y_panel_stop_c0_offset, cpu_get_reg(machine.device("maincpu"), TX0_STOP_CYC0));
+ tx0_draw_switch(machine, bitmap, x_panel_col2_offset, y_panel_stop_c1_offset, cpu_get_reg(machine.device("maincpu"), TX0_STOP_CYC1));
+ tx0_draw_switch(machine, bitmap, x_panel_col2_offset, y_panel_gbl_cm_sel_offset, cpu_get_reg(machine.device("maincpu"), TX0_GBL_CM_SEL));
+ tx0_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_run_offset, cpu_get_reg(machine.device("maincpu"), TX0_RUN));
+ tx0_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_cycle1_offset, cpu_get_reg(machine.device("maincpu"), TX0_CYCLE) & 1);
+ tx0_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_cycle2_offset, cpu_get_reg(machine.device("maincpu"), TX0_CYCLE) & 2);
+ tx0_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_rim_offset, cpu_get_reg(machine.device("maincpu"), TX0_RIM));
+ tx0_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_ioh_offset, cpu_get_reg(machine.device("maincpu"), TX0_IOH));
+ tx0_draw_led(machine, bitmap, x_panel_col2_offset, y_panel_ios_offset, cpu_get_reg(machine.device("maincpu"), TX0_IOS));
+ tx0_draw_multipleled(machine, bitmap, x_panel_col2_offset, y_panel_ir_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_IR), 5);
+ tx0_draw_multipleled(machine, bitmap, x_panel_col2_offset, y_panel_pf_offset+8, cpu_get_reg(machine.device("maincpu"), TX0_PF), 6);
+}
+
+
+
+/*
+ Typewriter code
+*/
+
+
+
+
+
+enum
+{
+ typewriter_line_height = 8,
+ typewriter_write_offset_y = typewriter_window_height-typewriter_line_height,
+ typewriter_scroll_step = typewriter_line_height
+};
+
+enum
+{
+ tab_step = 8
+};
+
+
+static void tx0_typewriter_linefeed(running_machine &machine)
+{
+ tx0_state *state = machine.driver_data<tx0_state>();
+ UINT8 buf[typewriter_window_width];
+ int y;
+
+ for (y=0; y<typewriter_window_height-typewriter_scroll_step; y++)
+ {
+ extract_scanline8(state->m_typewriter_bitmap, 0, y+typewriter_scroll_step, typewriter_window_width, buf);
+ draw_scanline8(state->m_typewriter_bitmap, 0, y, typewriter_window_width, buf, machine.pens);
+ }
+
+ const rectangle typewriter_scroll_clear_window(0, typewriter_window_width-1, typewriter_window_height-typewriter_scroll_step, typewriter_window_height-1);
+ state->m_typewriter_bitmap.fill(pen_typewriter_bg, typewriter_scroll_clear_window);
+}
+
+void tx0_typewriter_drawchar(running_machine &machine, int character)
+{
+ tx0_state *state = machine.driver_data<tx0_state>();
+ static const char ascii_table[2][64] =
+ {
+ { /* lower case */
+ '\0', '\0', 'e', '8',
+ '\0', '|', 'a', '3',
+ ' ', '=', 's', '4',
+ 'i', '+', 'u', '2',
+ '\0',/*color shift*/'.', 'd', '5',
+ 'r', '1', 'j', '7',
+ 'n', ',', 'f', '6',
+ 'c', '-', 'k', '\0',
+ 't', '\0', 'z', '\0',/*back space*/
+ 'l', '\0',/*tab*/ 'w', '\0',
+ 'h', '\0',/*carr. return*/'y', '\0',
+ 'p', '\0', 'q', '\0',
+ 'o', '\0',/*stop*/ 'b', '\0',
+ 'g', '\0', '9', '\0',
+ 'm', '\0',/*upper case*/ 'x', '\0',
+ 'v', '\0',/*lower case*/ '0', '\0'/*delete*/
+ },
+ { /* upper case */
+ '\0', '\0', 'E', '\210',
+ '\0', '_', 'A', '\203',
+ ' ', ':', 'S', '\204',
+ 'I', '/', 'U', '\202',
+ '\0',/*color shift*/')', 'D', '\205',
+ 'R', '\201', 'J', '\207',
+ 'N', '(', 'F', '\206',
+ 'C', '\212',/*macron*/ 'K', '\0',
+ 'T', '\0', 'Z', '\0',/*back space*/
+ 'L', '\0',/*tab*/ 'W', '\0',
+ 'H', '\0',/*carr. return*/'Y', '\0',
+ 'P', '\0', 'Q', '\0',
+ 'O', '\0',/*stop*/ 'B', '\0',
+ 'G', '\0', '\211', '\0',
+ 'M', '\0',/*upper case*/ 'X', '\0',
+ 'V', '\0',/*lower case*/ '\200', '\0'/*delete*/
+ }
+ };
+
+
+
+ character &= 0x3f;
+
+ switch (character)
+ {
+ case 020:
+#if 0
+ /* color shift */
+ state->m_typewriter_color = color_typewriter_black;
+ state->m_typewriter_color = color_typewriter_red;
+#endif
+ break;
+
+ case 043:
+ /* Backspace */
+ if (state->m_pos)
+ state->m_pos--;
+ break;
+
+ case 045:
+ /* Tab */
+ state->m_pos = state->m_pos + tab_step - (state->m_pos % tab_step);
+ break;
+
+ case 051:
+ /* Carriage Return */
+ state->m_pos = 0;
+ tx0_typewriter_linefeed( machine );
+ break;
+
+ case 061:
+ /* Stop */
+ /* ?????? */
+ break;
+
+ case 071:
+ /* Upper case */
+ state->m_case_shift = 1;
+ break;
+
+ case 075:
+ /* Lower case */
+ state->m_case_shift = 0;
+ break;
+
+ case 077:
+ /* Delete */
+ /* ?????? */
+ break;
+
+ default:
+ /* Any printable character... */
+
+ if (state->m_pos >= 80)
+ { /* if past right border, wrap around. (Right???) */
+ tx0_typewriter_linefeed( machine ); /* next line */
+ state->m_pos = 0; /* return to start of line */
+ }
+
+ /* print character (lookup ASCII equivalent in table) */
+ tx0_draw_char(machine, state->m_typewriter_bitmap, ascii_table[state->m_case_shift][character],
+ 8*state->m_pos, typewriter_write_offset_y,
+ state->m_typewriter_color); /* print char */
+
+ state->m_pos++; /* step carriage forward */
+ break;
+ }
+}
diff --git a/src/mess/video/upd7220.c b/src/mess/video/upd7220.c
new file mode 100644
index 00000000000..df8fb2fd90e
--- /dev/null
+++ b/src/mess/video/upd7220.c
@@ -0,0 +1,1667 @@
+/**********************************************************************
+
+ Intel 82720 Graphics Display Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - implement FIFO as ring buffer
+ - commands
+ - DMAR
+ - DMAW
+ - incomplete / unimplemented FIGD / GCHRD draw modes
+ - Arc
+ - FIGD character
+ - slanted character
+ - GCHRD character (needs rewrite)
+ - read-modify-write cycle
+ - read data
+ - modify data
+ - write data
+ - QX-10 diagnostic test has positioning bugs with the bitmap display test;
+ - QX-10 diagnostic test misses the zooming factor (external pin);
+ - compis2 SAD address for bitmap is 0x20000 for whatever reason (presumably missing banking);
+ - A5105 has a FIFO bug with the RDAT, should be a lot larger when it scrolls up;
+
+ - honor visible area
+ - wide mode (32-bit access)
+ - light pen
+
+*/
+
+#include "emu.h"
+#include "upd7220.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+
+// todo typedef
+enum
+{
+ COMMAND_INVALID = -1,
+ COMMAND_RESET,
+ COMMAND_SYNC,
+ COMMAND_VSYNC,
+ COMMAND_CCHAR,
+ COMMAND_START,
+ COMMAND_BCTRL,
+ COMMAND_ZOOM,
+ COMMAND_CURS,
+ COMMAND_PRAM,
+ COMMAND_PITCH,
+ COMMAND_WDAT,
+ COMMAND_MASK,
+ COMMAND_FIGS,
+ COMMAND_FIGD,
+ COMMAND_GCHRD,
+ COMMAND_RDAT,
+ COMMAND_CURD,
+ COMMAND_LPRD,
+ COMMAND_DMAR,
+ COMMAND_DMAW,
+ COMMAND_5A
+};
+
+enum
+{
+ FIFO_READ = 0,
+ FIFO_WRITE
+};
+
+enum
+{
+ FIFO_EMPTY = -1,
+ FIFO_PARAMETER,
+ FIFO_COMMAND
+};
+
+#define UPD7220_COMMAND_RESET 0x00
+#define UPD7220_COMMAND_SYNC 0x0e // & 0xfe
+#define UPD7220_COMMAND_VSYNC 0x6e // & 0xfe
+#define UPD7220_COMMAND_CCHAR 0x4b
+#define UPD7220_COMMAND_START 0x6b
+#define UPD7220_COMMAND_BCTRL 0x0c // & 0xfe
+#define UPD7220_COMMAND_ZOOM 0x46
+#define UPD7220_COMMAND_CURS 0x49
+#define UPD7220_COMMAND_PRAM 0x70 // & 0xf0
+#define UPD7220_COMMAND_PITCH 0x47
+#define UPD7220_COMMAND_WDAT 0x20 // & 0xe4
+#define UPD7220_COMMAND_MASK 0x4a
+#define UPD7220_COMMAND_FIGS 0x4c
+#define UPD7220_COMMAND_FIGD 0x6c
+#define UPD7220_COMMAND_GCHRD 0x68
+#define UPD7220_COMMAND_RDAT 0xa0 // & 0xe4
+#define UPD7220_COMMAND_CURD 0xe0
+#define UPD7220_COMMAND_LPRD 0xc0
+#define UPD7220_COMMAND_DMAR 0xa4 // & 0xe4
+#define UPD7220_COMMAND_DMAW 0x24 // & 0xe4
+#define UPD7220_COMMAND_5A 0x5a
+
+#define UPD7220_SR_DATA_READY 0x01
+#define UPD7220_SR_FIFO_FULL 0x02
+#define UPD7220_SR_FIFO_EMPTY 0x04
+#define UPD7220_SR_DRAWING_IN_PROGRESS 0x08
+#define UPD7220_SR_DMA_EXECUTE 0x10
+#define UPD7220_SR_VSYNC_ACTIVE 0x20
+#define UPD7220_SR_HBLANK_ACTIVE 0x40
+#define UPD7220_SR_LIGHT_PEN_DETECT 0x80
+
+#define UPD7220_MODE_S 0x01
+#define UPD7220_MODE_REFRESH_RAM 0x04
+#define UPD7220_MODE_I 0x08
+#define UPD7220_MODE_DRAW_ON_RETRACE 0x10
+#define UPD7220_MODE_DISPLAY_MASK 0x22
+#define UPD7220_MODE_DISPLAY_MIXED 0x00
+#define UPD7220_MODE_DISPLAY_GRAPHICS 0x02
+#define UPD7220_MODE_DISPLAY_CHARACTER 0x20
+#define UPD7220_MODE_DISPLAY_INVALID 0x22
+
+static const int x_dir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
+static const int y_dir[8] = { 1, 1, 0,-1,-1,-1, 0, 1};
+static const int x_dir_dot[8] = { 1, 1, 0,-1,-1,-1, 0, 1};
+static const int y_dir_dot[8] = { 0,-1,-1,-1, 0, 1, 1, 1};
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type UPD7220 = &device_creator<upd7220_device>;
+
+
+// default address map
+static ADDRESS_MAP_START( upd7220_vram, AS_0, 8, upd7220_device )
+ AM_RANGE(0x00000, 0x3ffff) AM_RAM
+ADDRESS_MAP_END
+
+
+// internal 128x14 control ROM
+ROM_START( upd7220 )
+ ROM_REGION( 0x100, "upd7220", 0 )
+ ROM_LOAD( "upd7220.bin", 0x000, 0x100, NO_DUMP )
+ROM_END
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *upd7220_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *upd7220_device::device_rom_region() const
+{
+ return ROM_NAME( upd7220 );
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void upd7220_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const upd7220_interface *intf = reinterpret_cast<const upd7220_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<upd7220_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_drq_cb, 0, sizeof(m_out_drq_cb));
+ memset(&m_out_hsync_cb, 0, sizeof(m_out_hsync_cb));
+ memset(&m_out_vsync_cb, 0, sizeof(m_out_vsync_cb));
+ memset(&m_out_blank_cb, 0, sizeof(m_out_blank_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 upd7220_device::readbyte(offs_t address)
+{
+ return space()->read_byte(address);
+}
+
+
+//-------------------------------------------------
+// writebyte - write a byte at the given address
+//-------------------------------------------------
+
+inline void upd7220_device::writebyte(offs_t address, UINT8 data)
+{
+ space()->write_byte(address, data);
+}
+
+
+//-------------------------------------------------
+// fifo_clear -
+//-------------------------------------------------
+
+inline void upd7220_device::fifo_clear()
+{
+ for (int i = 0; i < 16; i++)
+ {
+ m_fifo[i] = 0;
+ m_fifo_flag[i] = FIFO_EMPTY;
+ }
+
+ m_fifo_ptr = -1;
+
+ m_sr &= ~UPD7220_SR_DATA_READY;
+ m_sr |= UPD7220_SR_FIFO_EMPTY;
+ m_sr &= ~UPD7220_SR_FIFO_FULL;
+}
+
+
+//-------------------------------------------------
+// fifo_param_count -
+//-------------------------------------------------
+
+inline int upd7220_device::fifo_param_count()
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (m_fifo_flag[i] != FIFO_PARAMETER) break;
+ }
+
+ return i;
+}
+
+
+//-------------------------------------------------
+// fifo_set_direction -
+//-------------------------------------------------
+
+inline void upd7220_device::fifo_set_direction(int dir)
+{
+ if (m_fifo_dir != dir)
+ {
+ fifo_clear();
+ }
+
+ m_fifo_dir = dir;
+}
+
+
+//-------------------------------------------------
+// queue -
+//-------------------------------------------------
+
+inline void upd7220_device::queue(UINT8 data, int flag)
+{
+ if (m_fifo_ptr < 15)
+ {
+ m_fifo_ptr++;
+
+ m_fifo[m_fifo_ptr] = data;
+ m_fifo_flag[m_fifo_ptr] = flag;
+
+ if (m_fifo_ptr == 16)
+ {
+ m_sr |= UPD7220_SR_FIFO_FULL;
+ }
+
+ m_sr &= ~UPD7220_SR_FIFO_EMPTY;
+ }
+ else
+ {
+ // TODO what happen? somebody set us up the bomb
+ printf("FIFO?\n");
+ }
+}
+
+
+//-------------------------------------------------
+// dequeue -
+//-------------------------------------------------
+
+inline void upd7220_device::dequeue(UINT8 *data, int *flag)
+{
+ *data = m_fifo[0];
+ *flag = m_fifo_flag[0];
+
+ if (m_fifo_ptr > -1)
+ {
+ for (int i = 0; i < 15; i++)
+ {
+ m_fifo[i] = m_fifo[i + 1];
+ m_fifo_flag[i] = m_fifo_flag[i + 1];
+ }
+
+ m_fifo[15] = 0;
+ m_fifo_flag[15] = 0;
+
+ m_fifo_ptr--;
+
+ if (m_fifo_ptr == -1)
+ {
+ m_sr &= ~UPD7220_SR_DATA_READY;
+ m_sr |= UPD7220_SR_FIFO_EMPTY;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// update_vsync_timer -
+//-------------------------------------------------
+
+inline void upd7220_device::update_vsync_timer(int state)
+{
+ int next_y = state ? m_vs : 0;
+
+ attotime duration = m_screen->time_until_pos(next_y, 0);
+
+ m_vsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_hsync_timer -
+//-------------------------------------------------
+
+inline void upd7220_device::update_hsync_timer(int state)
+{
+ int y = m_screen->vpos();
+
+ int next_x = state ? m_hs : 0;
+ int next_y = state ? y : ((y + 1) % m_al);
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_hsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_blank_timer -
+//-------------------------------------------------
+
+inline void upd7220_device::update_blank_timer(int state)
+{
+ int y = m_screen->vpos();
+
+ int next_x = state ? (m_hs + m_hbp) : (m_hs + m_hbp + (m_aw << 3));
+ int next_y = state ? ((y + 1) % (m_vs + m_vbp + m_al + m_vfp - 1)) : y;
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_hsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// recompute_parameters -
+//-------------------------------------------------
+
+inline void upd7220_device::recompute_parameters()
+{
+ int horiz_pix_total = (m_hs + m_hbp + m_aw + m_hfp) * 8;
+ int vert_pix_total = m_vs + m_vbp + m_al + m_vfp;
+
+ //printf("%d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp);
+ //printf("%d %d\n",m_aw * 8,m_pitch * 8);
+
+ if (horiz_pix_total == 0 || vert_pix_total == 0) //bail out if screen params aren't valid
+ return;
+
+ attoseconds_t refresh = HZ_TO_ATTOSECONDS(60); //HZ_TO_ATTOSECONDS(clock() * 8) * horiz_pix_total * vert_pix_total;
+
+ rectangle visarea;
+
+ visarea.min_x = 0; //(m_hs + m_hbp) * 8;
+ visarea.min_y = 0; //m_vs + m_vbp;
+ visarea.max_x = m_aw * 8 - 1;//horiz_pix_total - (m_hfp * 8) - 1;
+ visarea.max_y = m_al - 1;//vert_pix_total - m_vfp - 1;
+
+
+ if (LOG)
+ {
+ logerror("uPD7220 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
+ logerror("uPD7220 '%s' Visible Area: (%u, %u) - (%u, %u)\n", tag(), visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y);
+ }
+
+ if (m_m)
+ {
+ m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh);
+
+ update_hsync_timer(0);
+ update_vsync_timer(0);
+ }
+ else
+ {
+ m_hsync_timer->enable(0);
+ m_vsync_timer->enable(0);
+ }
+
+ update_blank_timer(0);
+}
+
+
+//-------------------------------------------------
+// reset_figs_param -
+//-------------------------------------------------
+
+inline void upd7220_device::reset_figs_param()
+{
+ m_figs.m_dc = 0x0000;
+ m_figs.m_d = 0x0008;
+ m_figs.m_d1 = 0x0008;
+ m_figs.m_d2 = 0x0000;
+ m_figs.m_dm = 0x0000;
+}
+
+
+//-------------------------------------------------
+// advance_ead -
+//-------------------------------------------------
+
+inline void upd7220_device::advance_ead()
+{
+ #define EAD m_ead
+ #define DAD m_dad
+ #define P x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch)
+ #define MSB(value) (BIT(value, 15))
+ #define LSB(value) (BIT(value, 0))
+ #define LR(value) ((value << 1) | MSB(value))
+ #define RR(value) ((LSB(value) << 15) | (value >> 1))
+
+ switch (m_draw_mode & 0x07)
+ {
+ case 0:
+ EAD += P;
+ break;
+
+ case 1:
+ EAD += P;
+ if (MSB(DAD)) EAD++;
+ DAD = LR(DAD);
+ break;
+
+ case 2:
+ if (MSB(DAD)) EAD++;
+ DAD = LR(DAD);
+ break;
+
+ case 3:
+ EAD -= P;
+ if (MSB(DAD)) EAD++;
+ DAD = LR(DAD);
+ break;
+
+ case 4:
+ EAD -= P;
+ break;
+
+ case 5:
+ EAD -= P;
+ if (LSB(DAD)) EAD--;
+ DAD = RR(DAD);
+ break;
+
+ case 6:
+ if (LSB(DAD)) EAD--;
+ DAD = RR(DAD);
+ break;
+
+ case 7:
+ EAD += P;
+ if (LSB(DAD)) EAD--;
+ DAD = RR(DAD);
+ break;
+ }
+
+ EAD &= 0x3ffff;
+}
+
+
+//-------------------------------------------------
+// read_vram -
+//-------------------------------------------------
+
+inline void upd7220_device::read_vram(UINT8 type, UINT8 mod)
+{
+ if (type == 1)
+ {
+ logerror("uPD7220 invalid type 1 RDAT parameter\n");
+ return;
+ }
+
+ if (mod)
+ logerror("uPD7220 RDAT used with mod = %02x?\n",mod);
+
+ for (int i = 0; i < m_figs.m_dc; i++)
+ {
+ switch(type)
+ {
+ case 0:
+ queue(readbyte(m_ead*2), 0);
+ queue(readbyte(m_ead*2+1), 0);
+ break;
+ case 2:
+ queue(readbyte(m_ead*2), 0);
+ break;
+ case 3:
+ queue(readbyte(m_ead*2+1), 0);
+ break;
+ }
+
+ advance_ead();
+ }
+}
+
+
+//-------------------------------------------------
+// write_vram -
+//-------------------------------------------------
+
+inline void upd7220_device::write_vram(UINT8 type, UINT8 mod)
+{
+ UINT16 result;
+
+ if (type == 1)
+ {
+ printf("uPD7220 invalid type 1 WDAT parameter\n");
+ return;
+ }
+
+ result = 0;
+
+ switch(type)
+ {
+ case 0:
+ result = (m_pr[1] & 0xff);
+ result |= (m_pr[2] << 8);
+ result &= m_mask;
+ break;
+ case 2:
+ result = (m_pr[1] & 0xff);
+ result &= (m_mask & 0xff);
+ break;
+ case 3:
+ result = (m_pr[1] << 8);
+ result &= (m_mask & 0xff00);
+ break;
+ }
+
+ //if(result)
+ {
+ //printf("%04x %02x %02x %04x %02x %02x\n",readbyte(m_ead),m_pr[1],m_pr[2],m_mask,type,mod);
+ //printf("%04x %02x %02x\n",m_ead,m_figs.m_dir,m_pitch);
+ //printf("%04x %04x %02x %04x\n",m_ead,result,mod,m_figs.m_dc);
+ }
+
+ for(int i = 0; i < m_figs.m_dc + 1; i++)
+ {
+ switch(mod & 3)
+ {
+ case 0x00: //replace
+ if(type == 0 || type == 2)
+ writebyte(m_ead*2+0, result & 0xff);
+ if(type == 0 || type == 3)
+ writebyte(m_ead*2+1, result >> 8);
+ break;
+ case 0x01: //complement
+ if(type == 0 || type == 2)
+ writebyte(m_ead*2+0, readbyte(m_ead*2+0) ^ (result & 0xff));
+ if(type == 0 || type == 3)
+ writebyte(m_ead*2+1, readbyte(m_ead*2+1) ^ (result >> 8));
+ break;
+ case 0x02: //reset to zero
+ if(type == 0 || type == 2)
+ writebyte(m_ead*2+0, readbyte(m_ead*2+0) & ~(result & 0xff));
+ if(type == 0 || type == 3)
+ writebyte(m_ead*2+1, readbyte(m_ead*2+1) & ~(result >> 8));
+ break;
+ case 0x03: //set to one
+ if(type == 0 || type == 2)
+ writebyte(m_ead*2+0, readbyte(m_ead*2+0) | (result & 0xff));
+ if(type == 0 || type == 3)
+ writebyte(m_ead*2+1, readbyte(m_ead*2+1) | (result >> 8));
+ break;
+ }
+
+ advance_ead();
+ }
+}
+
+
+//-------------------------------------------------
+// check_pattern -
+//-------------------------------------------------
+
+inline UINT16 upd7220_device::check_pattern(UINT16 pattern)
+{
+ UINT16 res = 0;
+
+ switch (m_bitmap_mod & 3)
+ {
+ case 0: res = pattern; break; //replace
+ case 1: res = pattern; break; //complement
+ case 2: res = 0; break; //reset to zero
+ case 3: res |= 0xffff; break; //set to one
+ }
+
+ return res;
+}
+
+
+//-------------------------------------------------
+// get_text_partition -
+//-------------------------------------------------
+
+inline void upd7220_device::get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd)
+{
+ *sad = ((m_ra[(index * 4) + 1] & 0x1f) << 8) | m_ra[(index * 4) + 0];
+ *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4);
+ *im = BIT(m_ra[(index * 4) + 3], 6);
+ *wd = BIT(m_ra[(index * 4) + 3], 7);
+}
+
+
+//-------------------------------------------------
+// get_graphics_partition -
+//-------------------------------------------------
+
+inline void upd7220_device::get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd)
+{
+ *sad = ((m_ra[(index * 4) + 2] & 0x03) << 16) | (m_ra[(index * 4) + 1] << 8) | m_ra[(index * 4) + 0];
+ *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4);
+ *im = BIT(m_ra[(index * 4) + 3], 6);
+ *wd = BIT(m_ra[(index * 4) + 3], 7);
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// upd7220_device - constructor
+//-------------------------------------------------
+
+upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, UPD7220, "uPD7220", tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ m_mask(0),
+ m_pitch(0),
+ m_ead(0),
+ m_dad(0),
+ m_lad(0),
+ m_ra_addr(0),
+ m_sr(UPD7220_SR_FIFO_EMPTY),
+ m_cr(0),
+ m_param_ptr(0),
+ m_fifo_ptr(-1),
+ m_fifo_dir(0),
+ m_mode(0),
+ m_draw_mode(0),
+ m_de(0),
+ m_m(0),
+ m_aw(0),
+ m_al(0),
+ m_vs(0),
+ m_vfp(0),
+ m_vbp(0),
+ m_hs(0),
+ m_hfp(0),
+ m_hbp(0),
+ m_dc(0),
+ m_sc(0),
+ m_br(0),
+ m_ctop(0),
+ m_cbot(0),
+ m_lr(0),
+ m_disp(0),
+ m_gchr(0),
+ m_bitmap_mod(0),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 18, 0, NULL, *ADDRESS_MAP_NAME(upd7220_vram))
+{
+ m_shortname = "upd7220";
+ for (int i = 0; i < 16; i++)
+ {
+ m_fifo[i] = 0;
+ m_fifo_flag[i] = FIFO_EMPTY;
+
+ m_ra[i] = 0;
+ }
+
+ for (int i = 0; i < 17; i++)
+ {
+ m_pr[i] = 0;
+ }
+
+ m_figs.m_dir = 0;
+ m_figs.m_figure_type = 0;
+ m_figs.m_dc = 0;
+ m_figs.m_d = 0;
+ m_figs.m_d1 = 0;
+ m_figs.m_d2 = 0;
+ m_figs.m_dm = 0;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void upd7220_device::device_start()
+{
+ // allocate timers
+ m_vsync_timer = timer_alloc(TIMER_VSYNC);
+ m_hsync_timer = timer_alloc(TIMER_HSYNC);
+ m_blank_timer = timer_alloc(TIMER_BLANK);
+
+ // resolve callbacks
+ m_out_drq_func.resolve(m_out_drq_cb, *this);
+ m_out_hsync_func.resolve(m_out_hsync_cb, *this);
+ m_out_vsync_func.resolve(m_out_vsync_cb, *this);
+ m_out_blank_func.resolve(m_out_blank_cb, *this);
+
+ // find screen
+ m_screen = machine().device<screen_device>(m_screen_tag);
+
+ if (m_screen == NULL)
+ {
+ m_screen = owner()->subdevice<screen_device>(m_screen_tag);
+ }
+
+ assert(m_screen);
+
+ // register for state saving
+ save_item(NAME(m_ra));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_de));
+ save_item(NAME(m_aw));
+ save_item(NAME(m_al));
+ save_item(NAME(m_vs));
+ save_item(NAME(m_vfp));
+ save_item(NAME(m_vbp));
+ save_item(NAME(m_hs));
+ save_item(NAME(m_hfp));
+ save_item(NAME(m_hbp));
+ save_item(NAME(m_m));
+ save_item(NAME(m_dc));
+ save_item(NAME(m_sc));
+ save_item(NAME(m_br));
+ save_item(NAME(m_lr));
+ save_item(NAME(m_ctop));
+ save_item(NAME(m_cbot));
+ save_item(NAME(m_ead));
+ save_item(NAME(m_dad));
+ save_item(NAME(m_lad));
+ save_item(NAME(m_disp));
+ save_item(NAME(m_gchr));
+ save_item(NAME(m_mask));
+ save_item(NAME(m_pitch));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void upd7220_device::device_reset()
+{
+ m_out_drq_func(CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void upd7220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_HSYNC:
+ if (param)
+ {
+ m_sr |= UPD7220_SR_HBLANK_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
+ }
+
+ m_out_hsync_func(param);
+
+ update_hsync_timer(param);
+ break;
+
+ case TIMER_VSYNC:
+ if (param)
+ {
+ m_sr |= UPD7220_SR_VSYNC_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_VSYNC_ACTIVE;
+ }
+
+ m_out_vsync_func(param);
+
+ update_vsync_timer(param);
+ break;
+
+ case TIMER_BLANK:
+ if (param)
+ {
+ m_sr |= UPD7220_SR_HBLANK_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
+ }
+
+ m_out_blank_func(param);
+
+ update_blank_timer(param);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// draw_pixel -
+//-------------------------------------------------
+
+void upd7220_device::draw_pixel(int x, int y, UINT16 tile_data)
+{
+ UINT32 addr = (y * m_pitch * 2 + (x >> 3)) & 0x3ffff;
+
+ int dad = x & 0x7;
+
+ UINT8 data = readbyte(addr);
+
+ if((m_bitmap_mod & 3) == 1)
+ {
+ writebyte(addr, data ^ ((tile_data) & (0x80 >> (dad))));
+ }
+ else
+ {
+ writebyte(addr, data & ~(0x80 >> (dad)));
+ writebyte(addr, data | ((tile_data) & (0x80 >> (dad))));
+ }
+}
+
+
+//-------------------------------------------------
+// draw_line -
+//-------------------------------------------------
+
+void upd7220_device::draw_line(int x, int y)
+{
+ int line_size,i;
+ const int line_x_dir[8] = { 0, 1, 1, 0, 0,-1,-1, 0};
+ const int line_y_dir[8] = { 1, 0, 0,-1,-1, 0, 0, 1};
+ const int line_x_step[8] = { 1, 0, 0, 1,-1, 0, 0,-1 };
+ const int line_y_step[8] = { 0, 1,-1, 0, 0,-1, 1, 0 };
+ UINT16 line_pattern;
+ int line_step = 0;
+ UINT8 dot;
+
+ line_size = m_figs.m_dc + 1;
+ line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8));
+
+ for(i = 0;i<line_size;i++)
+ {
+ line_step = (m_figs.m_d1 * i);
+ line_step/= (m_figs.m_dc + 1);
+ line_step >>= 1;
+ dot = ((line_pattern >> (i & 0xf)) & 1) << 7;
+ draw_pixel(x + (line_step*line_x_step[m_figs.m_dir]),y + (line_step*line_y_step[m_figs.m_dir]),dot >> ((x + line_step*line_x_step[m_figs.m_dir]) & 0x7));
+ x += line_x_dir[m_figs.m_dir];
+ y += line_y_dir[m_figs.m_dir];
+ }
+
+ /* TODO: check me*/
+ x += (line_step*line_x_step[m_figs.m_dir]);
+ y += (line_step*line_y_step[m_figs.m_dir]);
+
+ m_ead = (x >> 4) + (y * m_pitch);
+ m_dad = x & 0x0f;
+}
+
+
+//-------------------------------------------------
+// draw_rectangle -
+//-------------------------------------------------
+
+void upd7220_device::draw_rectangle(int x, int y)
+{
+ int i;
+ const int rect_x_dir[8] = { 0, 1, 0,-1, 1, 1,-1,-1 };
+ const int rect_y_dir[8] = { 1, 0,-1, 0, 1,-1,-1, 1 };
+ UINT8 rect_type,rect_dir;
+ UINT16 line_pattern;
+ UINT8 dot;
+
+ logerror("uPD7220 rectangle check: %d %d %02x %08x\n",x,y,m_figs.m_dir,m_ead);
+
+ line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8));
+ rect_type = (m_figs.m_dir & 1) << 2;
+ rect_dir = rect_type | (((m_figs.m_dir >> 1) + 0) & 3);
+
+ for(i = 0;i < m_figs.m_d;i++)
+ {
+ dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7;
+ draw_pixel(x,y,dot >> (x & 0x7));
+ x+=rect_x_dir[rect_dir];
+ y+=rect_y_dir[rect_dir];
+ }
+
+ rect_dir = rect_type | (((m_figs.m_dir >> 1) + 1) & 3);
+
+ for(i = 0;i < m_figs.m_d2;i++)
+ {
+ dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7;
+ draw_pixel(x,y,dot >> (x & 0x7));
+ x+=rect_x_dir[rect_dir];
+ y+=rect_y_dir[rect_dir];
+ }
+
+ rect_dir = rect_type | (((m_figs.m_dir >> 1) + 2) & 3);
+
+ for(i = 0;i < m_figs.m_d;i++)
+ {
+ dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7;
+ draw_pixel(x,y,dot >> (x & 0x7));
+ x+=rect_x_dir[rect_dir];
+ y+=rect_y_dir[rect_dir];
+ }
+
+ rect_dir = rect_type | (((m_figs.m_dir >> 1) + 3) & 3);
+
+ for(i = 0;i < m_figs.m_d2;i++)
+ {
+ dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7;
+ draw_pixel(x,y,dot >> (x & 0x7));
+ x+=rect_x_dir[rect_dir];
+ y+=rect_y_dir[rect_dir];
+ }
+
+ m_ead = (x >> 4) + (y * m_pitch);
+ m_dad = x & 0x0f;
+
+}
+
+
+//-------------------------------------------------
+// draw_char -
+//-------------------------------------------------
+
+void upd7220_device::draw_char(int x, int y)
+{
+ int xi,yi;
+ int xsize,ysize;
+ UINT8 tile_data;
+
+ /* snippet for character checking */
+ #if 0
+ for(yi=0;yi<8;yi++)
+ {
+ for(xi=0;xi<8;xi++)
+ {
+ printf("%d",(m_ra[(yi & 7) | 8] >> xi) & 1);
+ }
+ printf("\n");
+ }
+ #endif
+
+ xsize = m_figs.m_d & 0x3ff;
+ /* Guess: D has presumably upper bits for ysize, QX-10 relies on this (TODO: check this on any real HW) */
+ ysize = ((m_figs.m_d & 0x400) + m_figs.m_dc) + 1;
+
+ /* TODO: internal direction, zooming, size stuff bigger than 8, rewrite using draw_pixel function */
+ for(yi=0;yi<ysize;yi++)
+ {
+ switch(m_figs.m_dir & 7)
+ {
+ case 0: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],0,1,2,3,4,5,6,7); break; // TODO
+ case 2: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],0,1,2,3,4,5,6,7); break;
+ case 6: tile_data = BITSWAP8(m_ra[((ysize-1-yi) & 7) | 8],7,6,5,4,3,2,1,0); break;
+ default: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],7,6,5,4,3,2,1,0);
+ printf("%d %d %d\n",m_figs.m_dir,xsize,ysize);
+ break;
+ }
+
+ for(xi=0;xi<xsize;xi++)
+ {
+ UINT32 addr = ((y+yi) * m_pitch * 2) + ((x+xi) >> 3);
+
+ writebyte(addr & 0x3ffff, readbyte(addr & 0x3ffff) & ~(1 << (xi & 7)));
+ writebyte(addr & 0x3ffff, readbyte(addr & 0x3ffff) | ((tile_data) & (1 << (xi & 7))));
+ }
+ }
+
+ m_ead = ((x+8*x_dir_dot[m_figs.m_dir]) >> 4) + ((y+8*y_dir_dot[m_figs.m_dir]) * m_pitch);
+ m_dad = ((x+8*x_dir_dot[m_figs.m_dir]) & 0xf);
+}
+
+
+//-------------------------------------------------
+// translate_command -
+//-------------------------------------------------
+
+int upd7220_device::translate_command(UINT8 data)
+{
+ int command = COMMAND_INVALID;
+
+ switch (data)
+ {
+ case UPD7220_COMMAND_RESET: command = COMMAND_RESET; break;
+ case UPD7220_COMMAND_CCHAR: command = COMMAND_CCHAR; break;
+ case UPD7220_COMMAND_START: command = COMMAND_START; break;
+ case UPD7220_COMMAND_ZOOM: command = COMMAND_ZOOM; break;
+ case UPD7220_COMMAND_CURS: command = COMMAND_CURS; break;
+ case UPD7220_COMMAND_PITCH: command = COMMAND_PITCH; break;
+ case UPD7220_COMMAND_MASK: command = COMMAND_MASK; break;
+ case UPD7220_COMMAND_FIGS: command = COMMAND_FIGS; break;
+ case UPD7220_COMMAND_FIGD: command = COMMAND_FIGD; break;
+ case UPD7220_COMMAND_GCHRD: command = COMMAND_GCHRD; break;
+ case UPD7220_COMMAND_CURD: command = COMMAND_CURD; break;
+ case UPD7220_COMMAND_LPRD: command = COMMAND_LPRD; break;
+ case UPD7220_COMMAND_5A: command = COMMAND_5A; break;
+ default:
+ switch (data & 0xfe)
+ {
+ case UPD7220_COMMAND_SYNC: command = COMMAND_SYNC; break;
+ case UPD7220_COMMAND_VSYNC: command = COMMAND_VSYNC; break;
+ case UPD7220_COMMAND_BCTRL: command = COMMAND_BCTRL; break;
+ default:
+ switch (data & 0xf0)
+ {
+ case UPD7220_COMMAND_PRAM: command = COMMAND_PRAM; break;
+ default:
+ switch (data & 0xe4)
+ {
+ case UPD7220_COMMAND_WDAT: command = COMMAND_WDAT; break;
+ case UPD7220_COMMAND_RDAT: command = COMMAND_RDAT; break;
+ case UPD7220_COMMAND_DMAR: command = COMMAND_DMAR; break;
+ case UPD7220_COMMAND_DMAW: command = COMMAND_DMAW; break;
+ }
+ }
+ }
+ }
+
+ return command;
+}
+
+
+//-------------------------------------------------
+// process_fifo -
+//-------------------------------------------------
+
+void upd7220_device::process_fifo()
+{
+ UINT8 data;
+ int flag;
+
+ dequeue(&data, &flag);
+
+ if (flag == FIFO_COMMAND)
+ {
+ m_cr = data;
+ m_param_ptr = 1;
+ }
+ else
+ {
+ m_pr[m_param_ptr] = data;
+ m_param_ptr++;
+ }
+
+ switch (translate_command(m_cr))
+ {
+ case COMMAND_INVALID:
+ printf("uPD7220 '%s' Invalid Command Byte %02x\n", tag(), m_cr);
+ break;
+
+ case COMMAND_5A:
+ if (m_param_ptr == 4)
+ printf("uPD7220 '%s' Undocumented Command 0x5A Executed %02x %02x %02x\n", tag(),m_pr[1],m_pr[2],m_pr[3] );
+ break;
+
+ case COMMAND_RESET: /* reset */
+ switch (m_param_ptr)
+ {
+ case 0:
+ if (LOG) logerror("uPD7220 '%s' RESET\n", tag());
+
+ m_de = 0;
+ m_ra[0] = m_ra[1] = m_ra[2] = 0;
+ m_ra[3] = 0x19;
+ m_ead = 0;
+ m_dad = 0;
+ m_mask = 0;
+ break;
+
+ case 9:
+ m_mode = m_pr[1];
+ m_aw = m_pr[2] + 2;
+ m_hs = (m_pr[3] & 0x1f) + 1;
+ m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5);
+ m_hfp = (m_pr[4] >> 2) + 1;
+ m_hbp = (m_pr[5] & 0x3f) + 1;
+ m_vfp = m_pr[6] & 0x3f;
+ m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7];
+ m_vbp = m_pr[8] >> 2;
+
+ m_pitch = m_aw;
+
+ if (LOG)
+ {
+ logerror("uPD7220 '%s' Mode: %02x\n", tag(), m_mode);
+ logerror("uPD7220 '%s' AW: %u\n", tag(), m_aw);
+ logerror("uPD7220 '%s' HS: %u\n", tag(), m_hs);
+ logerror("uPD7220 '%s' VS: %u\n", tag(), m_vs);
+ logerror("uPD7220 '%s' HFP: %u\n", tag(), m_hfp);
+ logerror("uPD7220 '%s' HBP: %u\n", tag(), m_hbp);
+ logerror("uPD7220 '%s' VFP: %u\n", tag(), m_vfp);
+ logerror("uPD7220 '%s' AL: %u\n", tag(), m_al);
+ logerror("uPD7220 '%s' VBP: %u\n", tag(), m_vbp);
+ logerror("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch);
+ }
+
+ recompute_parameters();
+ break;
+ }
+ break;
+
+ case COMMAND_SYNC: /* sync format specify */
+ if (m_param_ptr == 9)
+ {
+ m_mode = m_pr[1];
+ m_aw = m_pr[2] + 2;
+ m_hs = (m_pr[3] & 0x1f) + 1;
+ m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5);
+ m_hfp = (m_pr[4] >> 2) + 1;
+ m_hbp = (m_pr[5] & 0x3f) + 1;
+ m_vfp = m_pr[6] & 0x3f;
+ m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7];
+ m_vbp = m_pr[8] >> 2;
+
+ m_pitch = m_aw;
+
+ if (LOG)
+ {
+ logerror("uPD7220 '%s' Mode: %02x\n", tag(), m_mode);
+ logerror("uPD7220 '%s' AW: %u\n", tag(), m_aw);
+ logerror("uPD7220 '%s' HS: %u\n", tag(), m_hs);
+ logerror("uPD7220 '%s' VS: %u\n", tag(), m_vs);
+ logerror("uPD7220 '%s' HFP: %u\n", tag(), m_hfp);
+ logerror("uPD7220 '%s' HBP: %u\n", tag(), m_hbp);
+ logerror("uPD7220 '%s' VFP: %u\n", tag(), m_vfp);
+ logerror("uPD7220 '%s' AL: %u\n", tag(), m_al);
+ logerror("uPD7220 '%s' VBP: %u\n", tag(), m_vbp);
+ logerror("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch);
+ }
+
+ recompute_parameters();
+ }
+ break;
+
+ case COMMAND_VSYNC: /* vertical sync mode */
+ m_m = m_cr & 0x01;
+
+ if (LOG) logerror("uPD7220 '%s' M: %u\n", tag(), m_m);
+
+ recompute_parameters();
+ break;
+
+ case COMMAND_CCHAR: /* cursor & character characteristics */
+ if(m_param_ptr == 2)
+ {
+ m_lr = (m_pr[1] & 0x1f) + 1;
+ m_dc = BIT(m_pr[1], 7);
+
+ if (LOG)
+ {
+ logerror("uPD7220 '%s' LR: %u\n", tag(), m_lr);
+ logerror("uPD7220 '%s' DC: %u\n", tag(), m_dc);
+ }
+ }
+
+ if(m_param_ptr == 3)
+ {
+ m_ctop = m_pr[2] & 0x1f;
+ m_sc = BIT(m_pr[2], 5);
+
+ if (LOG)
+ {
+ logerror("uPD7220 '%s' CTOP: %u\n", tag(), m_ctop);
+ logerror("uPD7220 '%s' SC: %u\n", tag(), m_sc);
+ }
+ }
+
+ if(m_param_ptr == 4)
+ {
+ m_br = ((m_pr[3] & 0x07) << 2) | (m_pr[2] >> 6);
+ m_cbot = m_pr[3] >> 3;
+
+ if (LOG)
+ {
+ logerror("uPD7220 '%s' BR: %u\n", tag(), m_br);
+ logerror("uPD7220 '%s' CBOT: %u\n", tag(), m_cbot);
+ }
+ }
+ break;
+
+ case COMMAND_START: /* start display & end idle mode */
+ m_de = 1;
+
+ if (LOG) logerror("uPD7220 '%s' DE: 1\n", tag());
+ break;
+
+ case COMMAND_BCTRL: /* display blanking control */
+ m_de = m_cr & 0x01;
+
+ if (LOG) logerror("uPD7220 '%s' DE: %u\n", tag(), m_de);
+ break;
+
+ case COMMAND_ZOOM: /* zoom factors specify */
+ if (flag == FIFO_PARAMETER)
+ {
+ m_gchr = m_pr[1] & 0x0f;
+ m_disp = m_pr[1] >> 4;
+
+ if (LOG) logerror("uPD7220 '%s' GCHR: %01x\n", tag(), m_gchr);
+ if (LOG) logerror("uPD7220 '%s' DISP: %01x\n", tag(), m_disp);
+ }
+ break;
+
+ case COMMAND_CURS: /* cursor position specify */
+ if (m_param_ptr >= 3)
+ {
+ UINT8 upper_addr = (m_param_ptr == 3) ? 0 : (m_pr[3] & 0x03);
+
+ m_ead = (upper_addr << 16) | (m_pr[2] << 8) | m_pr[1];
+
+ if (LOG) logerror("uPD7220 '%s' EAD: %06x\n", tag(), m_ead);
+
+ if(m_param_ptr == 4)
+ {
+ m_dad = m_pr[3] >> 4;
+ if (LOG) logerror("uPD7220 '%s' DAD: %01x\n", tag(), m_dad);
+ }
+ }
+ break;
+
+ case COMMAND_PRAM: /* parameter RAM load */
+ if (flag == FIFO_COMMAND)
+ {
+ m_ra_addr = m_cr & 0x0f;
+ }
+ else
+ {
+ if (m_ra_addr < 16)
+ {
+ if (LOG) logerror("uPD7220 '%s' RA%u: %02x\n", tag(), m_ra_addr, data);
+
+ m_ra[m_ra_addr] = data;
+ m_ra_addr++;
+ }
+
+ m_param_ptr = 0;
+ }
+ break;
+
+ case COMMAND_PITCH: /* pitch specification */
+ if (flag == FIFO_PARAMETER)
+ {
+ m_pitch = data;
+
+ if (LOG) logerror("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch);
+ }
+ break;
+
+ case COMMAND_WDAT: /* write data into display memory */
+ m_bitmap_mod = m_cr & 3;
+
+ if (m_param_ptr == 3 || (m_param_ptr == 2 && m_cr & 0x10))
+ {
+ //printf("%02x = %02x %02x (%c) %04x\n",m_cr,m_pr[2],m_pr[1],m_pr[1],EAD);
+ fifo_set_direction(FIFO_WRITE);
+
+ write_vram((m_cr & 0x18) >> 3,m_cr & 3);
+ reset_figs_param();
+ m_param_ptr = 1;
+ }
+ break;
+
+ case COMMAND_MASK: /* mask register load */
+ if (m_param_ptr == 3)
+ {
+ m_mask = (m_pr[2] << 8) | m_pr[1];
+
+ if (LOG) logerror("uPD7220 '%s' MASK: %04x\n", tag(), m_mask);
+ }
+ break;
+
+ case COMMAND_FIGS: /* figure drawing parameters specify */
+ if (m_param_ptr == 2)
+ {
+ m_figs.m_dir = m_pr[1] & 0x7;
+ m_figs.m_figure_type = (m_pr[1] & 0xf8) >> 3;
+
+ //if(m_figs.m_dir != 2)
+ // printf("DIR %02x\n",m_pr[1]);
+ }
+
+ // the Decision Mate V during start-up test upload only 2 params before execute the
+ // RDAT command, so I assume this is the expected behaviour, but this needs to be verified.
+ if (m_param_ptr == 3)
+ m_figs.m_dc = (m_pr[2]) | (m_figs.m_dc & 0x3f00);
+
+ if (m_param_ptr == 4)
+ m_figs.m_dc = (m_pr[2]) | ((m_pr[3] & 0x3f) << 8);
+
+ if (m_param_ptr == 6)
+ m_figs.m_d = (m_pr[4]) | ((m_pr[5] & 0x3f) << 8);
+
+ if (m_param_ptr == 8)
+ m_figs.m_d2 = (m_pr[6]) | ((m_pr[7] & 0x3f) << 8);
+
+ if (m_param_ptr == 10)
+ m_figs.m_d1 = (m_pr[8]) | ((m_pr[9] & 0x3f) << 8);
+
+ if (m_param_ptr == 12)
+ m_figs.m_dm = (m_pr[10]) | ((m_pr[11] & 0x3f) << 8);
+
+ break;
+
+ case COMMAND_FIGD: /* figure draw start */
+ if(m_figs.m_figure_type == 0)
+ {
+ UINT16 line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8));
+ UINT8 dot = ((line_pattern >> (0 & 0xf)) & 1) << 7;
+
+ draw_pixel(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch),dot);
+ }
+ else if(m_figs.m_figure_type == 1)
+ draw_line(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch));
+ else if(m_figs.m_figure_type == 8)
+ draw_rectangle(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch));
+ else
+ printf("uPD7220 '%s' Unimplemented command FIGD %02x\n", tag(),m_figs.m_figure_type);
+
+ reset_figs_param();
+ m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS;
+ break;
+
+ case COMMAND_GCHRD: /* graphics character draw and area filling start */
+ if(m_figs.m_figure_type == 2)
+ draw_char(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch));
+ else
+ printf("uPD7220 '%s' Unimplemented command GCHRD %02x\n", tag(),m_figs.m_figure_type);
+
+ reset_figs_param();
+ m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS;
+ break;
+
+ case COMMAND_RDAT: /* read data from display memory */
+ fifo_set_direction(FIFO_READ);
+
+ read_vram((m_cr & 0x18) >> 3,m_cr & 3);
+ reset_figs_param();
+
+ m_sr |= UPD7220_SR_DATA_READY;
+ break;
+
+ case COMMAND_CURD: /* cursor address read */
+ fifo_set_direction(FIFO_READ);
+
+ queue(m_ead & 0xff, 0);
+ queue((m_ead >> 8) & 0xff, 0);
+ queue(m_ead >> 16, 0);
+ queue(m_dad & 0xff, 0);
+ queue(m_dad >> 8, 0);
+
+ m_sr |= UPD7220_SR_DATA_READY;
+ break;
+
+ case COMMAND_LPRD: /* light pen address read */
+ fifo_set_direction(FIFO_READ);
+
+ queue(m_lad & 0xff, 0);
+ queue((m_lad >> 8) & 0xff, 0);
+ queue(m_lad >> 16, 0);
+
+ m_sr |= UPD7220_SR_DATA_READY;
+ m_sr &= ~UPD7220_SR_LIGHT_PEN_DETECT;
+ break;
+
+ case COMMAND_DMAR: /* DMA read request */
+ printf("uPD7220 '%s' Unimplemented command DMAR\n", tag());
+ break;
+
+ case COMMAND_DMAW: /* DMA write request */
+ printf("uPD7220 '%s' Unimplemented command DMAW\n", tag());
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( upd7220_device::read )
+{
+ UINT8 data;
+
+ if (offset & 1)
+ {
+ /* FIFO read */
+ int flag;
+ fifo_set_direction(FIFO_READ);
+ dequeue(&data, &flag);
+ }
+ else
+ {
+ /* status register */
+ data = m_sr;
+
+ /* TODO: timing of these */
+ m_sr &= ~UPD7220_SR_DRAWING_IN_PROGRESS;
+ m_sr &= ~UPD7220_SR_DMA_EXECUTE;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE8_MEMBER( upd7220_device::write )
+{
+ if (offset & 1)
+ {
+ /* command into FIFO */
+ fifo_set_direction(FIFO_WRITE);
+ queue(data, 1);
+ }
+ else
+ {
+ /* parameter into FIFO */
+// fifo_set_direction(FIFO_WRITE);
+ queue(data, 0);
+ }
+
+ process_fifo();
+}
+
+
+//-------------------------------------------------
+// dack_r -
+//-------------------------------------------------
+
+READ8_MEMBER( upd7220_device::dack_r )
+{
+ return 0;
+}
+
+
+//-------------------------------------------------
+// dack_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( upd7220_device::dack_w )
+{
+}
+
+
+//-------------------------------------------------
+// ext_sync_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( upd7220_device::ext_sync_w )
+{
+ //if (LOG) logerror("uPD7220 '%s' External Synchronization: %u\n", tag(), state);
+
+ if (state)
+ {
+ m_sr |= UPD7220_SR_VSYNC_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_VSYNC_ACTIVE;
+ }
+}
+
+
+//-------------------------------------------------
+// ext_sync_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( upd7220_device::lpen_w )
+{
+ /* only if 2 rising edges on the lpen input occur at the same
+ point during successive video fields are the pulses accepted */
+
+ /*
+
+ 1. compute the address of the location on the CRT
+ 2. compare with LAD
+ 3. if not equal move address to LAD
+ 4. if equal set LPEN DETECT flag to 1
+
+ */
+}
+
+
+//-------------------------------------------------
+// update_text -
+//-------------------------------------------------
+
+void upd7220_device::update_text(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT32 addr, sad;
+ UINT16 len;
+ int im, wd;
+ int y, sy = 0;
+
+ for (int area = 0; area < 4; area++)
+ {
+ get_text_partition(area, &sad, &len, &im, &wd);
+
+ for (y = sy; y < sy + len; y++)
+ {
+ addr = sad + (y * m_pitch);
+
+ if (m_draw_text_cb)
+ m_draw_text_cb(this, bitmap, addr, y, wd, m_pitch, 0, 0, m_aw * 8 - 1, m_al - 1, m_lr, m_dc, m_ead);
+ }
+
+ sy = y + 1;
+ }
+}
+
+
+//-------------------------------------------------
+// draw_graphics_line -
+//-------------------------------------------------
+
+void upd7220_device::draw_graphics_line(bitmap_ind16 &bitmap, UINT32 addr, int y, int wd)
+{
+ int sx;
+
+ for (sx = 0; sx < m_pitch * 2; sx++)
+ {
+ if((sx << 3) < m_aw * 16 && y < m_al)
+ m_display_cb(this, bitmap, y, sx << 3, addr);
+
+ if (wd) addr += 2; else addr++;
+ }
+}
+
+
+//-------------------------------------------------
+// update_graphics -
+//-------------------------------------------------
+
+void upd7220_device::update_graphics(bitmap_ind16 &bitmap, const rectangle &cliprect, int force_bitmap)
+{
+ UINT32 addr, sad;
+ UINT16 len;
+ int im, wd, area;
+ int y, tsy = 0, bsy = 0;
+
+ for (area = 0; area < 2; area++)
+ {
+ get_graphics_partition(area, &sad, &len, &im, &wd);
+
+ for (y = 0; y < len; y++)
+ {
+ if (im || force_bitmap)
+ {
+ addr = (sad & 0x3ffff) + (y * m_pitch * 2);
+
+ if (m_display_cb)
+ draw_graphics_line(bitmap, addr, y + bsy, wd);
+ }
+ else
+ {
+ /* TODO: text params are more limited compared to graphics */
+ addr = (sad & 0x3ffff) + (y * m_pitch);
+
+ if (m_draw_text_cb)
+ m_draw_text_cb(this, bitmap, addr, y + tsy, wd, m_pitch, 0, 0, m_aw * 8 - 1, len + bsy - 1, m_lr, m_dc, m_ead);
+ }
+ }
+
+ if (m_lr)
+ tsy += (y / m_lr);
+ bsy += y;
+ }
+}
+
+
+//-------------------------------------------------
+// update_screen -
+//-------------------------------------------------
+
+UINT32 upd7220_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ if (m_de)
+ {
+ switch (m_mode & UPD7220_MODE_DISPLAY_MASK)
+ {
+ case UPD7220_MODE_DISPLAY_MIXED:
+ update_graphics(bitmap, cliprect, 0);
+ break;
+
+ case UPD7220_MODE_DISPLAY_GRAPHICS:
+ update_graphics(bitmap, cliprect, 1);
+ break;
+
+ case UPD7220_MODE_DISPLAY_CHARACTER:
+ update_text(bitmap, cliprect);
+ break;
+
+ case UPD7220_MODE_DISPLAY_INVALID:
+ logerror("uPD7220 '%s' Invalid Display Mode!\n", tag());
+ }
+ }
+ return 0;
+}
diff --git a/src/mess/video/upd7220.h b/src/mess/video/upd7220.h
new file mode 100644
index 00000000000..abce3e43128
--- /dev/null
+++ b/src/mess/video/upd7220.h
@@ -0,0 +1,233 @@
+/**********************************************************************
+
+ NEC uPD7220 Graphics Display Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ 2xWCLK 1 |* \_/ | 40 Vcc
+ _DBIN 2 | | 39 A17
+ HSYNC 3 | | 38 A16
+ V/EXT SYNC 4 | | 37 AD15
+ BLANK 5 | | 36 AD14
+ ALE 6 | | 35 AD13
+ DRQ 7 | | 34 AD12
+ _DACK 8 | | 33 AD11
+ _RD 9 | | 32 AD10
+ _WR 10 | uPD7220 | 31 AD9
+ A0 11 | 82720 | 30 AD8
+ DB0 12 | | 29 AD7
+ DB1 13 | | 28 AD6
+ DB2 14 | | 27 AD5
+ DB3 15 | | 26 AD4
+ DB4 16 | | 25 AD3
+ DB5 17 | | 24 AD2
+ DB6 18 | | 23 AD1
+ DB7 19 | | 22 AD0
+ GND 20 |_____________| 21 LPEN
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __UPD7220__
+#define __UPD7220__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_UPD7220_ADD(_tag, _clock, _config, _map) \
+ MCFG_DEVICE_ADD(_tag, UPD7220, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_0, _map)
+
+#define UPD7220_INTERFACE(name) \
+ const upd7220_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+typedef void (*upd7220_display_pixels_func)(device_t *device, bitmap_ind16 &bitmap, int y, int x, UINT32 address);
+#define UPD7220_DISPLAY_PIXELS(name) void name(device_t *device, bitmap_ind16 &bitmap, int y, int x, UINT32 address)
+
+typedef void (*upd7220_draw_text_line)(device_t *device, bitmap_ind16 &bitmap, UINT32 addr, int y, int wd, int pitch,int screen_min_x,int screen_min_y,int screen_max_x, int screen_max_y,int lr, int cursor_on, int cursor_addr);
+#define UPD7220_DRAW_TEXT_LINE(name) void name(device_t *device, bitmap_ind16 &bitmap, UINT32 addr, int y, int wd, int pitch,int screen_min_x,int screen_min_y,int screen_max_x, int screen_max_y,int lr, int cursor_on, int cursor_addr)
+
+
+// ======================> upd7220_interface
+
+struct upd7220_interface
+{
+ const char *m_screen_tag;
+
+ upd7220_display_pixels_func m_display_cb;
+ upd7220_draw_text_line m_draw_text_cb;
+
+ devcb_write_line m_out_drq_cb;
+ devcb_write_line m_out_hsync_cb;
+ devcb_write_line m_out_vsync_cb;
+ devcb_write_line m_out_blank_cb;
+};
+
+// ======================> upd7220_device
+
+class upd7220_device : public device_t,
+ public device_memory_interface,
+ public upd7220_interface
+{
+public:
+ // construction/destruction
+ upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+ DECLARE_READ8_MEMBER( dack_r );
+ DECLARE_WRITE8_MEMBER( dack_w );
+
+ DECLARE_WRITE_LINE_MEMBER( ext_sync_w );
+ DECLARE_WRITE_LINE_MEMBER( lpen_w );
+
+ DECLARE_WRITE8_MEMBER( bank_w );
+ DECLARE_READ8_MEMBER( vram_r );
+ DECLARE_WRITE8_MEMBER( vram_w );
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ virtual const rom_entry *device_rom_region() const;
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_config_complete();
+
+private:
+ static const device_timer_id TIMER_VSYNC = 0;
+ static const device_timer_id TIMER_HSYNC = 1;
+ static const device_timer_id TIMER_BLANK = 2;
+
+ inline UINT8 readbyte(offs_t address);
+ inline void writebyte(offs_t address, UINT8 data);
+ inline void fifo_clear();
+ inline int fifo_param_count();
+ inline void fifo_set_direction(int dir);
+ inline void queue(UINT8 data, int flag);
+ inline void dequeue(UINT8 *data, int *flag);
+ inline void update_vsync_timer(int state);
+ inline void update_hsync_timer(int state);
+ inline void update_blank_timer(int state);
+ inline void recompute_parameters();
+ inline void reset_figs_param();
+ inline void advance_ead();
+ inline void read_vram(UINT8 type, UINT8 mod);
+ inline void write_vram(UINT8 type, UINT8 mod);
+ inline UINT16 check_pattern(UINT16 pattern);
+ inline void get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd);
+ inline void get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd);
+
+ void draw_pixel(int x, int y, UINT16 tile_data);
+ void draw_line(int x, int y);
+ void draw_rectangle(int x, int y);
+ void draw_char(int x, int y);
+ int translate_command(UINT8 data);
+ void process_fifo();
+ void update_text(bitmap_ind16 &bitmap, const rectangle &cliprect);
+ void draw_graphics_line(bitmap_ind16 &bitmap, UINT32 addr, int y, int wd);
+ void update_graphics(bitmap_ind16 &bitmap, const rectangle &cliprect, int force_bitmap);
+
+ devcb_resolved_write_line m_out_drq_func;
+ devcb_resolved_write_line m_out_hsync_func;
+ devcb_resolved_write_line m_out_vsync_func;
+ devcb_resolved_write_line m_out_blank_func;
+
+ screen_device *m_screen;
+
+ UINT16 m_mask; // mask register
+ UINT8 m_pitch; // number of word addresses in display memory in the horizontal direction
+ UINT32 m_ead; // execute word address
+ UINT16 m_dad; // dot address within the word
+ UINT32 m_lad; // light pen address
+
+ UINT8 m_ra[16]; // parameter RAM
+ int m_ra_addr; // parameter RAM address
+
+ UINT8 m_sr; // status register
+ UINT8 m_cr; // command register
+ UINT8 m_pr[17]; // parameter byte register
+ int m_param_ptr; // parameter pointer
+
+ UINT8 m_fifo[16]; // FIFO data queue
+ int m_fifo_flag[16]; // FIFO flag queue
+ int m_fifo_ptr; // FIFO pointer
+ int m_fifo_dir; // FIFO direction
+
+ UINT8 m_mode; // mode of operation
+ UINT8 m_draw_mode; // mode of drawing
+
+ int m_de; // display enabled
+ int m_m; // 0 = accept external vertical sync (slave mode) / 1 = generate & output vertical sync (master mode)
+ int m_aw; // active display words per line - 2 (must be even number with bit 0 = 0)
+ int m_al; // active display lines per video field
+ int m_vs; // vertical sync width - 1
+ int m_vfp; // vertical front porch width - 1
+ int m_vbp; // vertical back porch width - 1
+ int m_hs; // horizontal sync width - 1
+ int m_hfp; // horizontal front porch width - 1
+ int m_hbp; // horizontal back porch width - 1
+
+ int m_dc; // display cursor
+ int m_sc; // 0 = blinking cursor / 1 = steady cursor
+ int m_br; // blink rate
+ int m_ctop; // cursor top line number in the row
+ int m_cbot; // cursor bottom line number in the row (CBOT < LR)
+ int m_lr; // lines per character row - 1
+
+ int m_disp; // display zoom factor
+ int m_gchr; // zoom factor for graphics character writing and area filling
+
+ UINT8 m_bitmap_mod;
+
+ struct {
+ UINT8 m_dir; // figs param 0: drawing direction
+ UINT8 m_figure_type; // figs param 1: figure type
+ UINT16 m_dc; // figs param 2:
+ UINT16 m_d; // figs param 3:
+ UINT16 m_d1; // figs param 4:
+ UINT16 m_d2; // figs param 5:
+ UINT16 m_dm; // figs param 6:
+ } m_figs;
+
+ // timers
+ emu_timer *m_vsync_timer; // vertical sync timer
+ emu_timer *m_hsync_timer; // horizontal sync timer
+ emu_timer *m_blank_timer; // CRT blanking timer
+
+ const address_space_config m_space_config;
+};
+
+
+// device type definition
+extern const device_type UPD7220;
+
+
+
+#endif
diff --git a/src/mess/video/ut88.c b/src/mess/video/ut88.c
new file mode 100644
index 00000000000..3d77ad5caea
--- /dev/null
+++ b/src/mess/video/ut88.c
@@ -0,0 +1,44 @@
+/***************************************************************************
+
+ UT88 video driver by Miodrag Milanovic
+
+ 06/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "includes/ut88.h"
+
+
+const gfx_layout ut88_charlayout =
+{
+ 8, 8, /* 8x8 characters */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ {0}, /* no bitplanes; 1 bit per pixel */
+ {0, 1, 2, 3, 4, 5, 6, 7},
+ {0 * 8, 1 * 8, 2 * 8, 3 * 8, 4 * 8, 5 * 8, 6 * 8, 7 * 8},
+ 8*8 /* size of one char */
+};
+
+VIDEO_START( ut88 )
+{
+}
+
+SCREEN_UPDATE_IND16( ut88 )
+{
+ ut88_state *state = screen.machine().driver_data<ut88_state>();
+ int x,y;
+
+ for(y = 0; y < 28; y++ )
+ {
+ for(x = 0; x < 64; x++ )
+ {
+ int code = state->m_p_videoram[ x + y*64 ] & 0x7f;
+ int attr = state->m_p_videoram[ x+1 + y*64 ] & 0x80;
+ drawgfx_opaque(bitmap, cliprect, screen.machine().gfx[0], code | attr, 0, 0,0, x*8,y*8);
+ }
+ }
+ return 0;
+}
+
diff --git a/src/mess/video/uv201.c b/src/mess/video/uv201.c
new file mode 100644
index 00000000000..b38a7223220
--- /dev/null
+++ b/src/mess/video/uv201.c
@@ -0,0 +1,603 @@
+/**********************************************************************
+
+ VideoBrain UV201/UV202 video chip emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "uv201.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+
+// screen parameters
+#define SCREEN_WIDTH 232
+#define SCREEN_HEIGHT 262
+#define VISAREA_WIDTH 193
+#define VBLANK_WIDTH 21
+#define HBLANK_WIDTH 39
+#define HSYNC_WIDTH 18
+#define HFP_WIDTH 16
+#define HBP_WIDTH 5
+#define HBLANK_END HSYNC_WIDTH + HFP_WIDTH
+#define HBLANK_START HBLANK_END + VISAREA_WIDTH
+
+
+// write-only registers
+#define REGISTER_COMMAND 0xf7
+#define REGISTER_BACKGROUND 0xf5
+#define REGISTER_FINAL_MODIFIER 0xf2
+#define REGISTER_Y_INTERRUPT 0xf0
+
+
+// read-only registers
+#define REGISTER_X_FREEZE 0xf8
+#define REGISTER_Y_FREEZE_LOW 0xf9
+#define REGISTER_Y_FREEZE_HIGH 0xfa
+#define REGISTER_CURRENT_Y_LOW 0xfb
+
+
+// read/write registers - RAM memory
+#define RAM_RP_LO 0x00 // cartridge pointer low order
+#define RAM_RP_HI_COLOR 0x10 // cartridge pointer high order and color
+#define RAM_DX_INT_XCOPY 0x20 // dX, intensity, X-copy
+#define RAM_DY 0x30 // dY
+#define RAM_X 0x40 // X value
+#define RAM_Y_LO_A 0x50 // Y value low order list A
+#define RAM_Y_LO_B 0x60 // Y value low order list B
+#define RAM_XY_HI_A 0x70 // Y value high order and X order list A
+#define RAM_XY_HI_B 0x80 // Y value high order and X order list B
+
+
+// command register bits
+#define COMMAND_YINT_H_O 0x80
+#define COMMAND_A_B 0x40
+#define COMMAND_Y_ZM 0x20
+#define COMMAND_KBD 0x10
+#define COMMAND_INT 0x08
+#define COMMAND_ENB 0x04
+#define COMMAND_FRZ 0x02
+#define COMMAND_X_ZM 0x01
+
+
+#define IS_CHANGED(_bit) \
+ ((m_cmd & _bit) != (data & _bit))
+
+#define RAM(_offset) \
+ m_ram[_offset + i]
+
+#define RAM_XORD(_offset) \
+ m_ram[_offset + xord]
+
+#define IS_VISIBLE(_y) \
+ ((_y >= cliprect.min_y) && (_y <= cliprect.max_y))
+
+#define DRAW_PIXEL(_scanline, _dot) \
+ if (IS_VISIBLE(_scanline)) bitmap.pix16((_scanline), HSYNC_WIDTH + HFP_WIDTH + _dot) = pixel;
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+// device type definition
+const device_type UV201 = &device_creator<uv201_device>;
+
+
+//-------------------------------------------------
+// uv201_device - constructor
+//-------------------------------------------------
+
+uv201_device::uv201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, UV201, "UV201", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void uv201_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const uv201_interface *intf = reinterpret_cast<const uv201_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<uv201_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_ext_int_cb, 0, sizeof(m_out_ext_int_cb));
+ memset(&m_out_hblank_cb, 0, sizeof(m_out_hblank_cb));
+ memset(&m_in_db_cb, 0, sizeof(m_in_db_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void uv201_device::device_start()
+{
+ // resolve callbacks
+ m_out_ext_int_func.resolve(m_out_ext_int_cb, *this);
+ m_out_hblank_func.resolve(m_out_hblank_cb, *this);
+ m_in_db_func.resolve(m_in_db_cb, *this);
+
+ // allocate timers
+ m_timer_y_odd = timer_alloc(TIMER_Y_ODD);
+ m_timer_y_even = timer_alloc(TIMER_Y_EVEN);
+ m_timer_hblank_on = timer_alloc(TIMER_HBLANK_ON);
+ m_timer_hblank_off = timer_alloc(TIMER_HBLANK_OFF);
+
+ // find devices
+ m_screen = machine().device<screen_device>(m_screen_tag);
+
+ initialize_palette();
+
+ // state saving
+ save_item(NAME(m_ram));
+ save_item(NAME(m_y_int));
+ save_item(NAME(m_fmod));
+ save_item(NAME(m_bg));
+ save_item(NAME(m_cmd));
+ save_item(NAME(m_freeze_x));
+ save_item(NAME(m_freeze_y));
+ save_item(NAME(m_field));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void uv201_device::device_reset()
+{
+ m_out_ext_int_func(CLEAR_LINE);
+
+ m_out_hblank_func(1);
+ m_timer_hblank_off->adjust(attotime::from_ticks( HBLANK_END, m_clock ));
+}
+
+
+//-------------------------------------------------
+// device_timer - handle timer events
+//-------------------------------------------------
+
+void uv201_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ int scanline = m_screen->vpos();
+
+ switch (id)
+ {
+ case TIMER_Y_ODD:
+ case TIMER_Y_EVEN:
+ if ((m_cmd & COMMAND_INT) && !(m_cmd & COMMAND_FRZ))
+ {
+ if (LOG) logerror("Y-Interrupt at scanline %u\n", scanline);
+
+ m_freeze_y = scanline;
+
+ m_out_ext_int_func(ASSERT_LINE);
+ m_out_ext_int_func(CLEAR_LINE);
+ }
+ break;
+
+ case TIMER_HBLANK_ON:
+ m_out_hblank_func(1);
+
+ m_timer_hblank_off->adjust(attotime::from_ticks( HBLANK_WIDTH, m_clock ) );
+ break;
+
+ case TIMER_HBLANK_OFF:
+ m_out_hblank_func(0);
+
+ m_timer_hblank_on->adjust(attotime::from_ticks( VISAREA_WIDTH, m_clock ) );
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// initialize_palette -
+//-------------------------------------------------
+
+void uv201_device::initialize_palette()
+{
+ UINT8 offlointensity = 0x00;
+ UINT8 offhiintensity = 0xc0;
+
+ UINT8 onlointensity = 0xa0;
+ UINT8 onhiintensity = 0xff;
+
+ for (int i = 0; i < 4; i++)
+ {
+ int offset = i * 8;
+ UINT8 onvalue, offvalue;
+
+ if (offset < 16)
+ {
+ offvalue = offlointensity;
+ onvalue = onlointensity;
+ }
+ else
+ {
+ offvalue = offhiintensity;
+ onvalue = onhiintensity;
+ }
+
+ palette_set_color_rgb(machine(), offset + 0, offvalue, offvalue, offvalue); // black
+ palette_set_color_rgb(machine(), offset + 1, onvalue, offvalue, offvalue); // red
+ palette_set_color_rgb(machine(), offset + 2, offvalue, onvalue, offvalue); // green
+ palette_set_color_rgb(machine(), offset + 3, onvalue, onvalue, offvalue); // red-green
+ palette_set_color_rgb(machine(), offset + 4, offvalue, offvalue, onvalue); // blue
+ palette_set_color_rgb(machine(), offset + 5, onvalue, offvalue, onvalue); // red-blue
+ palette_set_color_rgb(machine(), offset + 6, offvalue, onvalue, onvalue); // green-blue
+ palette_set_color_rgb(machine(), offset + 7, onvalue, onvalue, onvalue); // white
+ }
+}
+
+
+//-------------------------------------------------
+// get_field_vpos - get scanline within field
+//-------------------------------------------------
+
+int uv201_device::get_field_vpos()
+{
+ int vpos = m_screen->vpos();
+
+ if (vpos >= SCREEN_HEIGHT)
+ {
+ // even field
+ vpos -= SCREEN_HEIGHT;
+ }
+
+ return vpos;
+}
+
+
+//-------------------------------------------------
+// get_field - get video field
+//-------------------------------------------------
+
+int uv201_device::get_field()
+{
+ return m_screen->vpos() < SCREEN_HEIGHT;
+}
+
+
+//-------------------------------------------------
+// set_y_interrupt - set Y interrupt timer
+//-------------------------------------------------
+
+void uv201_device::set_y_interrupt()
+{
+ int scanline = ((m_cmd & COMMAND_YINT_H_O) << 1) | m_y_int;
+
+ m_timer_y_odd->adjust(m_screen->time_until_pos(scanline), 0, m_screen->frame_period());
+ //m_timer_y_even->adjust(m_screen->time_until_pos(scanline + SCREEN_HEIGHT), 0, m_screen->frame_period());
+}
+
+
+//-------------------------------------------------
+// do_partial_update - update screen
+//-------------------------------------------------
+
+void uv201_device::do_partial_update()
+{
+ int vpos = m_screen->vpos();
+
+ if (LOG) logerror("Partial screen update at scanline %u\n", vpos);
+
+ m_screen->update_partial(vpos);
+}
+
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( uv201_device::read )
+{
+ UINT8 data = 0xff;
+
+ switch (offset)
+ {
+ case REGISTER_X_FREEZE:
+ data = m_freeze_x;
+
+ if (LOG) logerror("X-Freeze %02x\n", data);
+ break;
+
+ case REGISTER_Y_FREEZE_LOW:
+ data = m_freeze_y & 0xff;
+
+ if (LOG) logerror("Y-Freeze Low %02x\n", data);
+ break;
+
+ case REGISTER_Y_FREEZE_HIGH:
+ /*
+
+ bit signal description
+
+ 0 Y-F8 Y freeze high order (MSB) bit
+ 1 Y-C8 current Y counter high order (MSB) bit
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7 O/_E odd/even field
+
+ */
+
+ data = (get_field() << 7) | (BIT(get_field_vpos(), 8) << 1) | BIT(m_freeze_y, 8);
+
+ if (LOG) logerror("Y-Freeze High %02x\n", data);
+ break;
+
+ case REGISTER_CURRENT_Y_LOW:
+ data = get_field_vpos() & 0xff;
+
+ if (LOG) logerror("Current-Y Low %02x\n", data);
+ break;
+
+ default:
+ if (offset < 0x90)
+ data = m_ram[offset];
+ else
+ if (LOG) logerror("Unknown VLSI read from %02x!\n", offset);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE8_MEMBER( uv201_device::write )
+{
+ switch (offset)
+ {
+ case REGISTER_Y_INTERRUPT:
+ if (LOG) logerror("Y-Interrupt %02x\n", data);
+
+ if (m_y_int != data)
+ {
+ m_y_int = data;
+ set_y_interrupt();
+ }
+ break;
+
+ case REGISTER_FINAL_MODIFIER:
+ /*
+
+ bit signal description
+
+ 0 RED red
+ 1 GREEN green
+ 2 BLUE blue
+ 3 INT 0 intensity 0
+ 4 INT 1 intensity 1
+ 5 not used
+ 6 not used
+ 7 not used
+
+ */
+
+ if (LOG) logerror("Final Modifier %02x\n", data);
+
+ do_partial_update();
+ m_fmod = data & 0x1f;
+ break;
+
+ case REGISTER_BACKGROUND:
+ /*
+
+ bit signal description
+
+ 0 RED red
+ 1 GREEN green
+ 2 BLUE blue
+ 3 INT 0 intensity 0
+ 4 INT 1 intensity 1
+ 5 not used
+ 6 not used
+ 7 not used
+
+ */
+
+ if (LOG) logerror("Background %02x\n", data);
+
+ do_partial_update();
+ m_bg = data & 0x1f;
+ break;
+
+ case REGISTER_COMMAND:
+ /*
+
+ bit signal description
+
+ 0 X-ZM X zoom
+ 1 FRZ freeze
+ 2 ENB video enable
+ 3 INT interrupt enable
+ 4 KBD general purpose output
+ 5 Y-ZM Y zoom
+ 6 A/_B list selection
+ 7 YINT H.O. Y COMMAND_INT register high order bit
+
+ */
+
+ if (LOG) logerror("Command %02x\n", data);
+
+ if (IS_CHANGED(COMMAND_YINT_H_O))
+ {
+ set_y_interrupt();
+ }
+
+ if (IS_CHANGED(COMMAND_A_B) || IS_CHANGED(COMMAND_Y_ZM) || IS_CHANGED(COMMAND_X_ZM))
+ {
+ do_partial_update();
+ }
+
+ m_cmd = data;
+ break;
+
+ default:
+ if (offset < 0x90)
+ m_ram[offset] = data;
+ else
+ logerror("Unknown VLSI write %02x to %02x!\n", data, offset);
+ }
+}
+
+
+//-------------------------------------------------
+// ext_int_w - external interrupt write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( uv201_device::ext_int_w )
+{
+ if (!state && (m_cmd & COMMAND_FRZ))
+ {
+ m_freeze_y = get_field_vpos();
+ m_freeze_x = m_screen->hpos();
+ }
+}
+
+
+//-------------------------------------------------
+// kbd_r - keyboard select read
+//-------------------------------------------------
+
+READ_LINE_MEMBER( uv201_device::kbd_r )
+{
+ return (m_cmd & COMMAND_KBD) ? 1 : 0;
+}
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+UINT32 uv201_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(get_black_pen(machine()), cliprect);
+
+ if (!(m_cmd & COMMAND_ENB))
+ {
+ return 0;
+ }
+
+ for (int y = 0; y < SCREEN_HEIGHT; y++)
+ {
+ for (int x = 0; x < VISAREA_WIDTH; x++)
+ {
+ int pixel = m_bg;
+ DRAW_PIXEL(y, x);
+ }
+ }
+
+ for (int i = 0; i < 16; i++)
+ {
+ UINT8 xy_hi = (m_cmd & COMMAND_A_B) ? RAM(RAM_XY_HI_A) : RAM(RAM_XY_HI_B);
+ UINT8 y_lo = (m_cmd & COMMAND_A_B) ? RAM(RAM_Y_LO_A) : RAM(RAM_Y_LO_B);
+ UINT16 y = (BIT(xy_hi, 7) << 8) | y_lo;
+ int xord = xy_hi & 0x0f;
+
+ UINT8 rp_hi_color = RAM_XORD(RAM_RP_HI_COLOR);
+ UINT8 rp_lo = RAM_XORD(RAM_RP_LO);
+ UINT16 rp = ((rp_hi_color << 8) | rp_lo) & 0x1fff;
+
+ if (rp < 0x800) rp |= 0x2000;
+
+ UINT8 dx_int_xcopy = RAM_XORD(RAM_DX_INT_XCOPY);
+ int color = ((dx_int_xcopy & 0x60) >> 2) | (BIT(rp_hi_color, 5) << 2) | (BIT(rp_hi_color, 6) << 1) | (BIT(rp_hi_color, 7));
+ UINT8 dx = dx_int_xcopy & 0x1f;
+ UINT8 dy = RAM_XORD(RAM_DY);
+ int xcopy = BIT(dx_int_xcopy, 7);
+ UINT8 x = RAM_XORD(RAM_X);
+
+ if (LOG) logerror("Object %u xord %u y %u x %u dy %u dx %u xcopy %u color %u rp %04x\n", i, xord, y, x, dy, dx, xcopy, color, rp);
+
+ if (rp == 0) continue;
+ if (y > SCREEN_HEIGHT) continue;
+
+ for (int sy = 0; sy < dy; sy++)
+ {
+ for (int sx = 0; sx < dx; sx++)
+ {
+ UINT8 data = m_in_db_func(rp);
+
+ for (int bit = 0; bit < 8; bit++)
+ {
+ int pixel = ((BIT(data, 7) ? color : m_bg) ^ m_fmod) & 0x1f;
+
+ if (m_cmd & COMMAND_Y_ZM)
+ {
+ int scanline = y + (sy * 2);
+
+ if (m_cmd & COMMAND_X_ZM)
+ {
+ int dot = (x * 2) + (sx * 16) + (bit * 2);
+
+ DRAW_PIXEL(scanline, dot);
+ DRAW_PIXEL(scanline, dot + 1);
+ DRAW_PIXEL(scanline + 1, dot);
+ DRAW_PIXEL(scanline + 1, dot + 1);
+ }
+ else
+ {
+ int dot = x + (sx * 8) + bit;
+
+ DRAW_PIXEL(scanline, dot);
+ DRAW_PIXEL(scanline + 1, dot);
+ }
+ }
+ else
+ {
+ int scanline = y + sy;
+
+ if (m_cmd & COMMAND_X_ZM)
+ {
+ int dot = (x * 2) + (sx * 16) + (bit * 2);
+
+ DRAW_PIXEL(scanline, dot);
+ DRAW_PIXEL(scanline, dot + 1);
+ }
+ else
+ {
+ int dot = x + (sx * 8) + bit;
+
+ DRAW_PIXEL(scanline, dot);
+ }
+ }
+
+ data <<= 1;
+ }
+
+ if (!xcopy) rp++;
+ }
+
+ if (xcopy) rp++;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/mess/video/uv201.h b/src/mess/video/uv201.h
new file mode 100644
index 00000000000..d5914e9a74b
--- /dev/null
+++ b/src/mess/video/uv201.h
@@ -0,0 +1,165 @@
+/**********************************************************************
+
+ VideoBrain UV201/UV202 video chip emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ GND 1 |* \_/ | 40
+ G 2 | | 39
+ I 3 | | 38 RESET
+ B 4 | | 37 BRC
+ R 5 | | 36
+ BA0 6 | | 35 B1 STROBE
+ BA1 7 | | 34 COLOR XTAL (3.636 MHz)
+ BA2 8 | | 33
+ BA3 9 | | 32
+ BA4 10 | UV201 | 31
+ BA5 11 | | 30 EXTINT
+ BA6 12 | | 29 O/E
+ BA7 13 | | 28 BO7
+ BA8 14 | | 27 BO6
+ BA9 15 | | 26 BO5
+ BA10 16 | | 25 BO4
+ BA11 17 | | 24 BO3
+ BA12 18 | | 23 BO2
+ HSYNC 19 | | 22 BO1
+ HSYNC 20 |_____________| 21 BO0
+
+ _____ _____
+ 1 |* \_/ | 40 B1 STROBE
+ 2 | | 39 CPU RQ1
+ CPU RQ0 3 | | 38 GND
+ XTAL IN 4 | | 37
+ XTAL IN 5 | | 36 RESET
+ 6 | | 35
+ CPU phi 7 | | 34 COLOR XTAL
+ 8 | | 33 BRC
+ BD0 9 | | 32 BD7
+ BO0 10 | UV202 | 31 BO7
+ BD1 11 | | 30 BD6
+ BO1 12 | | 29 BO6
+ BD2 13 | | 28 BD5
+ BO2 14 | | 27 BO5
+ BD3 15 | | 26 BD4
+ BO3 16 | | 25 BO4
+ HBLANK 17 | | 24
+ 18 | | 23
+ 19 | | 22
+ 20 |_____________| 21
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __UV201__
+#define __UV201__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_UV201_ADD(_tag, _screen_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, UV201, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_SCREEN_ADD(_screen_tag, RASTER) \
+ MCFG_SCREEN_UPDATE_DEVICE(_tag, uv201_device, screen_update) \
+ MCFG_SCREEN_RAW_PARAMS(_clock, 232, 18, 232, 262, 21, 262) \
+ MCFG_PALETTE_LENGTH(32)
+
+
+#define UV201_INTERFACE(name) \
+ const uv201_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> uv201_interface
+
+struct uv201_interface
+{
+ const char *m_screen_tag;
+
+ devcb_write_line m_out_ext_int_cb;
+ devcb_write_line m_out_hblank_cb;
+ devcb_read8 m_in_db_cb;
+};
+
+
+// ======================> uv201_device
+
+class uv201_device : public device_t,
+ public uv201_interface
+{
+public:
+ // construction/destruction
+ uv201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+ DECLARE_WRITE_LINE_MEMBER( ext_int_w );
+ DECLARE_READ_LINE_MEMBER( kbd_r );
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ enum
+ {
+ TIMER_Y_ODD,
+ TIMER_Y_EVEN,
+ TIMER_HBLANK_ON,
+ TIMER_HBLANK_OFF
+ };
+
+ void initialize_palette();
+ int get_field_vpos();
+ int get_field();
+ void set_y_interrupt();
+ void do_partial_update();
+
+ devcb_resolved_write_line m_out_ext_int_func;
+ devcb_resolved_write_line m_out_hblank_func;
+ devcb_resolved_read8 m_in_db_func;
+
+ screen_device *m_screen;
+
+ UINT8 m_ram[0x90];
+ UINT8 m_y_int;
+ UINT8 m_fmod;
+ UINT8 m_bg;
+ UINT8 m_cmd;
+ UINT8 m_freeze_x;
+ UINT16 m_freeze_y;
+ int m_field;
+
+ // timers
+ emu_timer *m_timer_y_odd;
+ emu_timer *m_timer_y_even;
+ emu_timer *m_timer_hblank_on;
+ emu_timer *m_timer_hblank_off;
+};
+
+
+// device type definition
+extern const device_type UV201;
+
+
+
+#endif
diff --git a/src/mess/video/v1050.c b/src/mess/video/v1050.c
new file mode 100644
index 00000000000..21be3cf250b
--- /dev/null
+++ b/src/mess/video/v1050.c
@@ -0,0 +1,147 @@
+#include "includes/v1050.h"
+
+/*
+
+ TODO:
+
+ - bright in reverse video
+
+*/
+
+#define V1050_ATTR_BRIGHT 0x01
+#define V1050_ATTR_BLINKING 0x02
+#define V1050_ATTR_ATTEN 0x04
+#define V1050_ATTR_REVERSE 0x10
+#define V1050_ATTR_BLANK 0x20
+#define V1050_ATTR_BOLD 0x40
+#define V1050_ATTR_BLINK 0x80
+
+/* Video RAM Access */
+
+READ8_MEMBER( v1050_state::attr_r )
+{
+ return m_attr;
+}
+
+WRITE8_MEMBER( v1050_state::attr_w )
+{
+ m_attr = data;
+}
+
+READ8_MEMBER( v1050_state::videoram_r )
+{
+ if (offset >= 0x2000)
+ {
+ m_attr = (m_attr & 0xfc) | (m_attr_ram[offset] & 0x03);
+ }
+
+ return m_video_ram[offset];
+}
+
+WRITE8_MEMBER( v1050_state::videoram_w )
+{
+ m_video_ram[offset] = data;
+
+ if (offset >= 0x2000 && BIT(m_attr, 2))
+ {
+ m_attr_ram[offset] = m_attr & 0x03;
+ }
+}
+
+/* MC6845 Interface */
+
+static MC6845_UPDATE_ROW( v1050_update_row )
+{
+ v1050_state *state = device->machine().driver_data<v1050_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ int column, bit;
+
+ for (column = 0; column < x_count; column++)
+ {
+ UINT16 address = (((ra & 0x03) + 1) << 13) | ((ma & 0x1fff) + column);
+ UINT8 data = state->m_video_ram[address & V1050_VIDEORAM_MASK];
+ UINT8 attr = (state->m_attr & 0xfc) | (state->m_attr_ram[address] & 0x03);
+
+ for (bit = 0; bit < 8; bit++)
+ {
+ int x = (column * 8) + bit;
+ int color = BIT(data, 7);
+
+ /* blinking */
+ if ((attr & V1050_ATTR_BLINKING) && !(attr & V1050_ATTR_BLINK)) color = 0;
+
+ /* reverse video */
+ color ^= BIT(attr, 4);
+
+ /* bright */
+ if (color && (!(attr & V1050_ATTR_BOLD) ^ (attr & V1050_ATTR_BRIGHT))) color = 2;
+
+ /* display blank */
+ if (attr & V1050_ATTR_BLANK) color = 0;
+
+ bitmap.pix32(y, x) = palette[color];
+
+ data <<= 1;
+ }
+ }
+}
+
+WRITE_LINE_MEMBER( v1050_state::crtc_vs_w )
+{
+ device_set_input_line(m_subcpu, INPUT_LINE_IRQ0, state ? ASSERT_LINE : CLEAR_LINE);
+
+ set_interrupt(INT_VSYNC, state);
+}
+
+static const mc6845_interface crtc_intf =
+{
+ SCREEN_TAG,
+ 8,
+ NULL,
+ v1050_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(v1050_state, crtc_vs_w),
+ NULL
+};
+
+/* Palette */
+
+static PALETTE_INIT( v1050 )
+{
+ palette_set_color(machine, 0, RGB_BLACK); /* black */
+ palette_set_color_rgb(machine, 1, 0x00, 0xc0, 0x00); /* green */
+ palette_set_color_rgb(machine, 2, 0x00, 0xff, 0x00); /* bright green */
+}
+
+/* Video Start */
+
+void v1050_state::video_start()
+{
+ /* allocate memory */
+ m_attr_ram = auto_alloc_array(machine(), UINT8, V1050_VIDEORAM_SIZE);
+
+ /* register for state saving */
+ save_item(NAME(m_attr));
+ save_pointer(NAME(m_attr_ram), V1050_VIDEORAM_SIZE);
+}
+
+/* Machine Drivers */
+
+MACHINE_CONFIG_FRAGMENT( v1050_video )
+ MCFG_MC6845_ADD(H46505_TAG, H46505, XTAL_15_36MHz/8, crtc_intf)
+
+ MCFG_SCREEN_ADD(SCREEN_TAG, RASTER)
+ MCFG_SCREEN_UPDATE_DEVICE(H46505_TAG, h46505_device, screen_update)
+
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_SIZE(640, 400)
+ MCFG_SCREEN_VISIBLE_AREA(0,640-1, 0, 400-1)
+
+ MCFG_PALETTE_LENGTH(3)
+ MCFG_PALETTE_INIT(v1050)
+MACHINE_CONFIG_END
diff --git a/src/mess/video/vc4000.c b/src/mess/video/vc4000.c
new file mode 100644
index 00000000000..ccf85be6dc3
--- /dev/null
+++ b/src/mess/video/vc4000.c
@@ -0,0 +1,655 @@
+
+#include "includes/vc4000.h"
+
+
+/*
+ emulation of signetics 2636 video/audio device
+
+ seams to me like a special microcontroller
+ mask programmed
+
+ note about mame s2636 emulation:
+ less encapsuled
+ missing grid, sound generation, retriggered sprites, paddle reading, score display
+ not "rasterline" based
+ */
+
+#define STICKCENTRE (105)
+#define STICKLOW (20)
+#define STICKHIGH (225)
+
+#define VC4000_END_LINE (269)
+
+
+
+VIDEO_START(vc4000)
+{
+ vc4000_state *state = machine.driver_data<vc4000_state>();
+ screen_device *screen = machine.first_screen();
+ int i;
+
+ for (i=0;i<0x20; i++)
+ {
+ state->m_sprite_collision[i]=0;
+ if ((i&3)==3) state->m_sprite_collision[i]|=0x20;
+ if ((i&5)==5) state->m_sprite_collision[i]|=0x10;
+ if ((i&9)==9) state->m_sprite_collision[i]|=8;
+ if ((i&6)==6) state->m_sprite_collision[i]|=4;
+ if ((i&0xa)==0xa) state->m_sprite_collision[i]|=2;
+ if ((i&0xc)==0xc) state->m_sprite_collision[i]|=1;
+ state->m_background_collision[i]=0;
+ if ((i&0x11)==0x11) state->m_background_collision[i]|=0x80;
+ if ((i&0x12)==0x12) state->m_background_collision[i]|=0x40;
+ if ((i&0x14)==0x14) state->m_background_collision[i]|=0x20;
+ if ((i&0x18)==0x18) state->m_background_collision[i]|=0x10;
+ }
+
+ state->m_joy1_x = STICKCENTRE;
+ state->m_joy1_y = STICKCENTRE;
+ state->m_joy2_x = STICKCENTRE;
+ state->m_joy2_y = STICKCENTRE;
+
+ memset(&state->m_video, 0, sizeof(state->m_video));
+ for (i=0; i<3; i++)
+ {
+ state->m_video.sprites[i].data = &state->m_video.reg.d.sprites[i];
+ state->m_video.sprites[i].mask = 1 << i;
+ }
+ state->m_video.sprites[3].data = &state->m_video.reg.d.sprite4;
+ state->m_video.sprites[3].mask = 1 << 3;
+
+ state->m_bitmap = auto_bitmap_ind16_alloc(machine, screen->width(), screen->height());
+}
+
+INLINE UINT8 vc4000_joystick_return_to_centre(UINT8 joy)
+{
+ UINT8 data;
+
+ if (joy > (STICKCENTRE+5))
+ data=joy-5;
+ else
+ if (joy < (STICKCENTRE-5))
+ data=joy+5;
+ else
+ data=105;
+
+ return data;
+}
+
+READ8_MEMBER( vc4000_state::vc4000_video_r )
+{
+ UINT8 data=0;
+ if (offset > 0xcf) offset &= 0xcf; // c0-cf is mirrored at d0-df, e0-ef, f0-ff
+ switch (offset)
+ {
+ case 0xca: // Background-sprite collision (bit 7-4) and sprite finished (bit 3-0)
+ data |= m_video.background_collision;
+ m_video.background_collision=0;
+ if (m_video.sprites[3].finished)
+ {
+ data |= 1;
+ m_video.sprites[3].finished = FALSE;
+ }
+
+ if (m_video.sprites[2].finished)
+ {
+ data |= 2;
+ m_video.sprites[2].finished = FALSE;
+ }
+ if (m_video.sprites[1].finished)
+ {
+ data |= 4;
+ m_video.sprites[1].finished = FALSE;
+ }
+ if (m_video.sprites[0].finished)
+ {
+ data |= 8;
+ m_video.sprites[0].finished = FALSE;
+ }
+ break;
+
+ case 0xcb: // VRST-Flag (bit 6) and intersprite collision (bit5-0)
+ data = m_video.sprite_collision | (m_video.reg.d.sprite_collision & 0xc0);
+ m_video.sprite_collision = 0;
+ m_video.reg.d.sprite_collision &= 0xbf;
+ break;
+
+#ifndef ANALOG_HACK
+ case 0xcc:
+ if (!activecpu_get_reg(S2650_FO)) data=ioport("JOY1_X")->read();
+ else data=ioport("JOY1_Y")->read();
+ break;
+ case 0xcd:
+ if (!activecpu_get_reg(S2650_FO)) data=ioport("JOY2_X")->read();
+ else data=ioport("JOY2_Y")->read();
+ break;
+#else
+
+ case 0xcc: /* left joystick */
+ if (ioport("CONFIG")->read()&1)
+ { /* paddle */
+ if (!cpu_get_reg(machine().device("maincpu"), S2650_FO))
+ {
+ data = ioport("JOYS")->read() & 0x03;
+ switch (data)
+ {
+ case 0x01:
+ m_joy1_x-=5;
+ if (m_joy1_x < STICKLOW) m_joy1_x=STICKLOW;
+ break;
+ case 0x02:
+ m_joy1_x+=5;
+ if (m_joy1_x > STICKHIGH) m_joy1_x=STICKHIGH;
+ break;
+ case 0x00:
+ m_joy1_x = vc4000_joystick_return_to_centre(m_joy1_x);
+ }
+ data = m_joy1_x;
+ }
+ else
+ {
+ data = ioport("JOYS")->read() & 0x0c;
+ switch (data)
+ {
+ case 0x08:
+ m_joy1_y-=5;
+ if (m_joy1_y < STICKLOW) m_joy1_y=STICKLOW;
+ break;
+ case 0x04:
+ m_joy1_y+=5;
+ if (m_joy1_y > STICKHIGH) m_joy1_y=STICKHIGH;
+ break;
+ // case 0x00:
+ // m_joy1_y = vc4000_joystick_return_to_centre(m_joy1_y);
+ }
+ data = m_joy1_y;
+ }
+ }
+ else
+ { /* buttons */
+ if (!cpu_get_reg(machine().device("maincpu"), S2650_FO))
+ {
+ data = ioport("JOYS")->read() & 0x03;
+ switch (data)
+ {
+ case 0x01:
+ m_joy1_x=STICKLOW;
+ break;
+ case 0x02:
+ m_joy1_x=STICKHIGH;
+ break;
+ default: /* autocentre */
+ m_joy1_x=STICKCENTRE;
+ }
+ data = m_joy1_x;
+ }
+ else
+ {
+ data = ioport("JOYS")->read() & 0x0c;
+ switch (data)
+ {
+ case 0x08:
+ m_joy1_y=STICKLOW;
+ break;
+ case 0x04:
+ m_joy1_y=STICKHIGH;
+ break;
+ default:
+ m_joy1_y=STICKCENTRE;
+ }
+ data = m_joy1_y;
+ }
+ }
+ break;
+
+ case 0xcd: /* right joystick */
+ if (ioport("CONFIG")->read()&1)
+ {
+ if (!cpu_get_reg(machine().device("maincpu"), S2650_FO))
+ {
+ data = ioport("JOYS")->read() & 0x30;
+ switch (data)
+ {
+ case 0x10:
+ m_joy2_x-=5;
+ if (m_joy2_x < STICKLOW) m_joy2_x=STICKLOW;
+ break;
+ case 0x20:
+ m_joy2_x+=5;
+ if (m_joy2_x > STICKHIGH) m_joy2_x=STICKHIGH;
+ case 0x00:
+ m_joy2_x = vc4000_joystick_return_to_centre(m_joy2_x);
+ break;
+ }
+ data = m_joy2_x;
+ }
+ else
+ {
+ data = ioport("JOYS")->read() & 0xc0;
+ switch (data)
+ {
+ case 0x80:
+ m_joy2_y-=5;
+ if (m_joy2_y < STICKLOW) m_joy2_y=STICKLOW;
+ break;
+ case 0x40:
+ m_joy2_y+=5;
+ if (m_joy2_y > STICKHIGH) m_joy2_y=STICKHIGH;
+ break;
+ // case 0x00:
+ // m_joy2_y = vc4000_joystick_return_to_centre(m_joy2_y);
+ }
+ data = m_joy2_y;
+ }
+ }
+ else
+ {
+ if (!cpu_get_reg(machine().device("maincpu"), S2650_FO))
+ {
+ data = ioport("JOYS")->read() & 0x30;
+ switch (data)
+ {
+ case 0x10:
+ m_joy2_x=STICKLOW;
+ break;
+ case 0x20:
+ m_joy2_x=STICKHIGH;
+ break;
+ default: /* autocentre */
+ m_joy2_x=STICKCENTRE;
+ }
+ data = m_joy2_x;
+ }
+ else
+ {
+ data = ioport("JOYS")->read() & 0xc0;
+ switch (data)
+ {
+ case 0x80:
+ m_joy2_y=STICKLOW;
+ break;
+ case 0x40:
+ m_joy2_y=STICKHIGH;
+ break;
+ default:
+ m_joy2_y=STICKCENTRE;
+ }
+ data = m_joy2_y;
+ }
+ }
+ break;
+#endif
+
+ default:
+ data = m_video.reg.data[offset];
+ break;
+ }
+ return data;
+}
+
+WRITE8_MEMBER( vc4000_state::vc4000_video_w )
+{
+// m_video.reg.data[offset]=data;
+ if (offset > 0xcf) offset &= 0xcf; // c0-cf is mirrored at d0-df, e0-ef, f0-ff
+
+ switch (offset)
+ {
+
+ case 0xc0: // Sprite size
+ m_video.sprites[0].size=1<<(data&3);
+ m_video.sprites[1].size=1<<((data>>2)&3);
+ m_video.sprites[2].size=1<<((data>>4)&3);
+ m_video.sprites[3].size=1<<((data>>6)&3);
+ break;
+
+ case 0xc1: // Sprite 1+2 color
+ m_video.sprites[0].scolor=((~data>>3)&7);
+ m_video.sprites[1].scolor=(~data&7);
+ break;
+
+ case 0xc2: // Sprite 2+3 color
+ m_video.sprites[2].scolor=((~data>>3)&7);
+ m_video.sprites[3].scolor=(~data&7);
+ break;
+
+ case 0xc3: // Score control
+ m_video.reg.d.score_control = data;
+ break;
+
+ case 0xc6: // Background color
+ m_video.reg.d.background = data;
+ break;
+
+ case 0xc7: // Soundregister
+ m_video.reg.data[offset] = data;
+ vc4000_soundport_w(machine().device("custom"), 0, data);
+ break;
+
+ case 0xc8: // Digits 1 and 2
+ m_video.reg.d.bcd[0] = data;
+ break;
+
+ case 0xc9: // Digits 3 and 4
+ m_video.reg.d.bcd[1] = data;
+ break;
+
+ case 0xca: // Background-sprite collision (bit 7-4) and sprite finished (bit 3-0)
+ m_video.reg.data[offset]=data;
+ m_video.background_collision=data;
+ break;
+
+ case 0xcb: // VRST-Flag (bit 6) and intersprite collision (bit5-0)
+ m_video.reg.data[offset]=data;
+ m_video.sprite_collision=data;
+ break;
+
+ default:
+ m_video.reg.data[offset]=data;
+ }
+}
+
+
+READ8_MEMBER( vc4000_state::vc4000_vsync_r )
+{
+ return m_video.line >= VC4000_END_LINE ? 0x80 : 0;
+}
+
+static const char led[20][12+1] =
+{
+ "aaaabbbbcccc",
+ "aaaabbbbcccc",
+ "aaaabbbbcccc",
+ "aaaabbbbcccc",
+ "llll dddd",
+ "llll dddd",
+ "llll dddd",
+ "llll dddd",
+ "kkkkmmmmeeee",
+ "kkkkmmmmeeee",
+ "kkkkmmmmeeee",
+ "kkkkmmmmeeee",
+ "jjjj ffff",
+ "jjjj ffff",
+ "jjjj ffff",
+ "jjjj ffff",
+ "iiiihhhhgggg",
+ "iiiihhhhgggg",
+ "iiiihhhhgggg",
+ "iiiihhhhgggg"
+};
+
+
+static void vc4000_draw_digit(vc4000_state *state, bitmap_ind16 &bitmap, int x, int y, int d, int line)
+{
+ static const int digit_to_segment[0x10]={
+ 0x0fff, 0x007c, 0x17df, 0x15ff, 0x1c7d, 0x1df7, 0x1ff7, 0x007f, 0x1fff, 0x1dff
+ };
+
+ int i=line,j;
+
+ for (j=0; j<sizeof(led[0]); j++)
+ {
+ if (digit_to_segment[d]&(1<<(led[i][j]-'a')) )
+ bitmap.pix16(y+i, x+j) = ((state->m_video.reg.d.background>>4)&7)^7;
+ }
+}
+
+INLINE void vc4000_collision_plot(UINT8 *collision, UINT8 data, UINT8 color, int scale)
+{
+ int i,j,m;
+
+ for (j=0,m=0x80; j<8; j++, m>>=1)
+ {
+ if (data&m)
+ for (i=0; i<scale; i++, collision++) *collision|=color;
+ else
+ collision+=scale;
+ }
+}
+
+
+static void vc4000_sprite_update(vc4000_state *state, bitmap_ind16 &bitmap, UINT8 *collision, SPRITE *This)
+{
+ int i,j,m;
+
+ if (state->m_video.line==0)
+ {
+ This->y=This->data->y1;
+ This->state=0;
+ This->delay=0;
+ This->finished=FALSE;
+ }
+
+ This->finished_now=FALSE;
+
+ if (state->m_video.line>VC4000_END_LINE) return;
+
+ switch (This->state)
+ {
+ case 0:
+ if (state->m_video.line != This->y + 2) break;
+ This->state++;
+
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:case 9:case 10:
+
+ vc4000_collision_plot(collision+This->data->x1, This->data->bitmap[This->state-1],This->mask,This->size);
+
+ for (j=0,m=0x80; j<8; j++, m>>=1)
+ {
+ if (This->data->bitmap[This->state-1]&m)
+ {
+ for (i=0; i<This->size; i++)
+ {
+ state->m_objects[This->data->x1 + i + j*This->size] |= This->scolor;
+ state->m_objects[This->data->x1 + i + j*This->size] &= 7;
+ }
+ }
+ }
+
+ This->delay++;
+
+ if (This->delay>=This->size)
+ {
+ This->delay=0;
+ This->state++;
+ }
+
+ if (This->state>10)
+ {
+ This->finished=TRUE;
+ This->finished_now=TRUE;
+ }
+
+ break;
+
+ case 11:
+ This->y=This->data->y2;
+
+ if (This->y==255)
+ This->y=0;
+ else
+ This->y++;
+
+ if (This->y>252) break;
+
+ This->delay=0;
+ This->state++;
+
+ case 12:
+ if (This->y!=0)
+ {
+ This->y--;
+ break;
+ }
+ This->state++;
+
+ case 13: case 14: case 15: case 16: case 17: case 18: case 19:case 20:case 21:case 22:
+
+ vc4000_collision_plot(collision+This->data->x2,This->data->bitmap[This->state-13],This->mask,This->size);
+ for (j=0,m=0x80; j<8; j++, m>>=1)
+ {
+ if (This->data->bitmap[This->state-13]&m)
+ {
+ for (i=0; i<This->size; i++)
+ {
+ int offset = This->data->x2 + i + j*This->size;
+
+ // clip objects outside the object buffer.
+ // someone who knows this hardware should look at
+ // it properly.
+ if (offset < 256)
+ {
+ state->m_objects[offset] |= This->scolor;
+ state->m_objects[offset] &= 7;
+ }
+ }
+ }
+ }
+ This->delay++;
+ if (This->delay<This->size) break;
+ This->delay=0;
+ This->state++;
+ if (This->state<23) break;
+ This->finished=TRUE;
+ This->finished_now=TRUE;
+ This->state=11;
+ break;
+ }
+}
+
+INLINE void vc4000_draw_grid(running_machine &machine, UINT8 *collision)
+{
+ vc4000_state *state = machine.driver_data<vc4000_state>();
+ screen_device *screen = machine.first_screen();
+ int width = screen->width();
+ int height = screen->height();
+ int i, j, m, x, line=state->m_video.line-20;
+ int w, k;
+
+ if (state->m_video.line>=height) return;
+
+ state->m_bitmap->plot_box(0, state->m_video.line, width, 1, (state->m_video.reg.d.background)&7);
+
+ if (line<0 || line>=200) return;
+ if (~state->m_video.reg.d.background & 8) return;
+
+ i=(line/20)*2;
+ if (line%20>=2) i++;
+
+ k=state->m_video.reg.d.grid_control[i>>2];
+ switch (k>>6) {
+ default:
+ case 0:case 2: w=1;break;
+ case 1: w=2;break;
+ case 3: w=4;break;
+ }
+ switch (i&3) {
+ case 0:
+ if (k&1) w=8;break;
+ case 1:
+ if ((line%40)<=10) {
+ if (k&2) w=8;
+ } else {
+ if (k&4) w=8;
+ }
+ break;
+ case 2: if (k&8) w=8;break;
+ case 3:
+ if ((line%40)<=30) {
+ if (k&0x10) w=8;
+ } else {
+ if (k&0x20) w=8;
+ }
+ break;
+ }
+ for (x=30, j=0, m=0x80; j<16; j++, x+=8, m>>=1)
+ {
+ if (state->m_video.reg.d.grid[i][j>>3]&m)
+ {
+ int l;
+ for (l=0; l<w; l++) collision[x+l]|=0x10;
+ state->m_bitmap->plot_box(x, state->m_video.line, w, 1, (state->m_video.reg.d.background>>4)&7);
+ }
+ if (j==7) m=0x100;
+ }
+}
+
+INTERRUPT_GEN( vc4000_video_line )
+{
+ vc4000_state *state = device->machine().driver_data<vc4000_state>();
+ int x,y,i;
+ UINT8 collision[400]={0}; // better alloca or gcc feature of non constant long automatic arrays
+ const rectangle &visarea = device->machine().primary_screen->visible_area();
+ assert(ARRAY_LENGTH(collision) >= device->machine().primary_screen->width());
+
+ state->m_video.line++;
+ if (state->m_irq_pause) state->m_irq_pause++;
+ if (state->m_video.line>311) state->m_video.line=0;
+
+ if (state->m_video.line==0)
+ {
+ state->m_video.background_collision=0;
+ state->m_video.sprite_collision=0;
+ state->m_video.reg.d.sprite_collision=0;
+// logerror("begin of frame\n");
+ }
+
+ if (state->m_irq_pause>10)
+ {
+ cputag_set_input_line(device->machine(), "maincpu", 0, CLEAR_LINE);
+ state->m_irq_pause = 0;
+ }
+
+ if (state->m_video.line <= VC4000_END_LINE)
+ {
+ vc4000_draw_grid(device->machine(), collision);
+
+ /* init object colours */
+ for (i=visarea.min_x; i<visarea.max_x; i++) state->m_objects[i]=8;
+
+ /* calculate object colours and OR overlapping object colours */
+ vc4000_sprite_update(state, *state->m_bitmap, collision, &state->m_video.sprites[0]);
+ vc4000_sprite_update(state, *state->m_bitmap, collision, &state->m_video.sprites[1]);
+ vc4000_sprite_update(state, *state->m_bitmap, collision, &state->m_video.sprites[2]);
+ vc4000_sprite_update(state, *state->m_bitmap, collision, &state->m_video.sprites[3]);
+
+ for (i=visarea.min_x; i<visarea.max_x; i++)
+ {
+ state->m_video.sprite_collision|=state->m_sprite_collision[collision[i]];
+ state->m_video.background_collision|=state->m_background_collision[collision[i]];
+ /* display final object colours */
+ if (state->m_objects[i] < 8)
+ state->m_bitmap->pix16(state->m_video.line, i) = state->m_objects[i];
+ }
+
+ y = state->m_video.reg.d.score_control&1?200:20;
+
+ if ((state->m_video.line>=y)&&(state->m_video.line<y+20))
+ {
+ x = 60;
+ vc4000_draw_digit(state, *state->m_bitmap, x, y, state->m_video.reg.d.bcd[0]>>4, state->m_video.line-y);
+ vc4000_draw_digit(state, *state->m_bitmap, x+16, y, state->m_video.reg.d.bcd[0]&0xf, state->m_video.line-y);
+ if (state->m_video.reg.d.score_control&2) x -= 16;
+ vc4000_draw_digit(state, *state->m_bitmap, x+48, y, state->m_video.reg.d.bcd[1]>>4, state->m_video.line-y);
+ vc4000_draw_digit(state, *state->m_bitmap, x+64, y, state->m_video.reg.d.bcd[1]&0xf, state->m_video.line-y);
+ }
+ }
+ if (state->m_video.line==VC4000_END_LINE) state->m_video.reg.d.sprite_collision |=0x40;
+
+ if (((state->m_video.line == VC4000_END_LINE) |
+ (state->m_video.sprites[3].finished_now) |
+ (state->m_video.sprites[2].finished_now) |
+ (state->m_video.sprites[1].finished_now) |
+ (state->m_video.sprites[0].finished_now)) && (!state->m_irq_pause))
+ {
+ cputag_set_input_line_and_vector(device->machine(), "maincpu", 0, ASSERT_LINE, 3);
+ state->m_irq_pause=1;
+ }
+}
+
+SCREEN_UPDATE_IND16( vc4000 )
+{
+ vc4000_state *state = screen.machine().driver_data<vc4000_state>();
+ copybitmap(bitmap, *state->m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
diff --git a/src/mess/video/vdc8563.c b/src/mess/video/vdc8563.c
new file mode 100644
index 00000000000..107f806253d
--- /dev/null
+++ b/src/mess/video/vdc8563.c
@@ -0,0 +1,673 @@
+/***************************************************************************
+
+ CBM Video Device Chip 8563
+
+ Original code by PeT (peter.trauner@jk.uni-linz.ac.at)
+
+ 2010-02: converted to be a device
+
+ TODO:
+ - clean up the code
+ - add RAM with an internal address map
+
+***************************************************************************/
+/*
+ several graphic problems
+ some are in the rastering engine and should be solved during its evalution
+ rare and short documentation,
+ registers and some words of description in the c128 user guide */
+/* seems to be a motorola m6845 variant */
+
+
+#include "emu.h"
+#include "video/vdc8563.h"
+
+typedef struct _vdc8563_state vdc8563_state;
+struct _vdc8563_state
+{
+ screen_device *screen;
+
+ int state;
+ UINT8 reg[37];
+ UINT8 index;
+
+ UINT16 addr, src;
+
+ UINT16 videoram_start, colorram_start, fontram_start;
+ UINT16 videoram_size;
+
+ int rastering;
+
+ UINT8 *ram;
+ UINT8 *dirty;
+ UINT8 fontdirty[0x200];
+ UINT16 mask, fontmask;
+
+ double cursor_time;
+ int cursor_on;
+
+ int changed;
+};
+
+/*****************************************************************************
+ CONSTANTS
+*****************************************************************************/
+
+#define VERBOSE_LEVEL 0
+#define DBG_LOG(N, M, A) \
+ do { \
+ if (VERBOSE_LEVEL >= N) \
+ { \
+ if (M) \
+ logerror("%11.6f: %-24s",device->machine().time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+
+static const struct {
+ int stored,
+ read;
+} reg_mask[]= {
+ { 0xff, 0 },
+ { 0xff, 0 },
+ { 0xff, 0 },
+ { 0xff, 0 },
+ { 0xff, 0 },
+ { 0x1f, 0 },
+ { 0xff, 0 },
+ { 0xff, 0 },
+ { 0x3, 0 }, //8
+ { 0x1f, 0 },
+ { 0x7f, 0 },
+ { 0x1f, 0 },
+ { 0xff, 0xff },
+ { 0xff, 0xff },
+ { 0xff, 0xff },
+ { 0xff, 0xff },
+ { -1, 0xff }, //0x10
+ { -1, 0xff },
+ { 0xff, 0xff },
+ { 0xff, 0xff },
+ { 0xff, -1 },
+ { 0x1f, -1 },
+ { 0xff, -1 },
+ { 0xff, -1 },
+ { 0xff, -1 },//0x18
+ { 0xff, -1 },
+ { 0xff, -1 },
+ { 0xff, -1 },
+ { 0xf0, -1 },
+ { 0x1f, -1 },
+ { 0xff, -1 },
+ { 0xff, -1 },
+ { 0xff, -1 }, //0x20
+ { 0xff, -1 },
+ { 0xff, -1 },
+ { 0xff, -1 },
+ { 0x0f, -1 },
+};
+#define REG(x) (vdc8563->reg[x] & reg_mask[x].stored)
+
+
+#define CHAR_WIDTH (((vdc8563->reg[0x16] & 0xf0) >> 4) + 1)
+#define CHAR_WIDTH_VISIBLE ((vdc8563->reg[0x16] & 0x0f) + 1)
+
+#define BLOCK_COPY (vdc8563->reg[0x18] & 0x80)
+
+#define MONOTEXT ((vdc8563->reg[0x19] & 0xc0) == 0)
+#define TEXT ((vdc8563->reg[0x19] & 0xc0) == 0x40)
+#define GRAPHIC (vdc8563->reg[0x19] & 0x80)
+
+#define FRAMECOLOR (vdc8563->reg[0x1a] & 0x0f)
+#define MONOCOLOR (vdc8563->reg[0x1a] >> 4)
+
+#define LINEDIFF (vdc8563->reg[0x1b])
+#define FONT_START ((vdc8563->reg[0x1c] & 0xe0) << 8)
+/* 0x1c 0x10 dram 0:4416, 1: 4164 */
+
+/* 0x1d 0x1f counter for underlining */
+
+#define FILLBYTE vdc8563->reg[0x1f]
+
+#define CLOCK_HALFING (vdc8563->reg[25] & 0x10)
+
+
+/* the regs below corresponds to the ones used by 6845, hence we borrow the macros */
+#define CRTC6845_COLUMNS (REG(0) + 1)
+#define CRTC6845_CHAR_COLUMNS (REG(1))
+#define CRTC6845_CHAR_LINES REG(6)
+#define CRTC6845_CHAR_HEIGHT ((REG(9) & 0x1f) + 1)
+#define CRTC6845_LINES (REG(4) * CRTC6845_CHAR_HEIGHT + REG(5))
+#define CRTC6845_VIDEO_START ((REG(0xc) << 8) | REG(0xd))
+#define CRTC6845_INTERLACE_MODE (REG(8) & 3)
+#define CRTC6845_INTERLACE_SIGNAL 1
+#define CRTC6845_INTERLACE 3
+#define CRTC6845_CURSOR_MODE (REG(0xa) & 0x60)
+#define CRTC6845_CURSOR_OFF 0x20
+#define CRTC6845_CURSOR_16FRAMES 0x40
+#define CRTC6845_CURSOR_32FRAMES 0x60
+#define CRTC6845_SKEW (REG(8) & 15)
+#define CRTC6845_CURSOR_POS ((REG(0xe) << 8) | REG(0xf))
+#define CRTC6845_CURSOR_TOP (REG(0xa) & 0x1f)
+#define CRTC6845_CURSOR_BOTTOM REG(0xb)
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE vdc8563_state *get_safe_token( device_t *device )
+{
+ assert(device != NULL);
+ assert(device->type() == VDC8563);
+
+ return (vdc8563_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+INLINE const vdc8563_interface *get_interface( device_t *device )
+{
+ assert(device != NULL);
+ assert((device->type() == VDC8563));
+ return (const vdc8563_interface *) device->static_config();
+}
+
+/*****************************************************************************
+ IMPLEMENTATION
+*****************************************************************************/
+
+static void vdc_videoram_w( device_t *device, int offset, int data )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+
+ offset &= vdc8563->mask;
+
+ if (vdc8563->ram[offset] != data)
+ {
+ vdc8563->ram[offset] = data;
+ vdc8563->dirty[offset] = 1;
+ if ((vdc8563->fontram_start & vdc8563->fontmask) == (offset & vdc8563->fontmask))
+ vdc8563->fontdirty[(offset & 0x1ff0) >> 4] = 1;
+ }
+}
+
+INLINE int vdc_videoram_r( device_t *device, int offset )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ return vdc8563->ram[offset & vdc8563->mask];
+}
+
+void vdc8563_set_rastering( device_t *device, int on )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ vdc8563->rastering = on;
+ vdc8563->changed |= 1;
+}
+
+
+
+/* 0x22 number of chars from start of line to positiv edge of display enable */
+/* 0x23 number of chars from start of line to negativ edge of display enable */
+/* 0x24 0xf number of refresh cycles per line */
+
+WRITE8_DEVICE_HANDLER( vdc8563_port_w )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ UINT8 i;
+
+ if (offset & 1)
+ {
+ if ((vdc8563->index & 0x3f) < 37)
+ {
+ switch (vdc8563->index & 0x3f)
+ {
+ case 1: case 4: case 0x1b:
+ vdc8563->reg[vdc8563->index] = data;
+ vdc8563->videoram_size = CRTC6845_CHAR_LINES * (CRTC6845_CHAR_COLUMNS + LINEDIFF);
+ vdc8563->changed = 1;
+ break;
+ case 0xe: case 0xf: case 0xa: case 0xb:
+ vdc8563->dirty[CRTC6845_CURSOR_POS & vdc8563->mask] = 1;
+ vdc8563->reg[vdc8563->index] = data;
+ break;
+ case 0xc: case 0xd:
+ vdc8563->reg[vdc8563->index] = data;
+ vdc8563->videoram_start = CRTC6845_VIDEO_START;
+ vdc8563->changed = 1;
+ break;
+ case 0x12:
+ vdc8563->addr = (vdc8563->addr & 0x00ff) | (data << 8);
+ break;
+ case 0x13:
+ vdc8563->addr = (vdc8563->addr & 0xff00) | data;
+ break;
+ case 0x20:
+ vdc8563->src = (vdc8563->src & 0x00ff) | (data << 8);
+ break;
+ case 0x21:
+ vdc8563->src = (vdc8563->src & 0xff00) | data;
+ break;
+ case 0x14: case 0x15:
+ vdc8563->reg[vdc8563->index] = data;
+ vdc8563->colorram_start = (vdc8563->reg[0x14] << 8) | vdc8563->reg[0x15];
+ vdc8563->changed = 1;
+ break;
+ case 0x1c:
+ vdc8563->reg[vdc8563->index] = data;
+ vdc8563->fontram_start = FONT_START;
+ vdc8563->changed = 1;
+ break;
+ case 0x16: case 0x19: case 0x1a:
+ vdc8563->reg[vdc8563->index] = data;
+ vdc8563->changed = 1;
+ break;
+ case 0x1e:
+ vdc8563->reg[vdc8563->index] = data;
+ if (BLOCK_COPY)
+ {
+ DBG_LOG(2, "vdc block copy", ("src:%.4x dst:%.4x size:%.2x\n", vdc8563->src, vdc8563->addr, data));
+ i = data;
+ do {
+ vdc_videoram_w(device, vdc8563->addr++, vdc_videoram_r(device, vdc8563->src++));
+ } while (--i != 0);
+ }
+ else
+ {
+ DBG_LOG(2, "vdc block set", ("dest:%.4x value:%.2x size:%.2x\n", vdc8563->addr, FILLBYTE, data));
+ i = data;
+ do {
+ vdc_videoram_w(device, vdc8563->addr++, FILLBYTE);
+ } while (--i != 0);
+ }
+ break;
+ case 0x1f:
+ DBG_LOG(2, "vdc written", ("dest:%.4x size:%.2x\n", vdc8563->addr, data));
+ vdc8563->reg[vdc8563->index] = data;
+ vdc_videoram_w(device, vdc8563->addr++, data);
+ break;
+ default:
+ vdc8563->reg[vdc8563->index] = data;
+ DBG_LOG(2, "vdc8563_port_w", ("%.2x:%.2x\n", vdc8563->index, data));
+ break;
+ }
+ }
+ DBG_LOG(3, "vdc8563_port_w", ("%.2x:%.2x\n", vdc8563->index, data));
+ }
+ else
+ {
+ vdc8563->index = data;
+ }
+}
+
+READ8_DEVICE_HANDLER( vdc8563_port_r )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ int val;
+
+ val = 0xff;
+ if (offset & 1)
+ {
+ if ((vdc8563->index & 0x3f) < 37)
+ {
+ switch (vdc8563->index & 0x3f)
+ {
+ case 0x12:
+ val = vdc8563->addr >> 8;
+ break;
+ case 0x13:
+ val = vdc8563->addr & 0xff;
+ break;
+ case 0x1e:
+ val = 0;
+ break;
+ case 0x1f:
+ val = vdc_videoram_r(device, vdc8563->addr);
+ DBG_LOG(2, "vdc read", ("%.4x %.2x\n", vdc8563->addr, val));
+ break;
+ case 0x20:
+ val = vdc8563->src >> 8;
+ break;
+ case 0x21:
+ val = vdc8563->src & 0xff;
+ break;
+ default:
+ val = vdc8563->reg[vdc8563->index & 0x3f] & reg_mask[vdc8563->index & 0x3f].read;
+ }
+ }
+ DBG_LOG(2, "vdc8563_port_r", ("%.2x:%.2x\n", vdc8563->index, val));
+ }
+ else
+ {
+ val = vdc8563->index;
+ if (vdc8563->state)
+ val |= 0x80;
+ }
+ return val;
+}
+
+static int vdc8563_clocks_in_frame( device_t *device )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ int clocks = CRTC6845_COLUMNS * CRTC6845_LINES;
+
+ switch (CRTC6845_INTERLACE_MODE)
+ {
+ case CRTC6845_INTERLACE_SIGNAL: // interlace generation of video signals only
+ case CRTC6845_INTERLACE: // interlace
+ return clocks / 2;
+ default:
+ return clocks;
+ }
+}
+
+static void vdc8563_time( device_t *device )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ double newtime, ftime;
+ newtime = device->machine().time().as_double();
+
+ if (vdc8563_clocks_in_frame(device) == 0.0)
+ return;
+
+ ftime = 16 * vdc8563_clocks_in_frame(device) / 2000000.0;
+ if (CLOCK_HALFING)
+ ftime *= 2;
+ switch (CRTC6845_CURSOR_MODE)
+ {
+ case CRTC6845_CURSOR_OFF:
+ vdc8563->cursor_on = 0;
+ break;
+ case CRTC6845_CURSOR_32FRAMES:
+ ftime *= 2;
+ case CRTC6845_CURSOR_16FRAMES:
+ if (newtime - vdc8563->cursor_time > ftime)
+ {
+ vdc8563->cursor_time += ftime;
+ vdc8563->dirty[CRTC6845_CURSOR_POS & vdc8563->mask] = 1;
+ vdc8563->cursor_on ^= 1;
+ }
+ break;
+ default:
+ vdc8563->cursor_on = 1;
+ break;
+ }
+}
+
+static void vdc8563_monotext_screenrefresh( device_t *device, bitmap_ind16 &bitmap, int full_refresh )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ running_machine &machine = device->machine();
+ int x, y, i;
+ rectangle rect;
+ int w = CRTC6845_CHAR_COLUMNS;
+ int h = CRTC6845_CHAR_LINES;
+ int height = CRTC6845_CHAR_HEIGHT;
+
+ rect.setx(vdc8563->screen->visible_area().min_x, vdc8563->screen->visible_area().max_x);
+
+ if (full_refresh)
+ memset(vdc8563->dirty + vdc8563->videoram_start, 1, vdc8563->videoram_size);
+
+ for (y = 0, rect.min_y = height, rect.max_y = rect.min_y + height - 1, i = vdc8563->videoram_start & vdc8563->mask; y < h;
+ y++, rect.min_y += height, rect.max_y += height)
+ {
+ for (x = 0; x < w; x++, i = (i + 1) & vdc8563->mask)
+ {
+ if (vdc8563->dirty[i])
+ {
+ drawgfx_opaque(bitmap,rect,machine.gfx[0], vdc8563->ram[i], FRAMECOLOR | (MONOCOLOR << 4), 0, 0,
+ machine.gfx[0]->width * x + 8, height * y + height);
+
+ if ((vdc8563->cursor_on) && (i == (CRTC6845_CURSOR_POS & vdc8563->mask)))
+ {
+ int k = height - CRTC6845_CURSOR_TOP;
+ if (CRTC6845_CURSOR_BOTTOM < height)
+ k = CRTC6845_CURSOR_BOTTOM - CRTC6845_CURSOR_TOP + 1;
+
+ if (k > 0)
+ bitmap.plot_box(machine.gfx[0]->width * x + 8, height * y + height + CRTC6845_CURSOR_TOP, machine.gfx[0]->width, k, FRAMECOLOR);
+ }
+
+ vdc8563->dirty[i] = 0;
+ }
+ }
+ i += LINEDIFF;
+ }
+}
+
+static void vdc8563_text_screenrefresh( device_t *device, bitmap_ind16 &bitmap, int full_refresh )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ running_machine &machine = device->machine();
+ int x, y, i, j;
+ rectangle rect;
+ int w = CRTC6845_CHAR_COLUMNS;
+ int h = CRTC6845_CHAR_LINES;
+ int height = CRTC6845_CHAR_HEIGHT;
+
+ rect.setx(vdc8563->screen->visible_area().min_x, vdc8563->screen->visible_area().max_x);
+
+ if (full_refresh)
+ memset(vdc8563->dirty + vdc8563->videoram_start, 1, vdc8563->videoram_size);
+
+ for (y = 0, rect.min_y = height, rect.max_y = rect.min_y + height - 1, i = vdc8563->videoram_start & vdc8563->mask,
+ j = vdc8563->colorram_start & vdc8563->mask; y < h; y++, rect.min_y += height, rect.max_y += height)
+ {
+ for (x = 0; x < w; x++, i = (i + 1) & vdc8563->mask, j = (j + 1) & vdc8563->mask)
+ {
+ if (vdc8563->dirty[i] || vdc8563->dirty[j])
+ {
+ {
+ UINT16 ch, fg, bg;
+ const UINT8 *charptr;
+ int v, h2;
+ UINT16 *pixel;
+
+ ch = vdc8563->ram[i] | ((vdc8563->ram[j] & 0x80) ? 0x100 : 0);
+ charptr = &vdc8563->ram[(vdc8563->fontram_start + (ch * 16)) & vdc8563->mask];
+ fg = ((vdc8563->ram[j] & 0x0f) >> 0) + 0x10;
+ bg = ((vdc8563->ram[j] & 0x70) >> 4) + 0x10;
+
+ for (v = 0; v < 16; v++)
+ {
+ for (h2 = 0; h2 < 8; h2++)
+ {
+ pixel = &bitmap.pix16((y * height) + height + v, (x * 8) + 8 + h2);
+ *pixel = (charptr[v] & (0x80 >> h2)) ? fg : bg;
+ }
+ }
+ }
+
+ if ((vdc8563->cursor_on) && (i == (CRTC6845_CURSOR_POS & vdc8563->mask)))
+ {
+ int k = height - CRTC6845_CURSOR_TOP;
+ if (CRTC6845_CURSOR_BOTTOM < height)
+ k = CRTC6845_CURSOR_BOTTOM - CRTC6845_CURSOR_TOP + 1;
+
+ if (k > 0)
+ bitmap.plot_box(machine.gfx[0]->width * x + 8, height * y + height + CRTC6845_CURSOR_TOP, machine.gfx[0]->width,
+ k, 0x10 | (vdc8563->ram[j] & 0x0f));
+ }
+
+ vdc8563->dirty[i] = 0;
+ vdc8563->dirty[j] = 0;
+ }
+ }
+ i += LINEDIFF;
+ j += LINEDIFF;
+ }
+}
+
+static void vdc8563_graphic_screenrefresh( device_t *device, bitmap_ind16 &bitmap, int full_refresh )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ running_machine &machine = device->machine();
+ int x, y, i, j, k;
+ rectangle rect;
+ int w = CRTC6845_CHAR_COLUMNS;
+ int h = CRTC6845_CHAR_LINES;
+ int height = CRTC6845_CHAR_HEIGHT;
+
+ rect.setx(vdc8563->screen->visible_area().min_x, vdc8563->screen->visible_area().max_x);
+
+ if (full_refresh)
+ memset(vdc8563->dirty, 1, vdc8563->mask + 1);
+
+ for (y = 0, rect.min_y = height, rect.max_y = rect.min_y + height - 1, i = vdc8563->videoram_start & vdc8563->mask; y < h;
+ y++, rect.min_y += height, rect.max_y += height)
+ {
+ for (x = 0; x < w; x++, i = (i + 1) & vdc8563->mask)
+ {
+ for (j = 0; j < height; j++)
+ {
+ k = ((i << 4) + j) & vdc8563->mask;
+ if (vdc8563->dirty[k])
+ {
+ drawgfx_opaque(bitmap, rect, machine.gfx[1], vdc8563->ram[k], FRAMECOLOR | (MONOCOLOR << 4), 0, 0,
+ machine.gfx[0]->width * x + 8, height * y + height + j);
+ vdc8563->dirty[k] = 0;
+ }
+ }
+ }
+ i += LINEDIFF;
+ }
+}
+
+UINT32 vdc8563_video_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ int i;
+ int full_refresh = 1;
+
+ if (!vdc8563->rastering)
+ return 0;
+
+ vdc8563_time(device);
+
+ full_refresh |= vdc8563->changed;
+
+ if (GRAPHIC)
+ {
+ vdc8563_graphic_screenrefresh(device, bitmap, full_refresh);
+ }
+ else
+ {
+ for (i = 0; i < 512; i++)
+ {
+ if (full_refresh || vdc8563->fontdirty[i])
+ {
+ gfx_element_mark_dirty(device->machine().gfx[0],i);
+ vdc8563->fontdirty[i] = 0;
+ }
+ }
+ if (TEXT)
+ vdc8563_text_screenrefresh(device, bitmap, full_refresh);
+ else
+ vdc8563_monotext_screenrefresh(device, bitmap, full_refresh);
+ }
+
+ if (full_refresh)
+ {
+ int w = CRTC6845_CHAR_COLUMNS;
+ int h = CRTC6845_CHAR_LINES;
+ int height = CRTC6845_CHAR_HEIGHT;
+
+ bitmap.plot_box(0, 0, device->machine().gfx[0]->width * (w + 2), height, FRAMECOLOR);
+
+ bitmap.plot_box(0, height, device->machine().gfx[0]->width, height * h, FRAMECOLOR);
+
+ bitmap.plot_box(device->machine().gfx[0]->width * (w + 1), height, device->machine().gfx[0]->width, height * h, FRAMECOLOR);
+
+ bitmap.plot_box(0, height * (h + 1), device->machine().gfx[0]->width * (w + 2), height, FRAMECOLOR);
+ }
+
+ vdc8563->changed = 0;
+ return 0;
+}
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( vdc8563 )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+ const vdc8563_interface *intf = (vdc8563_interface *)device->static_config();
+
+ vdc8563->screen = device->machine().device<screen_device>(intf->screen);
+
+ vdc8563->ram = auto_alloc_array_clear(device->machine(), UINT8, 0x20000);
+ vdc8563->dirty = vdc8563->ram + 0x10000;
+
+ /* currently no driver uses 16k only */
+ if (intf->ram16konly)
+ {
+ vdc8563->mask = 0x3fff;
+ vdc8563->fontmask = 0x2000;
+ }
+ else
+ {
+ vdc8563->mask = 0xffff;
+ vdc8563->fontmask = 0xe000;
+ }
+
+ device->save_pointer(NAME(vdc8563->ram), 0x20000);
+
+ device->save_item(NAME(vdc8563->reg));
+ device->save_item(NAME(vdc8563->state));
+ device->save_item(NAME(vdc8563->index));
+
+ device->save_item(NAME(vdc8563->addr));
+ device->save_item(NAME(vdc8563->src));
+
+ device->save_item(NAME(vdc8563->videoram_start));
+ device->save_item(NAME(vdc8563->colorram_start));
+ device->save_item(NAME(vdc8563->fontram_start));
+ device->save_item(NAME(vdc8563->videoram_size));
+
+ device->save_item(NAME(vdc8563->rastering));
+
+ device->save_item(NAME(vdc8563->fontdirty));
+
+ device->save_item(NAME(vdc8563->cursor_time));
+ device->save_item(NAME(vdc8563->cursor_on));
+
+ device->save_item(NAME(vdc8563->changed));
+}
+
+
+static DEVICE_RESET( vdc8563 )
+{
+ vdc8563_state *vdc8563 = get_safe_token(device);
+
+ memset(vdc8563->reg, 0, ARRAY_LENGTH(vdc8563->reg));
+ memset(vdc8563->fontdirty, 0, ARRAY_LENGTH(vdc8563->fontdirty));
+
+ vdc8563->cursor_time = 0.0;
+ vdc8563->state = 1;
+
+ vdc8563->index = 0;
+ vdc8563->addr = 0;
+ vdc8563->src = 0;
+ vdc8563->videoram_start = 0;
+ vdc8563->colorram_start = 0;
+ vdc8563->fontram_start = 0;
+ vdc8563->videoram_size = 0;
+ vdc8563->rastering = 1;
+ vdc8563->cursor_on = 0;
+ vdc8563->changed = 0;
+}
+
+/*-------------------------------------------------
+ device definition
+-------------------------------------------------*/
+
+static const char DEVTEMPLATE_SOURCE[] = __FILE__;
+
+#define DEVTEMPLATE_ID(p,s) p##vdc8563##s
+#define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET
+#define DEVTEMPLATE_NAME "8563 / 8568 VDC"
+#define DEVTEMPLATE_FAMILY "8563 / 8568 VDC"
+#include "devtempl.h"
+
+DEFINE_LEGACY_DEVICE(VDC8563, vdc8563);
diff --git a/src/mess/video/vdc8563.h b/src/mess/video/vdc8563.h
new file mode 100644
index 00000000000..5462e8de8ba
--- /dev/null
+++ b/src/mess/video/vdc8563.h
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ *
+ * video/vdc8563.h
+ *
+ * CBM Video Device Chip 8563
+ *
+ * peter.trauner@jk.uni-linz.ac.at, 2000
+ *
+ ****************************************************************************/
+
+#ifndef __VDC8563_H__
+#define __VDC8563_H__
+
+#include "devcb.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _vdc8563_interface vdc8563_interface;
+struct _vdc8563_interface
+{
+ const char *screen;
+ int ram16konly;
+};
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(VDC8563, vdc8563);
+
+#define MCFG_VDC8563_ADD(_tag, _interface) \
+ MCFG_DEVICE_ADD(_tag, VDC8563, 0) \
+ MCFG_DEVICE_CONFIG(_interface)
+
+
+/*----------- defined in video/vdc8563.c -----------*/
+
+void vdc8563_set_rastering(device_t *device, int on);
+UINT32 vdc8563_video_update(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+WRITE8_DEVICE_HANDLER( vdc8563_port_w );
+READ8_DEVICE_HANDLER( vdc8563_port_r );
+
+
+#endif /* __VDC8563_H__ */
diff --git a/src/mess/video/vector06.c b/src/mess/video/vector06.c
new file mode 100644
index 00000000000..3446fbbaa37
--- /dev/null
+++ b/src/mess/video/vector06.c
@@ -0,0 +1,60 @@
+/***************************************************************************
+
+ Vector06c driver by Miodrag Milanovic
+
+ 10/07/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "includes/vector06.h"
+
+
+VIDEO_START( vector06 )
+{
+}
+
+SCREEN_UPDATE_IND16( vector06 )
+{
+ vector06_state *state = screen.machine().driver_data<vector06_state>();
+ UINT8 code1,code2,code3,code4;
+ UINT8 col;
+ int y, x, b,draw_y;
+ UINT8 *ram = screen.machine().device<ram_device>(RAM_TAG)->pointer();
+
+ int width = (state->m_video_mode==0x00) ? 256 : 512;
+ rectangle screen_area(0,width+64-1,0,256+64-1);
+ // fill border color
+ bitmap.fill(state->m_color_index, screen_area);
+
+ // draw image
+ for (x = 0; x < 32; x++)
+ {
+ for (y = 0; y < 256; y++)
+ {
+ // port A of 8255 also used as scroll
+ draw_y = ((255-y-state->m_keyboard_mask) & 0xff) +32;
+ code1 = ram[0x8000 + x*256 + y];
+ code2 = ram[0xa000 + x*256 + y];
+ code3 = ram[0xc000 + x*256 + y];
+ code4 = ram[0xe000 + x*256 + y];
+ for (b = 0; b < 8; b++)
+ {
+ col = ((code1 >> b) & 0x01) * 8 + ((code2 >> b) & 0x01) * 4 + ((code3 >> b) & 0x01)* 2+ ((code4 >> b) & 0x01);
+ if (state->m_video_mode==0x00) {
+ bitmap.pix16(draw_y, x*8+(7-b)+32) = col;
+ } else {
+ bitmap.pix16(draw_y, x*16+(7-b)*2+1+32) = ((code2 >> b) & 0x01) * 2;
+ bitmap.pix16(draw_y, x*16+(7-b)*2+32) = ((code3 >> b) & 0x01) * 2;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+PALETTE_INIT( vector06 )
+{
+ for (UINT8 i=0; i<16; i++)
+ palette_set_color( machine, i, RGB_BLACK );
+}
diff --git a/src/mess/video/vic4567.c b/src/mess/video/vic4567.c
new file mode 100644
index 00000000000..5284cf721c3
--- /dev/null
+++ b/src/mess/video/vic4567.c
@@ -0,0 +1,2165 @@
+/***************************************************************************
+
+ Video Interface Chip (4567)
+
+ original emulation by PeT (mess@utanet.at)
+
+ 2010-02: converted to be a device and split from vic II
+
+ TODO:
+ - plenty of cleanups
+ - emulate variants of the vic chip
+ - update vic III to use the new vic6567.c code for the vic II comaptibility
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/vic4567.h"
+
+#define SPRITE_BASE_X_SIZE 24
+#define SPRITE_BASE_Y_SIZE 21
+
+struct vic3_sprite
+{
+ int x, y;
+
+ int repeat; /* expand, line once drawn */
+ int line; /* 0 not painting, else painting */
+
+ /* buffer for currently painted line */
+ int paintedline[8];
+ UINT8 bitmap[8][SPRITE_BASE_X_SIZE * 2 / 8 + 1 /*for simplier sprite collision detection*/];
+};
+
+typedef struct _vic3_state vic3_state;
+struct _vic3_state
+{
+ vic3_type type;
+
+ screen_device *main_screen; // screen which sets bitmap properties
+
+ device_t *cpu;
+
+ UINT8 reg[0x80];
+ int on; /* rastering of the screen */
+
+ int lines;
+
+ UINT16 chargenaddr, videoaddr, bitmapaddr;
+
+ bitmap_ind16 *bitmap;
+ int x_begin, x_end;
+ int y_begin, y_end;
+
+ UINT16 c64_bitmap[2], bitmapmulti[4], mono[2], multi[4], ecmcolor[2], colors[4], spritemulti[4];
+
+ int lastline, rasterline;
+
+ int interlace;
+ int columns, rows;
+
+ /* background/foreground for sprite collision */
+ UINT8 *screen[216], shift[216];
+
+ /* convert multicolor byte to background/foreground for sprite collision */
+ UINT8 foreground[256];
+ UINT16 expandx[256];
+ UINT16 expandx_multi[256];
+
+ /* converts sprite multicolor info to info for background collision checking */
+ UINT8 multi_collision[256];
+
+ vic3_sprite sprites[8];
+
+ /* DMA */
+ vic3_dma_read dma_read;
+ vic3_dma_read_color dma_read_color;
+
+ /* IRQ */
+ vic3_irq interrupt;
+
+ /* Port Changed */
+ vic3_port_changed_callback port_changed;
+
+ /* lightpen */
+ vic3_lightpen_button_callback lightpen_button_cb;
+ vic3_lightpen_x_callback lightpen_x_cb;
+ vic3_lightpen_y_callback lightpen_y_cb;
+
+ /* C64 memory access */
+ vic3_c64mem_callback c64_mem_r;
+
+ /* palette - vic3 specific items (the ones above are used for VIC II as well) */
+ UINT8 palette_red[0x100];
+ UINT8 palette_green[0x100];
+ UINT8 palette_blue[0x100];
+ int palette_dirty;
+};
+
+/*****************************************************************************
+ CONSTANTS
+*****************************************************************************/
+
+#define VERBOSE_LEVEL 0
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_LEVEL >= N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s", device->machine().time().as_double(), (char*) M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+#define VREFRESHINLINES 28
+
+#define VIC2_YPOS 50
+#define RASTERLINE_2_C64(a) (a)
+#define C64_2_RASTERLINE(a) (a)
+#define XPOS (VIC2_STARTVISIBLECOLUMNS + (VIC2_VISIBLECOLUMNS - VIC2_HSIZE) / 2)
+#define YPOS (VIC2_STARTVISIBLELINES /* + (VIC2_VISIBLELINES - VIC2_VSIZE) / 2 */)
+#define FIRSTLINE 10 /* 36 ((VIC2_VISIBLELINES - VIC2_VSIZE)/2) */
+#define FIRSTCOLUMN 50
+
+/* 2008-05 FP: lightpen code needs to read input port from c64.c and cbmb.c */
+
+#define LIGHTPEN_BUTTON (vic3->lightpen_button_cb(machine))
+#define LIGHTPEN_X_VALUE (vic3->lightpen_x_cb(machine))
+#define LIGHTPEN_Y_VALUE (vic3->lightpen_y_cb(machine))
+
+/* lightpen delivers values from internal counters; they do not start with the visual area or frame area */
+#define VIC2_MAME_XPOS 0
+#define VIC2_MAME_YPOS 0
+#define VIC6567_X_BEGIN 38
+#define VIC6567_Y_BEGIN -6 /* first 6 lines after retrace not for lightpen! */
+#define VIC6569_X_BEGIN 38
+#define VIC6569_Y_BEGIN -6
+#define VIC2_X_BEGIN ((vic3->type == VIC4567_PAL) ? VIC6569_X_BEGIN : VIC6567_X_BEGIN)
+#define VIC2_Y_BEGIN ((vic3->type == VIC4567_PAL) ? VIC6569_Y_BEGIN : VIC6567_Y_BEGIN)
+#define VIC2_X_VALUE ((LIGHTPEN_X_VALUE + VIC2_X_BEGIN + VIC2_MAME_XPOS) / 2)
+#define VIC2_Y_VALUE ((LIGHTPEN_Y_VALUE + VIC2_Y_BEGIN + VIC2_MAME_YPOS))
+
+#define VIC2E_K0_LEVEL (vic3->reg[0x2f] & 0x01)
+#define VIC2E_K1_LEVEL (vic3->reg[0x2f] & 0x02)
+#define VIC2E_K2_LEVEL (vic3->reg[0x2f] & 0x04)
+
+/*#define VIC3_P5_LEVEL (vic3->reg[0x30] & 0x20) */
+#define VIC3_BITPLANES (vic3->reg[0x31] & 0x10)
+#define VIC3_80COLUMNS (vic3->reg[0x31] & 0x80)
+#define VIC3_LINES ((vic3->reg[0x31] & 0x19) == 0x19 ? 400 : 200)
+#define VIC3_BITPLANES_WIDTH (vic3->reg[0x31] & 0x80 ? 640 : 320)
+
+/*#define VIC2E_TEST (vic2[0x30] & 2) */
+#define DOUBLE_CLOCK (vic3->reg[0x30] & 0x01)
+
+/* sprites 0 .. 7 */
+#define SPRITEON(nr) (vic3->reg[0x15] & (1 << nr))
+#define SPRITE_Y_EXPAND(nr) (vic3->reg[0x17] & (1 << nr))
+#define SPRITE_Y_SIZE(nr) (SPRITE_Y_EXPAND(nr) ? 2 * 21 : 21)
+#define SPRITE_X_EXPAND(nr) (vic3->reg[0x1d] & (1 << nr))
+#define SPRITE_X_SIZE(nr) (SPRITE_X_EXPAND(nr) ? 2 * 24 : 24)
+#define SPRITE_X_POS(nr) ((vic3->reg[(nr) * 2] | (vic3->reg[0x10] & (1 <<(nr)) ? 0x100 : 0)) - 24 + XPOS)
+#define SPRITE_X_POS2(nr) (vic3->reg[(nr) * 2] | (vic3->reg[0x10] & (1 <<(nr)) ? 0x100 : 0))
+#define SPRITE_Y_POS(nr) (vic3->reg[1+2*(nr)] - 50 + YPOS)
+#define SPRITE_Y_POS2(nr) (vic3->reg[1 + 2 *(nr)])
+#define SPRITE_MULTICOLOR(nr) (vic3->reg[0x1c] & (1 << nr))
+#define SPRITE_PRIORITY(nr) (vic3->reg[0x1b] & (1 << nr))
+#define SPRITE_MULTICOLOR1 (vic3->reg[0x25] & 0x0f)
+#define SPRITE_MULTICOLOR2 (vic3->reg[0x26] & 0x0f)
+#define SPRITE_COLOR(nr) (vic3->reg[0x27+nr] & 0x0f)
+#define SPRITE_ADDR(nr) (vic3->videoaddr | 0x3f8 | nr)
+#define SPRITE_BG_COLLISION(nr) (vic3->reg[0x1f] & (1 << nr))
+#define SPRITE_COLLISION(nr) (vic3->reg[0x1e] & (1 << nr))
+#define SPRITE_SET_BG_COLLISION(nr) (vic3->reg[0x1f] |= (1 << nr))
+#define SPRITE_SET_COLLISION(nr) (vic3->reg[0x1e] |= (1 << nr))
+#define SPRITE_COLL (vic3->reg[0x1e])
+#define SPRITE_BG_COLL (vic3->reg[0x1f])
+
+#define GFXMODE ((vic3->reg[0x11] & 0x60) | (vic3->reg[0x16] & 0x10)) >> 4
+#define SCREENON (vic3->reg[0x11] & 0x10)
+#define VERTICALPOS (vic3->reg[0x11] & 0x07)
+#define HORIZONTALPOS (vic3->reg[0x16] & 0x07)
+#define ECMON (vic3->reg[0x11] & 0x40)
+#define HIRESON (vic3->reg[0x11] & 0x20)
+#define MULTICOLORON (vic3->reg[0x16] & 0x10)
+#define LINES25 (vic3->reg[0x11] & 0x08) /* else 24 Lines */
+#define LINES (LINES25 ? 25 : 24)
+#define YSIZE (LINES * 8)
+#define COLUMNS40 (vic3->reg[0x16] & 0x08) /* else 38 Columns */
+#define COLUMNS (COLUMNS40 ? 40 : 38)
+#define XSIZE (COLUMNS * 8)
+
+#define VIDEOADDR ((vic3->reg[0x18] & 0xf0) << (10 - 4))
+#define CHARGENADDR ((vic3->reg[0x18] & 0x0e) << 10)
+#define BITMAPADDR ((data & 0x08) << 10)
+
+#define RASTERLINE (((vic3->reg[0x11] & 0x80) << 1) | vic3->reg[0x12])
+
+#define FRAMECOLOR (vic3->reg[0x20] & 0x0f)
+#define BACKGROUNDCOLOR (vic3->reg[0x21] & 0x0f)
+#define MULTICOLOR1 (vic3->reg[0x22] & 0x0f)
+#define MULTICOLOR2 (vic3->reg[0x23] & 0x0f)
+#define FOREGROUNDCOLOR (vic3->reg[0x24] & 0x0f)
+
+
+#define VIC2_LINES (vic3->type == VIC4567_PAL ? VIC6569_LINES : VIC6567_LINES)
+#define VIC2_VISIBLELINES (vic3->type == VIC4567_PAL ? VIC6569_VISIBLELINES : VIC6567_VISIBLELINES)
+#define VIC2_VISIBLECOLUMNS (vic3->type == VIC4567_PAL ? VIC6569_VISIBLECOLUMNS : VIC6567_VISIBLECOLUMNS)
+#define VIC2_STARTVISIBLELINES ((VIC2_LINES - VIC2_VISIBLELINES)/2)
+#define VIC2_FIRSTRASTERLINE (vic3->type == VIC4567_PAL ? VIC6569_FIRSTRASTERLINE : VIC6567_FIRSTRASTERLINE)
+#define VIC2_COLUMNS (vic3->type == VIC4567_PAL ? VIC6569_COLUMNS : VIC6567_COLUMNS)
+#define VIC2_STARTVISIBLECOLUMNS ((VIC2_COLUMNS - VIC2_VISIBLECOLUMNS)/2)
+
+#define VIC3_BITPLANES_MASK (vic3->reg[0x32])
+/* bit 0, 4 not used !?*/
+/* I think hinibbles contains the banknumbers for interlaced modes */
+/* if hinibble set then x&1==0 should be in bank1 (0x10000), x&1==1 in bank 0 */
+#define VIC3_BITPLANE_ADDR_HELPER(x) ((vic3->reg[0x33 + x] & 0x0f) << 12)
+#define VIC3_BITPLANE_ADDR(x) (x & 1 ? VIC3_BITPLANE_ADDR_HELPER(x) + 0x10000 : VIC3_BITPLANE_ADDR_HELPER(x) )
+#define VIC3_BITPLANE_IADDR_HELPER(x) ((vic3->reg[0x33 + x] & 0xf0) << 8)
+#define VIC3_BITPLANE_IADDR(x) (x & 1 ? VIC3_BITPLANE_IADDR_HELPER(x) + 0x10000 : VIC3_BITPLANE_IADDR_HELPER(x))
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE vic3_state *get_safe_token( device_t *device )
+{
+ assert(device != NULL);
+ assert(device->type() == VIC3);
+
+ return (vic3_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+INLINE const vic3_interface *get_interface( device_t *device )
+{
+ assert(device != NULL);
+ assert((device->type() == VIC3));
+ return (const vic3_interface *) device->static_config();
+}
+
+/*****************************************************************************
+ IMPLEMENTATION
+*****************************************************************************/
+
+INLINE int vic3_getforeground( device_t *device, int y, int x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ return ((vic3->screen[y][x >> 3] << 8) | (vic3->screen[y][(x >> 3) + 1])) >> (8 - (x & 7));
+}
+
+INLINE int vic3_getforeground16(device_t *device, int y, int x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ return ((vic3->screen[y][x >> 3] << 16) | (vic3->screen[y][(x >> 3) + 1] << 8) | (vic3->screen[y][(x >> 3) + 2])) >> (8 - (x & 7));
+}
+
+static void vic3_set_interrupt( running_machine &machine, int mask, vic3_state *vic3 )
+{
+ if (((vic3->reg[0x19] ^ mask) & vic3->reg[0x1a] & 0xf))
+ {
+ if (!(vic3->reg[0x19] & 0x80))
+ {
+ //DBG_LOG(2, "vic2", ("irq start %.2x\n", mask));
+ vic3->reg[0x19] |= 0x80;
+ vic3->interrupt(machine, 1);
+ }
+ }
+ vic3->reg[0x19] |= mask;
+}
+
+static void vic3_clear_interrupt( running_machine &machine, int mask, vic3_state *vic3 )
+{
+ vic3->reg[0x19] &= ~mask;
+ if ((vic3->reg[0x19] & 0x80) && !(vic3->reg[0x19] & vic3->reg[0x1a] & 0xf))
+ {
+ //DBG_LOG(2, "vic2", ("irq end %.2x\n", mask));
+ vic3->reg[0x19] &= ~0x80;
+ vic3->interrupt(machine, 0);
+ }
+}
+
+static TIMER_CALLBACK(vic3_timer_timeout)
+{
+ vic3_state *vic3 = (vic3_state *)ptr;
+ int which = param;
+ //DBG_LOG(3, "vic3 ", ("timer %d timeout\n", which));
+ switch (which)
+ {
+ case 1: /* light pen */
+ /* and diode must recognize light */
+ if (1)
+ {
+ vic3->reg[0x13] = VIC2_X_VALUE;
+ vic3->reg[0x14] = VIC2_Y_VALUE;
+ }
+ vic3_set_interrupt(machine, 8, vic3);
+ break;
+ }
+}
+static void vic3_draw_character( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int y, code;
+
+ for (y = ybegin; y <= yend; y++)
+ {
+ code = vic3->dma_read(device->machine(), vic3->chargenaddr + ch * 8 + y);
+ vic3->screen[y + yoff][xoff >> 3] = code;
+ if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = color[code >> 7];
+ if ((xoff + 1 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = color[(code >> 6) & 1];
+ if ((xoff + 2 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = color[(code >> 5) & 1];
+ if ((xoff + 3 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = color[(code >> 4) & 1];
+ if ((xoff + 4 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = color[(code >> 3) & 1];
+ if ((xoff + 5 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = color[(code >> 2) & 1];
+ if ((xoff + 6 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = color[(code >> 1) & 1];
+ if ((xoff + 7 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = color[code & 1];
+ }
+}
+
+static void vic3_draw_character_multi( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int y, code;
+
+ for (y = ybegin; y <= yend; y++)
+ {
+ code = vic3->dma_read(device->machine(), vic3->chargenaddr + ch * 8 + y);
+ vic3->screen[y + yoff][xoff >> 3] = vic3->foreground[code];
+ if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = vic3->multi[code >> 6];
+ if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = vic3->multi[code >> 6];
+ if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = vic3->multi[(code >> 4) & 3];
+ if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = vic3->multi[(code >> 4) & 3];
+ if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = vic3->multi[(code >> 2) & 3];
+ if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = vic3->multi[(code >> 2) & 3];
+ if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = vic3->multi[code & 3];
+ if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = vic3->multi[code & 3];
+ }
+}
+
+static void vic3_draw_bitmap( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int y, code;
+
+ for (y = ybegin; y <= yend; y++)
+ {
+ code = vic3->dma_read(device->machine(), (vic3->chargenaddr & 0x2000) + ch * 8 + y);
+ vic3->screen[y + yoff][xoff >> 3] = code;
+ if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = vic3->c64_bitmap[code >> 7];
+ if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = vic3->c64_bitmap[(code >> 6) & 1];
+ if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = vic3->c64_bitmap[(code >> 5) & 1];
+ if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = vic3->c64_bitmap[(code >> 4) & 1];
+ if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = vic3->c64_bitmap[(code >> 3) & 1];
+ if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = vic3->c64_bitmap[(code >> 2) & 1];
+ if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = vic3->c64_bitmap[(code >> 1) & 1];
+ if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = vic3->c64_bitmap[code & 1];
+ }
+}
+
+static void vic3_draw_bitmap_multi( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int y, code;
+
+ for (y = ybegin; y <= yend; y++)
+ {
+ code = vic3->dma_read(device->machine(), (vic3->chargenaddr & 0x2000) + ch * 8 + y);
+ vic3->screen[y + yoff][xoff >> 3] = vic3->foreground[code];
+ if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = vic3->bitmapmulti[code >> 6];
+ if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = vic3->bitmapmulti[code >> 6];
+ if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = vic3->bitmapmulti[(code >> 4) & 3];
+ if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = vic3->bitmapmulti[(code >> 4) & 3];
+ if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = vic3->bitmapmulti[(code >> 2) & 3];
+ if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = vic3->bitmapmulti[(code >> 2) & 3];
+ if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = vic3->bitmapmulti[code & 3];
+ if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) vic3->bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = vic3->bitmapmulti[code & 3];
+ }
+}
+
+static void vic3_draw_sprite_code( device_t *device, int y, int xbegin, int code, int color, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ register int mask, x;
+
+ if ((y < YPOS) || (y >= (VIC2_STARTVISIBLELINES + VIC2_VISIBLELINES)) || (xbegin <= 1) || (xbegin >= (VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS)))
+ return;
+
+ for (x = 0, mask = 0x80; x < 8; x++, mask >>= 1)
+ {
+ if (code & mask)
+ {
+ if ((xbegin + x > start_x) && (xbegin + x < end_x))
+ vic3->bitmap->pix16(y + FIRSTLINE, xbegin + x) = color;
+ }
+ }
+}
+
+static void vic3_draw_sprite_code_multi( device_t *device, int y, int xbegin, int code, int prior, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ register int x, mask, shift;
+
+ if ((y < YPOS) || (y >= (VIC2_STARTVISIBLELINES + VIC2_VISIBLELINES)) || (xbegin <= 1) || (xbegin >= (VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS)))
+ {
+ return;
+ }
+
+ for (x = 0, mask = 0xc0, shift = 6; x < 8; x += 2, mask >>= 2, shift -= 2)
+ {
+ if (code & mask)
+ {
+ switch ((prior & mask) >> shift)
+ {
+ case 1:
+ if ((xbegin + x + 1 > start_x) && (xbegin + x + 1 < end_x))
+ vic3->bitmap->pix16(y + FIRSTLINE, xbegin + x + 1) = vic3->spritemulti[(code >> shift) & 3];
+ break;
+ case 2:
+ if ((xbegin + x > start_x) && (xbegin + x < end_x))
+ vic3->bitmap->pix16(y + FIRSTLINE, xbegin + x) = vic3->spritemulti[(code >> shift) & 3];
+ break;
+ case 3:
+ if ((xbegin + x > start_x) && (xbegin + x < end_x))
+ vic3->bitmap->pix16(y + FIRSTLINE, xbegin + x) = vic3->spritemulti[(code >> shift) & 3];
+ if ((xbegin + x + 1> start_x) && (xbegin + x + 1< end_x))
+ vic3->bitmap->pix16(y + FIRSTLINE, xbegin + x + 1) = vic3->spritemulti[(code >> shift) & 3];
+ break;
+ }
+ }
+ }
+}
+
+static void vic3_sprite_collision( device_t *device, int nr, int y, int x, int mask )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int i, value, xdiff;
+
+ for (i = 7; i > nr; i--)
+ {
+ if (!SPRITEON(i) || !vic3->sprites[i].paintedline[y] || (SPRITE_COLLISION(i) && SPRITE_COLLISION(nr)))
+ continue;
+
+ if ((x + 7 < SPRITE_X_POS(i)) || (x >= SPRITE_X_POS(i) + SPRITE_X_SIZE(i)))
+ continue;
+
+ xdiff = x - SPRITE_X_POS(i);
+
+ if ((x & 7) == (SPRITE_X_POS(i) & 7))
+ value = vic3->sprites[i].bitmap[y][xdiff >> 3];
+ else if (xdiff < 0)
+ value = vic3->sprites[i].bitmap[y][0] >> (-xdiff);
+ else {
+ UINT8 *vp = vic3->sprites[i].bitmap[y]+(xdiff >> 3);
+ value = ((vp[1] | (*vp << 8)) >> (8 - (xdiff & 7) )) & 0xff;
+ }
+
+ if (value & mask)
+ {
+ SPRITE_SET_COLLISION(i);
+ SPRITE_SET_COLLISION(nr);
+ vic3_set_interrupt(device->machine(), 4, vic3);
+ }
+ }
+}
+
+static void vic3_draw_sprite( device_t *device, int nr, int yoff, int ybegin, int yend, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int y, i, addr, xbegin, color, prior, collision;
+ int value, value3 = 0;
+
+ xbegin = SPRITE_X_POS(nr);
+ addr = vic3->dma_read(device->machine(), SPRITE_ADDR(nr)) << 6;
+ color = SPRITE_COLOR(nr);
+ prior = SPRITE_PRIORITY(nr);
+ collision = SPRITE_BG_COLLISION(nr);
+
+ if (SPRITE_X_EXPAND(nr))
+ {
+ for (y = ybegin; y <= yend; y++)
+ {
+ vic3->sprites[nr].paintedline[y] = 1;
+ for (i = 0; i < 3; i++)
+ {
+ value = vic3->expandx[vic3->dma_read(device->machine(), addr + vic3->sprites[nr].line * 3 + i)];
+ vic3->sprites[nr].bitmap[y][i * 2] = value >> 8;
+ vic3->sprites[nr].bitmap[y][i * 2 + 1] = value & 0xff;
+ vic3_sprite_collision(device, nr, y, xbegin + i * 16, value >> 8);
+ vic3_sprite_collision(device, nr, y, xbegin + i * 16 + 8, value & 0xff);
+ if (prior || !collision)
+ value3 = vic3_getforeground16(device, yoff + y, xbegin + i * 16 - 7);
+ if (!collision && (value & value3))
+ {
+ collision = 1;
+ SPRITE_SET_BG_COLLISION(nr);
+ vic3_set_interrupt(device->machine(), 2, vic3);
+ }
+ if (prior)
+ value &= ~value3;
+ vic3_draw_sprite_code(device, yoff + y, xbegin + i * 16, value >> 8, color, start_x, end_x);
+ vic3_draw_sprite_code(device, yoff + y, xbegin + i * 16 + 8, value & 0xff, color, start_x, end_x);
+ }
+ vic3->sprites[nr].bitmap[y][i * 2]=0; //easier sprite collision detection
+ if (SPRITE_Y_EXPAND(nr))
+ {
+ if (vic3->sprites[nr].repeat)
+ {
+ vic3->sprites[nr].line++;
+ vic3->sprites[nr].repeat = 0;
+ }
+ else
+ vic3->sprites[nr].repeat = 1;
+ }
+ else
+ {
+ vic3->sprites[nr].line++;
+ }
+ }
+ }
+ else
+ {
+ for (y = ybegin; y <= yend; y++)
+ {
+ vic3->sprites[nr].paintedline[y] = 1;
+ for (i = 0; i < 3; i++)
+ {
+ value = vic3->dma_read(device->machine(), addr + vic3->sprites[nr].line * 3 + i);
+ vic3->sprites[nr].bitmap[y][i] = value;
+ vic3_sprite_collision(device, nr, y, xbegin + i * 8, value);
+ if (prior || !collision)
+ value3 = vic3_getforeground(device, yoff + y, xbegin + i * 8 - 7);
+ if (!collision && (value & value3))
+ {
+ collision = 1;
+ SPRITE_SET_BG_COLLISION(nr);
+ vic3_set_interrupt(device->machine(), 2, vic3);
+ }
+ if (prior)
+ value &= ~value3;
+ vic3_draw_sprite_code(device, yoff + y, xbegin + i * 8, value, color, start_x, end_x);
+ }
+ vic3->sprites[nr].bitmap[y][i]=0; //easier sprite collision detection
+ if (SPRITE_Y_EXPAND(nr))
+ {
+ if (vic3->sprites[nr].repeat)
+ {
+ vic3->sprites[nr].line++;
+ vic3->sprites[nr].repeat = 0;
+ }
+ else
+ vic3->sprites[nr].repeat = 1;
+ }
+ else
+ {
+ vic3->sprites[nr].line++;
+ }
+ }
+ }
+}
+
+static void vic3_draw_sprite_multi( device_t *device, int nr, int yoff, int ybegin, int yend, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int y, i, prior, addr, xbegin, collision;
+ int value, value2, value3 = 0, bg/*, color[2]*/;
+
+ xbegin = SPRITE_X_POS(nr);
+ addr = vic3->dma_read(device->machine(), SPRITE_ADDR(nr)) << 6;
+ vic3->spritemulti[2] = SPRITE_COLOR(nr);
+ prior = SPRITE_PRIORITY(nr);
+ collision = SPRITE_BG_COLLISION(nr);
+ //color[0] = 0;
+ //color[1] = 1;
+
+ if (SPRITE_X_EXPAND(nr))
+ {
+ for (y = ybegin; y <= yend; y++)
+ {
+ vic3->sprites[nr].paintedline[y] = 1;
+ for (i = 0; i < 3; i++)
+ {
+ value = vic3->expandx_multi[bg = vic3->dma_read(device->machine(), addr + vic3->sprites[nr].line * 3 + i)];
+ value2 = vic3->expandx[vic3->multi_collision[bg]];
+ vic3->sprites[nr].bitmap[y][i * 2] = value2 >> 8;
+ vic3->sprites[nr].bitmap[y][i * 2 + 1] = value2 & 0xff;
+ vic3_sprite_collision(device, nr, y, xbegin + i * 16, value2 >> 8);
+ vic3_sprite_collision(device, nr, y, xbegin + i * 16 + 8, value2 & 0xff);
+ if (prior || !collision)
+ {
+ value3 = vic3_getforeground16(device, yoff + y, xbegin + i * 16 - 7);
+ }
+ if (!collision && (value2 & value3))
+ {
+ collision = 1;
+ SPRITE_SET_BG_COLLISION(nr);
+ vic3_set_interrupt(device->machine(), 2, vic3);
+ }
+ if (prior)
+ {
+ vic3_draw_sprite_code_multi(device, yoff + y, xbegin + i * 16, value >> 8, (value3 >> 8) ^ 0xff, start_x, end_x);
+ vic3_draw_sprite_code_multi(device, yoff + y, xbegin + i * 16 + 8, value & 0xff, (value3 & 0xff) ^ 0xff, start_x, end_x);
+ }
+ else
+ {
+ vic3_draw_sprite_code_multi(device, yoff + y, xbegin + i * 16, value >> 8, 0xff, start_x, end_x);
+ vic3_draw_sprite_code_multi(device, yoff + y, xbegin + i * 16 + 8, value & 0xff, 0xff, start_x, end_x);
+ }
+ }
+ vic3->sprites[nr].bitmap[y][i * 2]=0; //easier sprite collision detection
+ if (SPRITE_Y_EXPAND(nr))
+ {
+ if (vic3->sprites[nr].repeat)
+ {
+ vic3->sprites[nr].line++;
+ vic3->sprites[nr].repeat = 0;
+ }
+ else
+ vic3->sprites[nr].repeat = 1;
+ }
+ else
+ {
+ vic3->sprites[nr].line++;
+ }
+ }
+ }
+ else
+ {
+ for (y = ybegin; y <= yend; y++)
+ {
+ vic3->sprites[nr].paintedline[y] = 1;
+ for (i = 0; i < 3; i++)
+ {
+ value = vic3->dma_read(device->machine(), addr + vic3->sprites[nr].line * 3 + i);
+ vic3->sprites[nr].bitmap[y][i] = value2 = vic3->multi_collision[value];
+ vic3_sprite_collision(device, nr, y, xbegin + i * 8, value2);
+ if (prior || !collision)
+ {
+ value3 = vic3_getforeground(device, yoff + y, xbegin + i * 8 - 7);
+ }
+ if (!collision && (value2 & value3))
+ {
+ collision = 1;
+ SPRITE_SET_BG_COLLISION(nr);
+ vic3_set_interrupt(device->machine(), 2, vic3);
+ }
+ if (prior)
+ {
+ vic3_draw_sprite_code_multi(device, yoff + y, xbegin + i * 8, value, value3 ^ 0xff, start_x, end_x);
+ }
+ else
+ {
+ vic3_draw_sprite_code_multi(device, yoff + y, xbegin + i * 8, value, 0xff, start_x, end_x);
+ }
+ }
+ vic3->sprites[nr].bitmap[y][i] = 0; //easier sprite collision detection
+ if (SPRITE_Y_EXPAND(nr))
+ {
+ if (vic3->sprites[nr].repeat)
+ {
+ vic3->sprites[nr].line++;
+ vic3->sprites[nr].repeat = 0;
+ }
+ else
+ vic3->sprites[nr].repeat = 1;
+ }
+ else
+ {
+ vic3->sprites[nr].line++;
+ }
+ }
+ }
+}
+
+#ifndef memset16
+static void *memset16 (void *dest, int value, size_t size)
+{
+ register int i;
+
+ for (i = 0; i < size; i++)
+ ((short *) dest)[i] = value;
+ return dest;
+}
+#endif
+
+static void vic3_drawlines( device_t *device, int first, int last, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int line, vline, end;
+ int attr, ch, ecm;
+ int syend;
+ int offs, yoff, xoff, ybegin, yend, xbegin, xend;
+ int x_end2;
+ int i, j;
+
+ if (first == last)
+ return;
+ vic3->lastline = last;
+
+ /* top part of display not rastered */
+ first -= VIC2_YPOS - YPOS;
+ last -= VIC2_YPOS - YPOS;
+ if ((first >= last) || (last <= 0))
+ {
+ for (i = 0; i < 8; i++)
+ vic3->sprites[i].repeat = vic3->sprites[i].line = 0;
+ return;
+ }
+ if (first < 0)
+ first = 0;
+
+ if (!SCREENON)
+ {
+ for (line = first; (line < last) && (line < vic3->bitmap->height()); line++)
+ {
+ memset16(&vic3->bitmap->pix16(line + FIRSTLINE), 0, vic3->bitmap->width());
+ }
+ return;
+ }
+ if (COLUMNS40)
+ xbegin = XPOS, xend = xbegin + 640;
+ else
+ xbegin = XPOS + 7, xend = xbegin + 624;
+
+ if (last < vic3->y_begin)
+ end = last;
+ else
+ end = vic3->y_begin + YPOS;
+
+ for (line = first; line < end; line++)
+ {
+ memset16(&vic3->bitmap->pix16(line + FIRSTLINE), FRAMECOLOR, vic3->bitmap->width());
+ }
+
+ if (LINES25)
+ {
+ vline = line - vic3->y_begin - YPOS;
+ }
+ else
+ {
+ vline = line - vic3->y_begin - YPOS + 8 - VERTICALPOS;
+ }
+ if (last < vic3->y_end + YPOS)
+ end = last;
+ else
+ end = vic3->y_end + YPOS;
+ x_end2 = vic3->x_end * 2;
+ for (; line < end; vline = (vline + 8) & ~7, line = line + 1 + yend - ybegin)
+ {
+ offs = (vline >> 3) * 80;
+ ybegin = vline & 7;
+ yoff = line - ybegin;
+ yend = (yoff + 7 < end) ? 7 : (end - yoff - 1);
+ /* rendering 39 characters */
+ /* left and right borders are overwritten later */
+ vic3->shift[line] = HORIZONTALPOS;
+
+ for (xoff = vic3->x_begin + XPOS; xoff < x_end2 + XPOS; xoff += 8, offs++)
+ {
+ ch = vic3->dma_read(device->machine(), vic3->videoaddr + offs);
+ attr = vic3->dma_read_color(device->machine(), vic3->videoaddr + offs);
+ if (HIRESON)
+ {
+ vic3->bitmapmulti[1] = vic3->c64_bitmap[1] = ch >> 4;
+ vic3->bitmapmulti[2] = vic3->c64_bitmap[0] = ch & 0xf;
+ if (MULTICOLORON)
+ {
+ vic3->bitmapmulti[3] = attr;
+ vic3_draw_bitmap_multi(device, ybegin, yend, offs, yoff, xoff, start_x, end_x);
+ }
+ else
+ {
+ vic3_draw_bitmap(device, ybegin, yend, offs, yoff, xoff, start_x, end_x);
+ }
+ }
+ else if (ECMON)
+ {
+ ecm = ch >> 6;
+ vic3->ecmcolor[0] = vic3->colors[ecm];
+ vic3->ecmcolor[1] = attr;
+ vic3_draw_character(device, ybegin, yend, ch & ~0xC0, yoff, xoff, vic3->ecmcolor, start_x, end_x);
+ }
+ else if (MULTICOLORON && (attr & 8))
+ {
+ vic3->multi[3] = attr & 7;
+ vic3_draw_character_multi(device, ybegin, yend, ch, yoff, xoff, start_x, end_x);
+ }
+ else
+ {
+ vic3->mono[1] = attr;
+ vic3_draw_character(device, ybegin, yend, ch, yoff, xoff, vic3->mono, start_x, end_x);
+ }
+ }
+ /* sprite priority, sprite overwrites lowerprior pixels */
+ for (i = 7; i >= 0; i--)
+ {
+ if (vic3->sprites[i].line || vic3->sprites[i].repeat)
+ {
+ syend = yend;
+ if (SPRITE_Y_EXPAND(i))
+ {
+ if ((21 - vic3->sprites[i].line) * 2 - vic3->sprites[i].repeat < yend - ybegin + 1)
+ syend = ybegin + (21 - vic3->sprites[i].line) * 2 - vic3->sprites[i].repeat - 1;
+ }
+ else
+ {
+ if (vic3->sprites[i].line + yend - ybegin + 1 > 20)
+ syend = ybegin + 20 - vic3->sprites[i].line;
+ }
+ if (yoff + syend > YPOS + 200)
+ syend = YPOS + 200 - yoff - 1;
+ if (SPRITE_MULTICOLOR(i))
+ vic3_draw_sprite_multi(device, i, yoff, ybegin, syend, start_x, end_x);
+ else
+ vic3_draw_sprite(device, i, yoff, ybegin, syend, start_x, end_x);
+ if ((syend != yend) || (vic3->sprites[i].line > 20))
+ {
+ vic3->sprites[i].line = vic3->sprites[i].repeat = 0;
+ for (j = syend; j <= yend; j++)
+ vic3->sprites[i].paintedline[j] = 0;
+ }
+ }
+ // sprite wrap y at the top of the screen
+ else if (SPRITEON(i) && (yoff == 1 + yend - ybegin) && (SPRITE_Y_POS(i) < 1 + yend - ybegin))
+ {
+ int wrapped = 1 + yend - ybegin - SPRITE_Y_POS(i);
+ syend = yend;
+
+ if (SPRITE_Y_EXPAND(i))
+ {
+ if (wrapped & 1) vic3->sprites[i].repeat = 1;
+ wrapped >>= 1;
+ syend = 21 * 2 - 1 - wrapped * 2;
+ if (syend > (yend - ybegin)) syend = yend - ybegin;
+ }
+ else
+ {
+ syend = 21 - 1 - wrapped;
+ if (syend > (yend - ybegin)) syend = yend - ybegin;
+ }
+
+ vic3->sprites[i].line = wrapped;
+
+ if (SPRITE_MULTICOLOR(i))
+ vic3_draw_sprite_multi(device, i, yoff, 0 , syend, start_x, end_x);
+ else
+ vic3_draw_sprite(device, i, yoff, 0 , syend, start_x, end_x);
+
+ if ((syend != yend) || (vic3->sprites[i].line > 20))
+ {
+ for (j = syend; j <= yend; j++)
+ vic3->sprites[i].paintedline[j] = 0;
+ vic3->sprites[i].line = vic3->sprites[i].repeat = 0;
+ }
+ }
+ else if (SPRITEON(i) && (yoff + ybegin <= SPRITE_Y_POS(i))
+ && (yoff + yend >= SPRITE_Y_POS(i)))
+ {
+ syend = yend;
+ if (SPRITE_Y_EXPAND(i))
+ {
+ if (21 * 2 < yend - ybegin + 1)
+ syend = ybegin + 21 * 2 - 1;
+ }
+ else
+ {
+ if (yend - ybegin + 1 > 21)
+ syend = ybegin + 21 - 1;
+ }
+ if (yoff + syend >= YPOS + 200)
+ syend = YPOS + 200 - yoff - 1;
+ for (j = 0; j < SPRITE_Y_POS(i) - yoff; j++)
+ vic3->sprites[i].paintedline[j] = 0;
+ if (SPRITE_MULTICOLOR(i))
+ vic3_draw_sprite_multi(device, i, yoff, SPRITE_Y_POS(i) - yoff, syend, start_x, end_x);
+ else
+ vic3_draw_sprite(device, i, yoff, SPRITE_Y_POS(i) - yoff, syend, start_x, end_x);
+ if ((syend != yend) || (vic3->sprites[i].line > 20))
+ {
+ for (j = syend; j <= yend; j++)
+ vic3->sprites[i].paintedline[j] = 0;
+ vic3->sprites[i].line = vic3->sprites[i].repeat = 0;
+ }
+ }
+ else
+ {
+ memset (vic3->sprites[i].paintedline, 0, sizeof (vic3->sprites[i].paintedline));
+ }
+ }
+
+ for (i = ybegin; i <= yend; i++)
+ {
+ vic3->bitmap->plot_box(0, yoff + ybegin + FIRSTLINE, xbegin, yend-ybegin+1, FRAMECOLOR);
+ vic3->bitmap->plot_box(xend, yoff + ybegin + FIRSTLINE, vic3->bitmap->width() - xend, yend-ybegin+1, FRAMECOLOR);
+ }
+ }
+ if (last < vic3->bitmap->height())
+ end = last;
+ else
+ end = vic3->bitmap->height();
+
+ for (; line < end; line++)
+ {
+ memset16 (&vic3->bitmap->pix16(line + FIRSTLINE), FRAMECOLOR, vic3->bitmap->width());
+ }
+}
+
+static void vic2_drawlines( device_t *device, int first, int last, int start_x, int end_x )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int line, vline, end;
+ int attr, ch, ecm;
+ int syend;
+ int offs, yoff, xoff, ybegin, yend, xbegin, xend;
+ int i;
+
+ if (VIC3_BITPLANES)
+ return ;
+
+ /* temporary allowing vic3 displaying 80 columns */
+ if (vic3->reg[0x31] & 0x80)
+ {
+ vic3_drawlines(device, first, first + 1, start_x, end_x);
+ return;
+ }
+
+ /* otherwise, draw VIC II output (currently using the old code, not the new one from vic6567.c) */
+
+ /* top part of display not rastered */
+ first -= VIC2_YPOS - YPOS;
+
+ xbegin = VIC2_STARTVISIBLECOLUMNS;
+ xend = xbegin + VIC2_VISIBLECOLUMNS;
+ if (!SCREENON)
+ {
+ xbegin = VIC2_STARTVISIBLECOLUMNS;
+ xend = xbegin + VIC2_VISIBLECOLUMNS;
+ if ((start_x <= xbegin) && (end_x >= xend))
+ vic3->bitmap->plot_box(xbegin, first + FIRSTLINE, xend - xbegin, 1, FRAMECOLOR);
+ if ((start_x > xbegin) && (end_x >= xend))
+ vic3->bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xend - start_x, 1, FRAMECOLOR);
+ if ((start_x <= xbegin) && (end_x < xend))
+ vic3->bitmap->plot_box(xbegin, first + FIRSTLINE, end_x - xbegin , 1, FRAMECOLOR);
+ if ((start_x > xbegin) && (end_x < xend))
+ vic3->bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
+ return;
+ }
+
+ if (COLUMNS40)
+ {
+ xbegin = XPOS;
+ xend = xbegin + 320;
+ }
+ else
+ {
+ xbegin = XPOS + 7;
+ xend = xbegin + 304;
+ }
+
+ if (first + 1 < vic3->y_begin)
+ end = first + 1;
+ else
+ end = vic3->y_begin + YPOS;
+
+ line = first;
+ // top border
+ if (line < end)
+ {
+ if ((start_x <= xbegin) && (end_x >= xend))
+ vic3->bitmap->plot_box(xbegin, first + FIRSTLINE, xend - xbegin, 1, FRAMECOLOR);
+ if ((start_x > xbegin) && (end_x >= xend))
+ vic3->bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xend - start_x, 1, FRAMECOLOR);
+ if ((start_x <= xbegin) && (end_x < xend))
+ vic3->bitmap->plot_box(xbegin, first + FIRSTLINE, end_x - xbegin , 1, FRAMECOLOR);
+ if ((start_x > xbegin) && (end_x < xend))
+ vic3->bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
+ line = end;
+ }
+
+ vline = line - YPOS + 3 - VERTICALPOS;
+
+ if (first + 1 < vic3->y_end + YPOS)
+ end = first + 1;
+ else
+ end = vic3->y_end + YPOS;
+
+ if (line < end)
+ {
+ offs = (vline >> 3) * 40;
+ ybegin = vline & 7;
+ yoff = line - ybegin;
+ yend = (yoff + 7 < end) ? 7 : (end - yoff - 1);
+
+ /* rendering 39 characters */
+ /* left and right borders are overwritten later */
+
+ vic3->shift[line] = HORIZONTALPOS;
+ for (xoff = vic3->x_begin + XPOS; xoff < vic3->x_end + XPOS; xoff += 8, offs++)
+ {
+ ch = vic3->dma_read(device->machine(), vic3->videoaddr + offs);
+#if 0
+ attr = vic3->dma_read_color(device->machine(), vic3->videoaddr + offs);
+#else
+ /* temporaery until vic3 finished */
+ attr = vic3->dma_read_color(device->machine(), (vic3->videoaddr + offs)&0x3ff)&0x0f;
+#endif
+ if (HIRESON)
+ {
+ vic3->bitmapmulti[1] = vic3->c64_bitmap[1] = ch >> 4;
+ vic3->bitmapmulti[2] = vic3->c64_bitmap[0] = ch & 0xf;
+ if (MULTICOLORON)
+ {
+ vic3->bitmapmulti[3] = attr;
+ vic3_draw_bitmap_multi(device, ybegin, yend, offs, yoff, xoff, start_x, end_x);
+ }
+ else
+ {
+ vic3_draw_bitmap(device, ybegin, yend, offs, yoff, xoff, start_x, end_x);
+ }
+ }
+ else if (ECMON)
+ {
+ ecm = ch >> 6;
+ vic3->ecmcolor[0] = vic3->colors[ecm];
+ vic3->ecmcolor[1] = attr;
+ vic3_draw_character(device, ybegin, yend, ch & ~0xC0, yoff, xoff, vic3->ecmcolor, start_x, end_x);
+ }
+ else if (MULTICOLORON && (attr & 8))
+ {
+ vic3->multi[3] = attr & 7;
+ vic3_draw_character_multi(device, ybegin, yend, ch, yoff, xoff, start_x, end_x);
+ }
+ else
+ {
+ vic3->mono[1] = attr;
+ vic3_draw_character(device, ybegin, yend, ch, yoff, xoff, vic3->mono, start_x, end_x);
+ }
+ }
+
+ /* sprite priority, sprite overwrites lowerprior pixels */
+ for (i = 7; i >= 0; i--)
+ {
+ if (SPRITEON (i) &&
+ (yoff + ybegin >= SPRITE_Y_POS (i)) &&
+ (yoff + ybegin - SPRITE_Y_POS (i) < (SPRITE_Y_EXPAND (i)? 21 * 2 : 21 )) &&
+ (SPRITE_Y_POS (i) < 0))
+ {
+ int wrapped = - SPRITE_Y_POS (i) + 6;
+
+ syend = yend;
+
+ if (SPRITE_Y_EXPAND (i))
+ {
+ if (wrapped & 1) vic3->sprites[i].repeat = 1;
+ wrapped >>= 1;
+ syend = 21 * 2 - 1 - wrapped * 2;
+ if (syend > (yend - ybegin)) syend = yend - ybegin;
+ }
+ else
+ {
+ syend = 21 - 1 - wrapped;
+ if (syend > (yend - ybegin)) syend = yend - ybegin;
+ }
+
+ vic3->sprites[i].line = wrapped;
+
+ if (SPRITE_MULTICOLOR (i))
+ vic3_draw_sprite_multi(device, i, 0, 0 , syend, start_x, end_x);
+ else
+ vic3_draw_sprite(device, i, 0, 0 , syend, start_x, end_x);
+ }
+ else if (SPRITEON (i) &&
+ (yoff + ybegin >= SPRITE_Y_POS (i)) &&
+ (yoff + ybegin - SPRITE_Y_POS (i) < (SPRITE_Y_EXPAND (i)? 21 * 2 : 21 )) &&
+ (SPRITE_Y_POS (i) >= 0))
+ {
+ int wrapped = yoff + ybegin - SPRITE_Y_POS (i);
+
+ syend = yend;
+
+ if (SPRITE_Y_EXPAND (i))
+ {
+ if (wrapped & 1) vic3->sprites[i].repeat = 1;
+ wrapped >>= 1;
+ syend = 21 * 2 - 1 - wrapped * 2;
+ if (syend > (yend - ybegin)) syend = yend - ybegin;
+ }
+ else
+ {
+ syend = 21 - 1 - wrapped;
+ if (syend > (yend - ybegin)) syend = yend - ybegin;
+ }
+
+ vic3->sprites[i].line = wrapped;
+
+ if (SPRITE_MULTICOLOR (i))
+ vic3_draw_sprite_multi(device, i, yoff + ybegin, 0, 0, start_x, end_x);
+ else
+ vic3_draw_sprite(device, i, yoff + ybegin, 0, 0, start_x, end_x);
+ }
+ else
+ {
+ memset (vic3->sprites[i].paintedline, 0, sizeof (vic3->sprites[i].paintedline));
+ }
+ }
+ line += 1 + yend - ybegin;
+ }
+
+ // left border
+ if ((start_x <= VIC2_STARTVISIBLECOLUMNS) && (end_x >= xbegin))
+ vic3->bitmap->plot_box(VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xbegin - VIC2_STARTVISIBLECOLUMNS, 1, FRAMECOLOR);
+ else if ((start_x > VIC2_STARTVISIBLECOLUMNS) && (end_x >= xbegin))
+ vic3->bitmap->plot_box(start_x, first + FIRSTLINE, xbegin - start_x, 1, FRAMECOLOR);
+ else if ((start_x <= VIC2_STARTVISIBLECOLUMNS) && (end_x < xbegin))
+ vic3->bitmap->plot_box(VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x, 1, FRAMECOLOR);
+ else if ((start_x > VIC2_STARTVISIBLECOLUMNS) && (end_x < xbegin))
+ vic3->bitmap->plot_box(start_x, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
+
+ // right border
+ if ((start_x <= xend) && (end_x >= VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS))
+ vic3->bitmap->plot_box(xend, first + FIRSTLINE, VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS - xend, 1, FRAMECOLOR);
+ else if ((start_x > xend) && (end_x >= VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS))
+ vic3->bitmap->plot_box(start_x, first + FIRSTLINE, VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS - start_x, 1, FRAMECOLOR);
+ else if ((start_x <= xend) && (end_x < VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS))
+ vic3->bitmap->plot_box(xend, first + FIRSTLINE, end_x - xend, 1, FRAMECOLOR);
+ else if ((start_x > VIC2_STARTVISIBLECOLUMNS) && (end_x < xbegin))
+ vic3->bitmap->plot_box(start_x, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
+
+ if (first + 1 < vic3->bitmap->height())
+ end = first + 1;
+ else
+ end = vic3->bitmap->height();
+
+ // bottom border
+ if (line < end)
+ {
+ if ((start_x <= xbegin) && (end_x >= xend))
+ vic3->bitmap->plot_box(xbegin, first + FIRSTLINE, xend - xbegin, 1, FRAMECOLOR);
+ if ((start_x > xbegin) && (end_x >= xend))
+ vic3->bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xend - start_x, 1, FRAMECOLOR);
+ if ((start_x <= xbegin) && (end_x < xend))
+ vic3->bitmap->plot_box(xbegin, first + FIRSTLINE, end_x - xbegin , 1, FRAMECOLOR);
+ if ((start_x > xbegin) && (end_x < xend))
+ vic3->bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
+ line = end;
+ }
+}
+
+/*****************************************************************************
+ I/O HANDLERS
+*****************************************************************************/
+
+WRITE8_DEVICE_HANDLER( vic3_palette_w )
+{
+ vic3_state *vic3 = get_safe_token(device);
+
+ if (offset < 0x100)
+ vic3->palette_red[offset] = data;
+ else if (offset < 0x200)
+ vic3->palette_green[offset & 0xff] = data;
+ else
+ vic3->palette_blue[offset & 0xff] = data;
+
+ vic3->palette_dirty = 1;
+}
+
+
+WRITE8_DEVICE_HANDLER( vic3_port_w )
+{
+ vic3_state *vic3 = get_safe_token(device);
+
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ offset &= 0x7f;
+
+ /* offsets 0x00 -> 0x2e coincide with VICII */
+ switch (offset)
+ {
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ case 0x09:
+ case 0x0b:
+ case 0x0d:
+ case 0x0f:
+ /* sprite y positions */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->sprites[offset / 2].y = SPRITE_Y_POS(offset / 2);
+ }
+ break;
+
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ case 0x08:
+ case 0x0a:
+ case 0x0c:
+ case 0x0e:
+ /* sprite x positions */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->sprites[offset / 2].x = SPRITE_X_POS(offset / 2);
+ }
+ break;
+
+ case 0x10: /* sprite x positions */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->sprites[0].x = SPRITE_X_POS(0);
+ vic3->sprites[1].x = SPRITE_X_POS(1);
+ vic3->sprites[2].x = SPRITE_X_POS(2);
+ vic3->sprites[3].x = SPRITE_X_POS(3);
+ vic3->sprites[4].x = SPRITE_X_POS(4);
+ vic3->sprites[5].x = SPRITE_X_POS(5);
+ vic3->sprites[6].x = SPRITE_X_POS(6);
+ vic3->sprites[7].x = SPRITE_X_POS(7);
+ }
+ break;
+
+ case 0x17: /* sprite y size */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ }
+ break;
+
+ case 0x1d: /* sprite x size */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ }
+ break;
+
+ case 0x1b: /* sprite background priority */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ }
+ break;
+
+ case 0x1c: /* sprite multicolor mode select */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ }
+ break;
+
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ /* sprite colors */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ }
+ break;
+
+ case 0x25: /* sprite multicolor */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->spritemulti[1] = SPRITE_MULTICOLOR1;
+ }
+ break;
+
+ case 0x26: /* sprite multicolor */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->spritemulti[3] = SPRITE_MULTICOLOR2;
+ }
+ break;
+
+ case 0x19:
+ vic3_clear_interrupt(device->machine(), data & 0x0f, vic3);
+ break;
+
+ case 0x1a: /* irq mask */
+ vic3->reg[offset] = data;
+ vic3_set_interrupt(device->machine(), 0, vic3); // beamrider needs this
+ break;
+
+ case 0x11:
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ if (LINES25)
+ {
+ vic3->y_begin = 0;
+ vic3->y_end = vic3->y_begin + 200;
+ }
+ else
+ {
+ vic3->y_begin = 4;
+ vic3->y_end = vic3->y_begin + 192;
+ }
+ }
+ break;
+
+ case 0x12:
+ if (data != vic3->reg[offset])
+ {
+ vic3->reg[offset] = data;
+ }
+ break;
+
+ case 0x16:
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->x_begin = HORIZONTALPOS;
+ vic3->x_end = vic3->x_begin + 320;
+ }
+ break;
+
+ case 0x18:
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->videoaddr = VIDEOADDR;
+ vic3->chargenaddr = CHARGENADDR;
+ vic3->bitmapaddr = BITMAPADDR;
+ }
+ break;
+
+ case 0x21: /* background color */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->mono[0] = vic3->bitmapmulti[0] = vic3->multi[0] = vic3->colors[0] = BACKGROUNDCOLOR;
+ }
+ break;
+
+ case 0x22: /* background color 1 */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->multi[1] = vic3->colors[1] = MULTICOLOR1;
+ }
+ break;
+
+ case 0x23: /* background color 2 */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->multi[2] = vic3->colors[2] = MULTICOLOR2;
+ }
+ break;
+
+ case 0x24: /* background color 3 */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ vic3->colors[3] = FOREGROUNDCOLOR;
+ }
+ break;
+
+ case 0x20: /* framecolor */
+ if (vic3->reg[offset] != data)
+ {
+ vic3->reg[offset] = data;
+ }
+ break;
+
+ case 0x2f:
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ vic3->reg[offset] = data;
+ break;
+ case 0x30:
+ vic3->reg[offset] = data;
+ if (vic3->port_changed!=NULL) {
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ vic3->reg[offset] = data;
+ vic3->port_changed(device->machine(), data);
+ }
+ break;
+ case 0x31:
+ vic3->reg[offset] = data;
+ if (data & 0x40)
+ vic3->cpu->set_clock_scale(1.0);
+ else
+ vic3->cpu->set_clock_scale(1.0/3.5);
+ break;
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ vic3->reg[offset] = data;
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ DBG_LOG(2, "vic plane write", ("%.2x:%.2x\n", offset, data));
+ break;
+ default:
+ vic3->reg[offset] = data;
+ break;
+ }
+}
+
+READ8_DEVICE_HANDLER( vic3_port_r )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int val = 0;
+ offset &= 0x7f;
+
+ /* offsets 0x00 -> 0x2e coincide with VICII */
+ switch (offset)
+ {
+ case 0x11:
+ val = (vic3->reg[offset] & ~0x80) | ((vic3->rasterline & 0x100) >> 1);
+ break;
+
+ case 0x12:
+ val = vic3->rasterline & 0xff;
+ break;
+
+ case 0x16:
+ val = vic3->reg[offset] | 0xc0;
+ break;
+
+ case 0x18:
+ val = vic3->reg[offset] | 0x01;
+ break;
+
+ case 0x19: /* interrupt flag register */
+ /* vic2_clear_interrupt(0xf); */
+ val = vic3->reg[offset] | 0x70;
+ break;
+
+ case 0x1a:
+ val = vic3->reg[offset] | 0xf0;
+ break;
+
+ case 0x1e: /* sprite to sprite collision detect */
+ val = vic3->reg[offset];
+ vic3->reg[offset] = 0;
+ vic3_clear_interrupt(device->machine(), 4, vic3);
+ break;
+
+ case 0x1f: /* sprite to background collision detect */
+ val = vic3->reg[offset];
+ vic3->reg[offset] = 0;
+ vic3_clear_interrupt(device->machine(), 2, vic3);
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ val = vic3->reg[offset];
+ break;
+
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ case 0x10:
+ case 0x17:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ val = vic3->reg[offset];
+ break;
+
+ case 0x2f:
+ case 0x30:
+ val = vic3->reg[offset];
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ break;
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f: /* not used */
+ val = vic3->reg[offset];
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ DBG_LOG(2, "vic3 plane read", ("%.2x:%.2x\n", offset, val));
+ break;
+ default:
+ val = vic3->reg[offset];
+ }
+ return val;
+}
+
+
+#define VIC3_MASK(M) \
+ if (M) \
+ { \
+ if (M & 0x01) \
+ colors[0] = vic3->c64_mem_r(device->machine(), VIC3_ADDR(0) + offset); \
+ if (M & 0x02) \
+ colors[1] = vic3->c64_mem_r(device->machine(), VIC3_ADDR(1) + offset) << 1; \
+ if (M & 0x04) \
+ colors[2] = vic3->c64_mem_r(device->machine(), VIC3_ADDR(2) + offset) << 2; \
+ if (M & 0x08) \
+ colors[3] = vic3->c64_mem_r(device->machine(), VIC3_ADDR(3) + offset) << 3; \
+ if (M & 0x10) \
+ colors[4] = vic3->c64_mem_r(device->machine(), VIC3_ADDR(4) + offset) << 4; \
+ if (M & 0x20) \
+ colors[5] = vic3->c64_mem_r(device->machine(), VIC3_ADDR(5) + offset) << 5; \
+ if (M & 0x40) \
+ colors[6] = vic3->c64_mem_r(device->machine(), VIC3_ADDR(6) + offset) << 6; \
+ if (M & 0x80) \
+ colors[7] = vic3->c64_mem_r(device->machine(), VIC3_ADDR(7) + offset) << 7; \
+ for (i = 7; i >= 0; i--) \
+ { \
+ p = 0; \
+ if (M & 0x01) \
+ { \
+ p = colors[0] & 0x01; \
+ colors[0] >>= 1; \
+ } \
+ if (M & 0x02) \
+ { \
+ p |= colors[1] & 0x02; \
+ colors[1] >>= 1; \
+ } \
+ if (M & 0x04) \
+ { \
+ p |= colors[2] & 0x04; \
+ colors[2] >>= 1; \
+ } \
+ if (M & 0x08) \
+ { \
+ p |= colors[3] & 0x08; \
+ colors[3] >>= 1; \
+ } \
+ if (M & 0x10) \
+ { \
+ p |= colors[4] & 0x10; \
+ colors[4] >>= 1; \
+ } \
+ if (M & 0x20) \
+ { \
+ p |= colors[5] & 0x20; \
+ colors[5] >>= 1; \
+ } \
+ if (M & 0x40) \
+ { \
+ p |= colors[6] & 0x40; \
+ colors[6] >>= 1; \
+ } \
+ if (M & 0x80) \
+ { \
+ p |= colors[7] & 0x80; \
+ colors[7] >>= 1; \
+ } \
+ vic3->bitmap->pix16(YPOS + y, XPOS + x + i) = p; \
+ } \
+ }
+
+#define VIC3_ADDR(a) VIC3_BITPLANE_IADDR(a)
+static void vic3_interlace_draw_block( device_t *device, int x, int y, int offset )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int colors[8] = {0};
+ int i, p;
+
+ switch (VIC3_BITPLANES_MASK)
+ {
+ case 0x05:
+ VIC3_MASK(0x05)
+ break;
+ case 0x07:
+ VIC3_MASK(0x07)
+ break;
+ case 0x0f:
+ VIC3_MASK(0x0f)
+ break;
+ case 0x1f:
+ VIC3_MASK(0x1f)
+ break;
+ case 0x7f:
+ VIC3_MASK(0x7f)
+ break;
+ case 0xff:
+ VIC3_MASK(0xff)
+ break;
+ default:
+ if (VIC3_BITPLANES_MASK & 0x01)
+ colors[0] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_IADDR(0) + offset);
+
+ if (VIC3_BITPLANES_MASK & 0x02)
+ colors[1] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_IADDR(1) + offset) << 1;
+
+ if (VIC3_BITPLANES_MASK & 0x04)
+ colors[2] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_IADDR(2) + offset) << 2;
+
+ if (VIC3_BITPLANES_MASK & 0x08)
+ colors[3] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_IADDR(3) + offset) << 3;
+
+ if (VIC3_BITPLANES_MASK & 0x10)
+ colors[4] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_IADDR(4) + offset) << 4;
+
+ if (VIC3_BITPLANES_MASK & 0x20)
+ colors[5] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_IADDR(5) + offset) << 5;
+
+ if (VIC3_BITPLANES_MASK & 0x40)
+ colors[6] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_IADDR(6) + offset) << 6;
+
+ if (VIC3_BITPLANES_MASK & 0x80)
+ colors[7] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_IADDR(7) + offset) << 7;
+
+ for (i = 7; i >= 0; i--)
+ {
+ vic3->bitmap->pix16(YPOS + y, XPOS + x + i) =
+ (colors[0] & 0x01) | (colors[1] & 0x02)
+ | (colors[2] & 0x04) | (colors[3] & 0x08)
+ | (colors[4] & 0x10) | (colors[5] & 0x20)
+ | (colors[6] & 0x40) | (colors[7] & 0x80);
+ colors[0] >>= 1;
+ colors[1] >>= 1;
+ colors[2] >>= 1;
+ colors[3] >>= 1;
+ colors[4] >>= 1;
+ colors[5] >>= 1;
+ colors[6] >>= 1;
+ colors[7] >>= 1;
+ }
+ }
+}
+
+#undef VIC3_ADDR
+#define VIC3_ADDR(a) VIC3_BITPLANE_ADDR(a)
+static void vic3_draw_block( device_t *device, int x, int y, int offset )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int colors[8] = {0};
+ int i, p;
+
+ switch (VIC3_BITPLANES_MASK)
+ {
+ case 5:
+ VIC3_MASK(0x05)
+ break;
+ case 7:
+ VIC3_MASK(0x07)
+ break;
+ case 0xf:
+ VIC3_MASK(0x0f)
+ break;
+ case 0x1f:
+ VIC3_MASK(0x1f)
+ break;
+ case 0x7f:
+ VIC3_MASK(0x7f)
+ break;
+ case 0xff:
+ VIC3_MASK(0xff)
+ break;
+ default:
+ if (VIC3_BITPLANES_MASK & 0x01)
+ colors[0] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_ADDR(0) + offset);
+
+ if (VIC3_BITPLANES_MASK & 0x02)
+ colors[1] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_ADDR(1) + offset) << 1;
+
+ if (VIC3_BITPLANES_MASK & 0x04)
+ colors[2] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_ADDR(2) + offset) << 2;
+
+ if (VIC3_BITPLANES_MASK & 0x08)
+ colors[3] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_ADDR(3) + offset) << 3;
+
+ if (VIC3_BITPLANES_MASK & 0x10)
+ colors[4] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_ADDR(4) + offset) << 4;
+
+ if (VIC3_BITPLANES_MASK & 0x20)
+ colors[5] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_ADDR(5) + offset) << 5;
+
+ if (VIC3_BITPLANES_MASK & 0x40)
+ colors[6] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_ADDR(6) + offset) << 6;
+
+ if (VIC3_BITPLANES_MASK & 0x80)
+ colors[7] = vic3->c64_mem_r(device->machine(), VIC3_BITPLANE_ADDR(7) + offset) << 7;
+
+ for (i = 7; i >= 0; i--)
+ {
+ vic3->bitmap->pix16(YPOS + y, XPOS + x + i) =
+ (colors[0] & 0x01) | (colors[1] & 0x02)
+ | (colors[2] & 0x04) | (colors[3] & 0x08)
+ | (colors[4] & 0x10) | (colors[5] & 0x20)
+ | (colors[6] & 0x40) | (colors[7] & 0x80);
+ colors[0] >>= 1;
+ colors[1] >>= 1;
+ colors[2] >>= 1;
+ colors[3] >>= 1;
+ colors[4] >>= 1;
+ colors[5] >>= 1;
+ colors[6] >>= 1;
+ colors[7] >>= 1;
+ }
+ }
+}
+
+
+static void vic3_draw_bitplanes( device_t *device )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int x, y, y1s, offset;
+ rectangle vis;
+ const rectangle &visarea = vic3->main_screen->visible_area();
+
+ if (VIC3_LINES == 400)
+ { /* interlaced! */
+ for (y1s = 0, offset = 0; y1s < 400; y1s += 16)
+ {
+ for (x = 0; x < VIC3_BITPLANES_WIDTH; x += 8)
+ {
+ for (y = y1s; y < y1s + 16; y += 2, offset++)
+ {
+ if (vic3->interlace)
+ vic3_draw_block(device, x, y, offset);
+ else
+ vic3_interlace_draw_block(device, x, y + 1, offset);
+ }
+ }
+ }
+ vic3->interlace ^= 1;
+ }
+ else
+ {
+ for (y1s = 0, offset = 0; y1s < 200; y1s += 8)
+ {
+ for (x = 0; x < VIC3_BITPLANES_WIDTH; x += 8)
+ {
+ for (y = y1s; y < y1s + 8; y++, offset++)
+ {
+ vic3_draw_block(device, x, y, offset);
+ }
+ }
+ }
+ }
+
+ if (XPOS > 0)
+ {
+ vis.set(0, XPOS - 1, 0, visarea.max_y);
+ vic3->bitmap->fill(FRAMECOLOR, vis);
+ }
+
+ if (XPOS + VIC3_BITPLANES_WIDTH < visarea.max_x)
+ {
+ vis.set(XPOS + VIC3_BITPLANES_WIDTH, visarea.max_x, 0, visarea.max_y);
+ vic3->bitmap->fill(FRAMECOLOR, vis);
+ }
+
+ if (YPOS > 0)
+ {
+ vis.set(0, visarea.max_x, 0, YPOS - 1);
+ vic3->bitmap->fill(FRAMECOLOR, vis);
+ }
+
+ if (YPOS + VIC3_LINES < visarea.max_y)
+ {
+ vis.set(0, visarea.max_x, YPOS + VIC3_LINES, visarea.max_y);
+ vic3->bitmap->fill(FRAMECOLOR, vis);
+ }
+}
+
+void vic3_raster_interrupt_gen( device_t *device )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ running_machine &machine = device->machine();
+ int new_columns, new_rows;
+ int i;
+
+ vic3->rasterline++;
+ if (vic3->rasterline >= vic3->lines)
+ {
+ vic3->rasterline = 0;
+ if (vic3->palette_dirty)
+ for (i = 0; i < 256; i++)
+ palette_set_color_rgb(machine, i, vic3->palette_red[i] << 4, vic3->palette_green[i] << 4, vic3->palette_blue[i] << 4);
+
+ if (vic3->palette_dirty)
+ {
+ vic3->spritemulti[1] = SPRITE_MULTICOLOR1;
+ vic3->spritemulti[3] = SPRITE_MULTICOLOR2;
+ vic3->mono[0] = vic3->bitmapmulti[0] = vic3->multi[0] = vic3->colors[0] = BACKGROUNDCOLOR;
+ vic3->multi[1] = vic3->colors[1] = MULTICOLOR1;
+ vic3->multi[2] = vic3->colors[2] = MULTICOLOR2;
+ vic3->colors[3] = FOREGROUNDCOLOR;
+ vic3->palette_dirty = 0;
+ }
+
+ new_rows = 200;
+
+ if (VIC3_BITPLANES)
+ {
+ new_columns = VIC3_BITPLANES_WIDTH;
+ if (new_columns < 320)
+ new_columns = 320; /*sprites resolution about 320x200 */
+ new_rows = VIC3_LINES;
+ }
+ else if (VIC3_80COLUMNS)
+ {
+ new_columns = 640;
+ }
+ else
+ {
+ new_columns = 320;
+ }
+ if ((new_columns != vic3->columns) || (new_rows != vic3->rows))
+ {
+ vic3->rows = new_rows;
+ vic3->columns = new_columns;
+ if (vic3->type == VIC4567_PAL)
+ vic3->main_screen->set_visible_area(
+ VIC2_STARTVISIBLECOLUMNS + 32,
+ VIC2_STARTVISIBLECOLUMNS + 32 + vic3->columns + 16 - 1,
+ VIC2_STARTVISIBLELINES + 34,
+ VIC2_STARTVISIBLELINES + 34 + vic3->rows + 16 - 1);
+ else
+ vic3->main_screen->set_visible_area(
+ VIC2_STARTVISIBLECOLUMNS + 34,
+ VIC2_STARTVISIBLECOLUMNS + 34 + vic3->columns + 16 - 1,
+ VIC2_STARTVISIBLELINES + 10,
+ VIC2_STARTVISIBLELINES + 10 + vic3->rows + 16 - 1);
+ }
+ if (VIC3_BITPLANES)
+ {
+ vic3_draw_bitplanes(device);
+ }
+ else
+ {
+ if (vic3->type == VIC4567_PAL)
+ {
+ if (vic3->on)
+ vic2_drawlines(device, vic3->lastline, vic3->lines, VIC2_STARTVISIBLECOLUMNS + 32, VIC2_STARTVISIBLECOLUMNS + 32 + vic3->columns + 16 - 1);
+ }
+ else
+ {
+ if (vic3->on)
+ vic2_drawlines(device, vic3->lastline, vic3->lines, VIC2_STARTVISIBLECOLUMNS + 34, VIC2_STARTVISIBLECOLUMNS + 34 + vic3->columns + 16 - 1);
+ }
+ }
+
+ for (i = 0; i < 8; i++)
+ vic3->sprites[i].repeat = vic3->sprites[i].line = 0;
+
+ vic3->lastline = 0;
+
+ if (LIGHTPEN_BUTTON)
+ {
+ /* lightpen timer start */
+ machine.scheduler().timer_set(attotime(0, 0), FUNC(vic3_timer_timeout), 1, vic3);
+ }
+
+ }
+
+ if (vic3->rasterline == C64_2_RASTERLINE(RASTERLINE))
+ {
+ vic3_set_interrupt(machine, 1, vic3);
+ }
+
+ if (vic3->on)
+ if ((vic3->rasterline >= VIC2_FIRSTRASTERLINE) && (vic3->rasterline < (VIC2_FIRSTRASTERLINE + VIC2_VISIBLELINES)))
+ {
+ if (vic3->type == VIC4567_PAL)
+ {
+ if (vic3->on)
+ vic2_drawlines(device, vic3->rasterline - 1, vic3->rasterline, VIC2_STARTVISIBLECOLUMNS + 32, VIC2_STARTVISIBLECOLUMNS + 32 + vic3->columns + 16 - 1);
+ }
+ else
+ {
+ if (vic3->on)
+ vic2_drawlines(device, vic3->rasterline - 1, vic3->rasterline, VIC2_STARTVISIBLECOLUMNS + 34, VIC2_STARTVISIBLECOLUMNS + 34 + vic3->columns + 16 - 1);
+ }
+ }
+}
+
+UINT32 vic3_video_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect )
+{
+ vic3_state *vic3 = get_safe_token(device);
+
+ copybitmap(bitmap, *vic3->bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( vic3 )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ const vic3_interface *intf = (vic3_interface *)device->static_config();
+ int width, height;
+ int i;
+
+ vic3->cpu = device->machine().device(intf->cpu);
+
+ vic3->main_screen = device->machine().device<screen_device>(intf->screen);
+ width = vic3->main_screen->width();
+ height = vic3->main_screen->height();
+
+ vic3->bitmap = auto_bitmap_ind16_alloc(device->machine(), width, height);
+
+ vic3->type = intf->type;
+
+ vic3->dma_read = intf->dma_read;
+ vic3->dma_read_color = intf->dma_read_color;
+ vic3->interrupt = intf->irq;
+
+ vic3->port_changed = intf->port_changed;
+
+ vic3->c64_mem_r = intf->c64_mem_r;
+
+ vic3->lightpen_button_cb = intf->button_cb;
+ vic3->lightpen_x_cb = intf->x_cb;
+ vic3->lightpen_y_cb = intf->y_cb;
+
+ vic3->screen[0] = auto_alloc_array(device->machine(), UINT8, 216 * 656 / 8);
+
+ for (i = 1; i < 216; i++)
+ vic3->screen[i] = vic3->screen[i - 1] + 656 / 8;
+
+ for (i = 0; i < 256; i++)
+ {
+ vic3->foreground[i] = 0;
+ if ((i & 3) > 1)
+ vic3->foreground[i] |= 0x3;
+ if ((i & 0xc) > 0x4)
+ vic3->foreground[i] |= 0xc;
+ if ((i & 0x30) > 0x10)
+ vic3->foreground[i] |= 0x30;
+ if ((i & 0xc0) > 0x40)
+ vic3->foreground[i] |= 0xc0;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ vic3->expandx[i] = 0;
+ if (i & 1)
+ vic3->expandx[i] |= 3;
+ if (i & 2)
+ vic3->expandx[i] |= 0xc;
+ if (i & 4)
+ vic3->expandx[i] |= 0x30;
+ if (i & 8)
+ vic3->expandx[i] |= 0xc0;
+ if (i & 0x10)
+ vic3->expandx[i] |= 0x300;
+ if (i & 0x20)
+ vic3->expandx[i] |= 0xc00;
+ if (i & 0x40)
+ vic3->expandx[i] |= 0x3000;
+ if (i & 0x80)
+ vic3->expandx[i] |= 0xc000;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ vic3->expandx_multi[i] = 0;
+ if (i & 1)
+ vic3->expandx_multi[i] |= 5;
+ if (i & 2)
+ vic3->expandx_multi[i] |= 0xa;
+ if (i & 4)
+ vic3->expandx_multi[i] |= 0x50;
+ if (i & 8)
+ vic3->expandx_multi[i] |= 0xa0;
+ if (i & 0x10)
+ vic3->expandx_multi[i] |= 0x500;
+ if (i & 0x20)
+ vic3->expandx_multi[i] |= 0xa00;
+ if (i & 0x40)
+ vic3->expandx_multi[i] |= 0x5000;
+ if (i & 0x80)
+ vic3->expandx_multi[i] |= 0xa000;
+ }
+
+ device->save_item(NAME(vic3->reg));
+
+ device->save_item(NAME(vic3->on));
+
+ //device->save_item(NAME(vic3->bitmap));
+
+ device->save_item(NAME(vic3->lines));
+
+ device->save_item(NAME(vic3->chargenaddr));
+ device->save_item(NAME(vic3->videoaddr));
+ device->save_item(NAME(vic3->bitmapaddr));
+
+ device->save_item(NAME(vic3->x_begin));
+ device->save_item(NAME(vic3->x_end));
+ device->save_item(NAME(vic3->y_begin));
+ device->save_item(NAME(vic3->y_end));
+
+ device->save_item(NAME(vic3->c64_bitmap));
+ device->save_item(NAME(vic3->bitmapmulti));
+ device->save_item(NAME(vic3->mono));
+ device->save_item(NAME(vic3->multi));
+ device->save_item(NAME(vic3->ecmcolor));
+ device->save_item(NAME(vic3->colors));
+ device->save_item(NAME(vic3->spritemulti));
+
+ device->save_item(NAME(vic3->lastline));
+ device->save_item(NAME(vic3->rasterline));
+ device->save_item(NAME(vic3->interlace));
+
+ device->save_item(NAME(vic3->columns));
+ device->save_item(NAME(vic3->rows));
+
+ device->save_item(NAME(vic3->shift));
+ device->save_item(NAME(vic3->foreground));
+ device->save_item(NAME(vic3->multi_collision));
+
+ device->save_item(NAME(vic3->palette_red));
+ device->save_item(NAME(vic3->palette_green));
+ device->save_item(NAME(vic3->palette_blue));
+ device->save_item(NAME(vic3->palette_dirty));
+
+ for (i = 0; i < 8; i++)
+ {
+ device->save_item(NAME(vic3->sprites[i].x), i);
+ device->save_item(NAME(vic3->sprites[i].y), i);
+ device->save_item(NAME(vic3->sprites[i].repeat), i);
+ device->save_item(NAME(vic3->sprites[i].line), i);
+ device->save_item(NAME(vic3->sprites[i].paintedline), i);
+ device->save_item(NAME(vic3->sprites[i].bitmap[0]), i);
+ device->save_item(NAME(vic3->sprites[i].bitmap[1]), i);
+ device->save_item(NAME(vic3->sprites[i].bitmap[2]), i);
+ device->save_item(NAME(vic3->sprites[i].bitmap[3]), i);
+ device->save_item(NAME(vic3->sprites[i].bitmap[4]), i);
+ device->save_item(NAME(vic3->sprites[i].bitmap[5]), i);
+ device->save_item(NAME(vic3->sprites[i].bitmap[6]), i);
+ device->save_item(NAME(vic3->sprites[i].bitmap[7]), i);
+ }
+}
+
+static DEVICE_RESET( vic3 )
+{
+ vic3_state *vic3 = get_safe_token(device);
+ int i;
+
+ memset(vic3->reg, 0, ARRAY_LENGTH(vic3->reg));
+
+ vic3->on = 1;
+
+ vic3->interlace = 0;
+ vic3->columns = 640;
+ vic3->rows = 200;
+ vic3->lines = VIC2_LINES;
+
+ memset(&vic3->sprites, 0, sizeof(vic3->sprites));
+
+ vic3->chargenaddr = 0;
+ vic3->videoaddr = 0;
+ vic3->bitmapaddr = 0;
+
+ vic3->x_begin = 0;
+ vic3->x_end = 0;
+ vic3->y_begin = 0;
+ vic3->y_end = 0;
+
+ for (i = 0; i < 2; i++)
+ {
+ vic3->c64_bitmap[i] = 0;
+ vic3->mono[i] = 0;
+ vic3->ecmcolor[i] = 0;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ vic3->bitmapmulti[i] = 0;
+ vic3->multi[i] = 0;
+ vic3->colors[i] = 0;
+ vic3->spritemulti[i] = 0;
+ }
+
+ vic3->lastline = 0;
+ vic3->rasterline = 0;
+
+ memset(vic3->shift, 0, ARRAY_LENGTH(vic3->shift));
+ memset(vic3->multi_collision, 0, ARRAY_LENGTH(vic3->multi_collision));
+ memset(vic3->palette_red, 0, ARRAY_LENGTH(vic3->palette_red));
+ memset(vic3->palette_green, 0, ARRAY_LENGTH(vic3->palette_green));
+ memset(vic3->palette_blue, 0, ARRAY_LENGTH(vic3->palette_blue));
+
+ vic3->palette_dirty = 0;
+}
+
+
+/*-------------------------------------------------
+ device definition
+-------------------------------------------------*/
+
+static const char DEVTEMPLATE_SOURCE[] = __FILE__;
+
+#define DEVTEMPLATE_ID(p,s) p##vic3##s
+#define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET
+#define DEVTEMPLATE_NAME "4567 VIC III"
+#define DEVTEMPLATE_FAMILY "4567 VIC III"
+#include "devtempl.h"
+
+DEFINE_LEGACY_DEVICE(VIC3, vic3);
diff --git a/src/mess/video/vic4567.h b/src/mess/video/vic4567.h
new file mode 100644
index 00000000000..4dc36dd5b09
--- /dev/null
+++ b/src/mess/video/vic4567.h
@@ -0,0 +1,157 @@
+/*****************************************************************************
+ *
+ * video/vic4567.h
+ *
+ ****************************************************************************/
+
+#ifndef __VIC4567_H__
+#define __VIC4567_H__
+
+#include "devcb.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef UINT8 (*vic3_lightpen_x_callback)(running_machine &machine);
+typedef UINT8 (*vic3_lightpen_y_callback)(running_machine &machine);
+typedef UINT8 (*vic3_lightpen_button_callback)(running_machine &machine);
+
+typedef int (*vic3_dma_read)(running_machine &machine, int);
+typedef int (*vic3_dma_read_color)(running_machine &machine, int);
+typedef void (*vic3_irq) (running_machine &, int);
+
+typedef void (*vic3_port_changed_callback) (running_machine &, int);
+
+typedef UINT8 (*vic3_c64mem_callback)(running_machine &machine, int offset);
+
+typedef enum
+{
+ VIC4567_NTSC,
+ VIC4567_PAL
+} vic3_type;
+
+typedef struct _vic3_interface vic3_interface;
+struct _vic3_interface
+{
+ const char *screen;
+ const char *cpu;
+
+ vic3_type type;
+
+ vic3_lightpen_x_callback x_cb;
+ vic3_lightpen_y_callback y_cb;
+ vic3_lightpen_button_callback button_cb;
+
+ vic3_dma_read dma_read;
+ vic3_dma_read_color dma_read_color;
+ vic3_irq irq;
+
+ vic3_port_changed_callback port_changed;
+
+ vic3_c64mem_callback c64_mem_r;
+};
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define VIC6567_CLOCK (1022700 /* = 8181600 / 8) */ )
+#define VIC6569_CLOCK ( 985248 /* = 7881984 / 8) */ )
+
+#define VIC6567_CYCLESPERLINE 65
+#define VIC6569_CYCLESPERLINE 63
+
+#define VIC6567_LINES 263
+#define VIC6569_LINES 312
+
+#define VIC6567_VRETRACERATE (59.8245100906698 /* = 1022700 / (65 * 263) */ )
+#define VIC6569_VRETRACERATE (50.1245421245421 /* = 985248 / (63 * 312) */ )
+
+#define VIC6567_HRETRACERATE (VIC6567_CLOCK / VIC6567_CYCLESPERLINE)
+#define VIC6569_HRETRACERATE (VIC6569_CLOCK / VIC6569_CYCLESPERLINE)
+
+#define VIC2_HSIZE 320
+#define VIC2_VSIZE 200
+
+#define VIC6567_VISIBLELINES 235
+#define VIC6569_VISIBLELINES 284
+
+#define VIC6567_FIRST_DMA_LINE 0x30
+#define VIC6569_FIRST_DMA_LINE 0x30
+
+#define VIC6567_LAST_DMA_LINE 0xf7
+#define VIC6569_LAST_DMA_LINE 0xf7
+
+#define VIC6567_FIRST_DISP_LINE 0x29
+#define VIC6569_FIRST_DISP_LINE 0x10
+
+#define VIC6567_LAST_DISP_LINE (VIC6567_FIRST_DISP_LINE + VIC6567_VISIBLELINES - 1)
+#define VIC6569_LAST_DISP_LINE (VIC6569_FIRST_DISP_LINE + VIC6569_VISIBLELINES - 1)
+
+#define VIC6567_RASTER_2_EMU(a) ((a >= VIC6567_FIRST_DISP_LINE) ? (a - VIC6567_FIRST_DISP_LINE) : (a + 222))
+#define VIC6569_RASTER_2_EMU(a) (a - VIC6569_FIRST_DISP_LINE)
+
+#define VIC6567_FIRSTCOLUMN 50
+#define VIC6569_FIRSTCOLUMN 50
+
+#define VIC6567_VISIBLECOLUMNS 418
+#define VIC6569_VISIBLECOLUMNS 403
+
+#define VIC6567_X_2_EMU(a) (a)
+#define VIC6569_X_2_EMU(a) (a)
+
+#define VIC6567_STARTVISIBLELINES ((VIC6567_LINES - VIC6567_VISIBLELINES)/2)
+#define VIC6569_STARTVISIBLELINES 16 /* ((VIC6569_LINES - VIC6569_VISIBLELINES)/2) */
+
+#define VIC6567_FIRSTRASTERLINE 34
+#define VIC6569_FIRSTRASTERLINE 0
+
+#define VIC6567_COLUMNS 512
+#define VIC6569_COLUMNS 504
+
+
+#define VIC6567_STARTVISIBLECOLUMNS ((VIC6567_COLUMNS - VIC6567_VISIBLECOLUMNS)/2)
+#define VIC6569_STARTVISIBLECOLUMNS ((VIC6569_COLUMNS - VIC6569_VISIBLECOLUMNS)/2)
+
+#define VIC6567_FIRSTRASTERCOLUMNS 412
+#define VIC6569_FIRSTRASTERCOLUMNS 404
+
+#define VIC6569_FIRST_X 0x194
+#define VIC6567_FIRST_X 0x19c
+
+#define VIC6569_FIRST_VISIBLE_X 0x1e0
+#define VIC6567_FIRST_VISIBLE_X 0x1e8
+
+#define VIC6569_MAX_X 0x1f7
+#define VIC6567_MAX_X 0x1ff
+
+#define VIC6569_LAST_VISIBLE_X 0x17c
+#define VIC6567_LAST_VISIBLE_X 0x184
+
+#define VIC6569_LAST_X 0x193
+#define VIC6567_LAST_X 0x19b
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(VIC3, vic3);
+
+#define MCFG_VIC3_ADD(_tag, _interface) \
+ MCFG_DEVICE_ADD(_tag, VIC3, 0) \
+ MCFG_DEVICE_CONFIG(_interface)
+
+
+/*----------- defined in video/vic4567.c -----------*/
+
+WRITE8_DEVICE_HANDLER( vic3_port_w );
+WRITE8_DEVICE_HANDLER( vic3_palette_w );
+READ8_DEVICE_HANDLER( vic3_port_r );
+
+void vic3_raster_interrupt_gen( device_t *device );
+UINT32 vic3_video_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect );
+
+
+#endif /* __VIC4567_H__ */
diff --git a/src/mess/video/vic6567.c b/src/mess/video/vic6567.c
new file mode 100644
index 00000000000..aeac999dea7
--- /dev/null
+++ b/src/mess/video/vic6567.c
@@ -0,0 +1,2815 @@
+/***************************************************************************
+
+ Video Interface Chip (6567R8 for NTSC system and 6569 for PAL system)
+
+ original emulation by PeT (mess@utanet.at)
+
+ A part of the code (cycle routine and drawing routines) is a modified version of the vic ii emulation used in
+ commodore 64 emulator "frodo" by Christian Bauer
+
+ http://frodo.cebix.net/
+ The rights on the source code remain at the author.
+ It may not - not even in parts - used for commercial purposes without explicit written permission by the author.
+ Permission to use it for non-commercial purposes is hereby granted als long as my copyright notice remains in the program.
+ You are not allowed to use the source to create and distribute a modified version of Frodo.
+
+ 2010-02: converted to be a device and split vic III emulation (which still uses old cycle & drawing routines)
+
+ TODO:
+ - plenty of cleanups
+ - emulate variants of the vic chip
+ - update vic III to use new code for the vic II compatibility
+
+***************************************************************************/
+/* mos videochips
+ vic (6560 NTSC, 6561 PAL)
+ used in commodore vic20
+
+ vic II
+ 6566 NTSC
+ no dram refresh?
+ 6567 NTSC
+ 6569 PAL-B
+ 6572 PAL-N
+ 6573 PAL-M
+ 8562 NTSC
+ 8565 PAL
+ used in commodore c64
+ complete different to vic
+
+ ted
+ 7360/8360 (NTSC-M, PAL-B by same chip ?)
+ 8365 PAL-N
+ 8366 PAL-M
+ used in c16 c116 c232 c264 plus4 c364
+ based on the vic II
+ but no sprites and not register compatible
+ includes timers, input port, sound generators
+ memory interface, dram refresh, clock generation
+
+ vic IIe
+ 8564 NTSC-M
+ 8566 PAL-B
+ 8569 PAL-N
+ used in commodore c128
+ vic II with some additional features
+ 3 programmable output pins k0 k1 k2
+
+ vic III
+ 4567
+ used in commodore c65 prototype
+ vic II compatible (mode only?)
+ several additional features
+ different resolutions, more colors, ...
+ (maybe like in the amiga graphic chip docu)
+
+ vdc
+ 8563
+ 8568 (composite video and composite sync)
+ second graphic chip in c128
+ complete different to above chips
+*/
+
+
+#include "emu.h"
+#include "video/vic6567.h"
+
+typedef struct _vic2_state vic2_state;
+struct _vic2_state
+{
+ vic2_type type;
+
+ screen_device *screen; // screen which sets bitmap properties
+ cpu_device *cpu;
+
+ UINT8 rdy_cycles;
+ UINT8 reg[0x80];
+
+ int on; /* rastering of the screen */
+
+ UINT16 chargenaddr, videoaddr, bitmapaddr;
+
+ bitmap_ind16 *bitmap;
+
+ UINT16 colors[4], spritemulti[4];
+
+ int rasterline;
+ UINT64 cycles_counter;
+ UINT8 cycle;
+ UINT16 raster_x;
+ UINT16 graphic_x;
+
+ /* convert multicolor byte to background/foreground for sprite collision */
+ UINT16 expandx[256];
+ UINT16 expandx_multi[256];
+
+ /* Display */
+ UINT16 dy_start;
+ UINT16 dy_stop;
+
+ /* GFX */
+ UINT8 draw_this_line;
+ UINT8 is_bad_line;
+ UINT8 bad_lines_enabled;
+ UINT8 display_state;
+ UINT8 char_data;
+ UINT8 gfx_data;
+ UINT8 color_data;
+ UINT8 last_char_data;
+ UINT8 matrix_line[40]; // Buffer for video line, read in Bad Lines
+ UINT8 color_line[40]; // Buffer for color line, read in Bad Lines
+ UINT8 vblanking;
+ UINT16 ml_index;
+ UINT8 rc;
+ UINT16 vc;
+ UINT16 vc_base;
+ UINT8 ref_cnt;
+
+ /* Sprites */
+ UINT8 spr_coll_buf[0x400]; // Buffer for sprite-sprite collisions and priorities
+ UINT8 fore_coll_buf[0x400]; // Buffer for foreground-sprite collisions and priorities
+ UINT8 spr_draw_data[8][4]; // Sprite data for drawing
+ UINT8 spr_exp_y;
+ UINT8 spr_dma_on;
+ UINT8 spr_draw;
+ UINT8 spr_disp_on;
+ UINT16 spr_ptr[8];
+ UINT8 spr_data[8][4];
+ UINT16 mc_base[8]; // Sprite data counter bases
+ UINT16 mc[8]; // Sprite data counters
+
+ /* Border */
+ UINT8 border_on;
+ UINT8 ud_border_on;
+ UINT8 border_on_sample[5];
+ UINT8 border_color_sample[0x400 / 8]; // Samples of border color at each "displayed" cycle
+
+ /* Cycles */
+ UINT64 first_ba_cycle;
+ UINT8 device_suspended;
+
+ /* DMA */
+ devcb_resolved_read8 in_dma_read_func;
+ devcb_resolved_read8 in_dma_read_color_func;
+
+ /* IRQ */
+ devcb_resolved_write_line out_interrupt_func;
+
+ /* RDY */
+ devcb_resolved_read8 in_rdy_workaround_func;
+
+ /* lightpen */
+ devcb_resolved_read8 in_lightpen_button_func;
+ devcb_resolved_read8 in_lightpen_x_func;
+ devcb_resolved_read8 in_lightpen_y_func;
+};
+
+
+/*****************************************************************************
+ CONSTANTS
+*****************************************************************************/
+
+#define VERBOSE_LEVEL 0
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_LEVEL >= N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s", machine.time().as_double(), (char*) M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+#define ROW25_YSTART 0x33
+#define ROW25_YSTOP 0xfb
+#define ROW24_YSTART 0x37
+#define ROW24_YSTOP 0xf7
+
+#define RASTERLINE_2_C64(a) (a)
+#define C64_2_RASTERLINE(a) (a)
+#define XPOS (VIC2_STARTVISIBLECOLUMNS + (VIC2_VISIBLECOLUMNS - VIC2_HSIZE) / 2)
+#define YPOS (VIC2_STARTVISIBLELINES /* + (VIC2_VISIBLELINES - VIC2_VSIZE) / 2 */)
+#define FIRSTCOLUMN 50
+
+/* 2008-05 FP: lightpen code needs to read input port from c64.c and cbmb.c */
+
+#define LIGHTPEN_BUTTON (vic2->in_lightpen_button_func(0))
+#define LIGHTPEN_X_VALUE (vic2->in_lightpen_x_func(0))
+#define LIGHTPEN_Y_VALUE (vic2->in_lightpen_y_func(0))
+
+/* lightpen delivers values from internal counters; they do not start with the visual area or frame area */
+#define VIC2_MAME_XPOS 0
+#define VIC2_MAME_YPOS 0
+#define VIC6567_X_BEGIN 38
+#define VIC6567_Y_BEGIN -6 /* first 6 lines after retrace not for lightpen! */
+#define VIC6569_X_BEGIN 38
+#define VIC6569_Y_BEGIN -6
+#define VIC2_X_BEGIN ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_X_BEGIN : VIC6567_X_BEGIN)
+#define VIC2_Y_BEGIN ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_Y_BEGIN : VIC6567_Y_BEGIN)
+#define VIC2_X_VALUE ((LIGHTPEN_X_VALUE / 1.3) + 12)
+#define VIC2_Y_VALUE ((LIGHTPEN_Y_VALUE ) + 10)
+
+#define VIC2E_K0_LEVEL (vic2->reg[0x2f] & 0x01)
+#define VIC2E_K1_LEVEL (vic2->reg[0x2f] & 0x02)
+#define VIC2E_K2_LEVEL (vic2->reg[0x2f] & 0x04)
+
+
+/* sprites 0 .. 7 */
+#define SPRITEON(nr) (vic2->reg[0x15] & (1 << nr))
+#define SPRITE_Y_EXPAND(nr) (vic2->reg[0x17] & (1 << nr))
+#define SPRITE_Y_SIZE(nr) (SPRITE_Y_EXPAND(nr) ? 2 * 21 : 21)
+#define SPRITE_X_EXPAND(nr) (vic2->reg[0x1d] & (1 << nr))
+#define SPRITE_X_SIZE(nr) (SPRITE_X_EXPAND(nr) ? 2 * 24 : 24)
+#define SPRITE_X_POS(nr) (vic2->reg[(nr) * 2] | (vic2->reg[0x10] & (1 << (nr)) ? 0x100 : 0))
+#define SPRITE_Y_POS(nr) (vic2->reg[1 + 2 * (nr)])
+#define SPRITE_MULTICOLOR(nr) (vic2->reg[0x1c] & (1 << nr))
+#define SPRITE_PRIORITY(nr) (vic2->reg[0x1b] & (1 << nr))
+#define SPRITE_MULTICOLOR1 (vic2->reg[0x25] & 0x0f)
+#define SPRITE_MULTICOLOR2 (vic2->reg[0x26] & 0x0f)
+#define SPRITE_COLOR(nr) (vic2->reg[0x27+nr] & 0x0f)
+#define SPRITE_ADDR(nr) (vic2->videoaddr | 0x3f8 | nr)
+#define SPRITE_COLL (vic2->reg[0x1e])
+#define SPRITE_BG_COLL (vic2->reg[0x1f])
+
+#define GFXMODE ((vic2->reg[0x11] & 0x60) | (vic2->reg[0x16] & 0x10)) >> 4
+#define SCREENON (vic2->reg[0x11] & 0x10)
+#define VERTICALPOS (vic2->reg[0x11] & 0x07)
+#define HORIZONTALPOS (vic2->reg[0x16] & 0x07)
+#define ECMON (vic2->reg[0x11] & 0x40)
+#define HIRESON (vic2->reg[0x11] & 0x20)
+#define COLUMNS40 (vic2->reg[0x16] & 0x08) /* else 38 Columns */
+
+#define VIDEOADDR ((vic2->reg[0x18] & 0xf0) << (10 - 4))
+#define CHARGENADDR ((vic2->reg[0x18] & 0x0e) << 10)
+#define BITMAPADDR ((data & 0x08) << 10)
+
+#define RASTERLINE (((vic2->reg[0x11] & 0x80) << 1) | vic2->reg[0x12])
+
+#define FRAMECOLOR (vic2->reg[0x20] & 0x0f)
+#define BACKGROUNDCOLOR (vic2->reg[0x21] & 0x0f)
+#define MULTICOLOR1 (vic2->reg[0x22] & 0x0f)
+#define MULTICOLOR2 (vic2->reg[0x23] & 0x0f)
+#define FOREGROUNDCOLOR (vic2->reg[0x24] & 0x0f)
+
+#define VIC2_LINES ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_LINES : VIC6567_LINES)
+#define VIC2_FIRST_DMA_LINE ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_FIRST_DMA_LINE : VIC6567_FIRST_DMA_LINE)
+#define VIC2_LAST_DMA_LINE ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_LAST_DMA_LINE : VIC6567_LAST_DMA_LINE)
+#define VIC2_FIRST_DISP_LINE ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_FIRST_DISP_LINE : VIC6567_FIRST_DISP_LINE)
+#define VIC2_LAST_DISP_LINE ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_LAST_DISP_LINE : VIC6567_LAST_DISP_LINE)
+#define VIC2_RASTER_2_EMU(a) ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_RASTER_2_EMU(a) : VIC6567_RASTER_2_EMU(a))
+#define VIC2_FIRSTCOLUMN ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_FIRSTCOLUMN : VIC6567_FIRSTCOLUMN)
+#define VIC2_X_2_EMU(a) ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_X_2_EMU(a) : VIC6567_X_2_EMU(a))
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE vic2_state *get_safe_token( device_t *device )
+{
+ assert(device != NULL);
+ assert(device->type() == VIC2);
+
+ return (vic2_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+INLINE const vic2_interface *get_interface( device_t *device )
+{
+ assert(device != NULL);
+ assert((device->type() == VIC2));
+ return (const vic2_interface *) device->static_config();
+}
+
+/*****************************************************************************
+ IMPLEMENTATION
+*****************************************************************************/
+
+static void vic2_set_interrupt( running_machine &machine, int mask, vic2_state *vic2 )
+{
+ if (((vic2->reg[0x19] ^ mask) & vic2->reg[0x1a] & 0xf))
+ {
+ if (!(vic2->reg[0x19] & 0x80))
+ {
+ DBG_LOG(2, "vic2", ("irq start %.2x\n", mask));
+ vic2->reg[0x19] |= 0x80;
+ vic2->out_interrupt_func(1);
+ }
+ }
+ vic2->reg[0x19] |= mask;
+}
+
+static void vic2_clear_interrupt( running_machine &machine, int mask, vic2_state *vic2 )
+{
+ vic2->reg[0x19] &= ~mask;
+ if ((vic2->reg[0x19] & 0x80) && !(vic2->reg[0x19] & vic2->reg[0x1a] & 0xf))
+ {
+ DBG_LOG(2, "vic2", ("irq end %.2x\n", mask));
+ vic2->reg[0x19] &= ~0x80;
+ vic2->out_interrupt_func(0);
+ }
+}
+
+void vic2_lightpen_write( device_t *device, int level )
+{
+ /* calculate current position, write it and raise interrupt */
+}
+
+static TIMER_CALLBACK( vic2_timer_timeout )
+{
+ vic2_state *vic2 = (vic2_state *)ptr;
+ int which = param;
+
+ DBG_LOG(3, "vic2 ", ("timer %d timeout\n", which));
+
+ switch (which)
+ {
+ case 1: /* light pen */
+ /* and diode must recognize light */
+ if (1)
+ {
+ vic2->reg[0x13] = VIC2_X_VALUE;
+ vic2->reg[0x14] = VIC2_Y_VALUE;
+ }
+ vic2_set_interrupt(machine, 8, vic2);
+ break;
+ }
+}
+
+
+// modified VIC II emulation by Christian Bauer starts here...
+
+// Idle access
+INLINE void vic2_idle_access( running_machine &machine, vic2_state *vic2 )
+{
+ vic2->in_dma_read_func(0x3fff);
+}
+
+// Fetch sprite data pointer
+INLINE void vic2_spr_ptr_access( running_machine &machine, vic2_state *vic2, int num )
+{
+ vic2->spr_ptr[num] = vic2->in_dma_read_func(SPRITE_ADDR(num)) << 6;
+}
+
+// Fetch sprite data, increment data counter
+INLINE void vic2_spr_data_access( running_machine &machine, vic2_state *vic2, int num, int bytenum )
+{
+ if (vic2->spr_dma_on & (1 << num))
+ {
+ vic2->spr_data[num][bytenum] = vic2->in_dma_read_func((vic2->mc[num] & 0x3f) | vic2->spr_ptr[num]);
+ vic2->mc[num]++;
+ }
+ else
+ if (bytenum == 1)
+ vic2_idle_access(machine, vic2);
+}
+
+// Turn on display if Bad Line
+INLINE void vic2_display_if_bad_line( vic2_state *vic2 )
+{
+ if (vic2->is_bad_line)
+ vic2->display_state = 1;
+}
+
+// Suspend CPU
+INLINE void vic2_suspend_cpu( running_machine &machine, vic2_state *vic2 )
+{
+ if (vic2->device_suspended == 0)
+ {
+ vic2->first_ba_cycle = vic2->cycles_counter;
+ if (vic2->in_rdy_workaround_func(0) != 7 )
+ {
+// device_suspend(machine.firstcpu, SUSPEND_REASON_SPIN, 0);
+ }
+ vic2->device_suspended = 1;
+ }
+}
+
+// Resume CPU
+INLINE void vic2_resume_cpu( running_machine &machine, vic2_state *vic2 )
+{
+ if (vic2->device_suspended == 1)
+ {
+ // device_resume(machine.firstcpu, SUSPEND_REASON_SPIN);
+ vic2->device_suspended = 0;
+ }
+}
+
+// Refresh access
+INLINE void vic2_refresh_access( running_machine &machine, vic2_state *vic2 )
+{
+ vic2->in_dma_read_func(0x3f00 | vic2->ref_cnt--);
+}
+
+
+INLINE void vic2_fetch_if_bad_line( vic2_state *vic2 )
+{
+ if (vic2->is_bad_line)
+ vic2->display_state = 1;
+}
+
+
+// Turn on display and matrix access and reset RC if Bad Line
+INLINE void vic2_rc_if_bad_line( vic2_state *vic2 )
+{
+ if (vic2->is_bad_line)
+ {
+ vic2->display_state = 1;
+ vic2->rc = 0;
+ }
+}
+
+// Sample border color and increment vic2->graphic_x
+INLINE void vic2_sample_border( vic2_state *vic2 )
+{
+ if (vic2->draw_this_line)
+ {
+ if (vic2->border_on)
+ vic2->border_color_sample[vic2->cycle - 13] = FRAMECOLOR;
+ vic2->graphic_x += 8;
+ }
+}
+
+
+// Turn on sprite DMA if necessary
+INLINE void vic2_check_sprite_dma( vic2_state *vic2 )
+{
+ int i;
+ UINT8 mask = 1;
+
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if (SPRITEON(i) && ((vic2->rasterline & 0xff) == SPRITE_Y_POS(i)))
+ {
+ vic2->spr_dma_on |= mask;
+ vic2->mc_base[i] = 0;
+ if (SPRITE_Y_EXPAND(i))
+ vic2->spr_exp_y &= ~mask;
+ }
+}
+
+// Video matrix access
+INLINE void vic2_matrix_access( running_machine &machine, vic2_state *vic2 )
+{
+// if (vic2->device_suspended == 1)
+ {
+ if (vic2->cycles_counter < vic2->first_ba_cycle)
+ vic2->matrix_line[vic2->ml_index] = vic2->color_line[vic2->ml_index] = 0xff;
+ else
+ {
+ UINT16 adr = (vic2->vc & 0x03ff) | VIDEOADDR;
+ vic2->matrix_line[vic2->ml_index] = vic2->in_dma_read_func(adr); \
+ vic2->color_line[vic2->ml_index] = vic2->in_dma_read_color_func((adr & 0x03ff)); \
+ }
+ }
+}
+
+// Graphics data access
+INLINE void vic2_graphics_access( running_machine &machine, vic2_state *vic2 )
+{
+ if (vic2->display_state == 1)
+ {
+ UINT16 adr;
+ if (HIRESON)
+ adr = ((vic2->vc & 0x03ff) << 3) | vic2->bitmapaddr | vic2->rc;
+ else
+ adr = (vic2->matrix_line[vic2->ml_index] << 3) | vic2->chargenaddr | vic2->rc;
+ if (ECMON)
+ adr &= 0xf9ff;
+ vic2->gfx_data = vic2->in_dma_read_func(adr);
+ vic2->char_data = vic2->matrix_line[vic2->ml_index];
+ vic2->color_data = vic2->color_line[vic2->ml_index];
+ vic2->ml_index++;
+ vic2->vc++;
+ }
+ else
+ {
+ vic2->gfx_data = vic2->in_dma_read_func((ECMON ? 0x39ff : 0x3fff));
+ vic2->char_data = 0;
+ }
+}
+
+INLINE void vic2_draw_background( vic2_state *vic2 )
+{
+ if (vic2->draw_this_line)
+ {
+ UINT8 c;
+
+ switch (GFXMODE)
+ {
+ case 0:
+ case 1:
+ case 3:
+ c = vic2->colors[0];
+ break;
+ case 2:
+ c = vic2->last_char_data & 0x0f;
+ break;
+ case 4:
+ if (vic2->last_char_data & 0x80)
+ if (vic2->last_char_data & 0x40)
+ c = vic2->colors[3];
+ else
+ c = vic2->colors[2];
+ else
+ if (vic2->last_char_data & 0x40)
+ c = vic2->colors[1];
+ else
+ c = vic2->colors[0];
+ break;
+ default:
+ c = 0;
+ break;
+ }
+ vic2->bitmap->plot_box(vic2->graphic_x, VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, c);
+ }
+}
+
+INLINE void vic2_draw_mono( vic2_state *vic2, UINT16 p, UINT8 c0, UINT8 c1 )
+{
+ UINT8 c[2];
+ UINT8 data = vic2->gfx_data;
+
+ c[0] = c0;
+ c[1] = c1;
+
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = c[data & 1];
+ vic2->fore_coll_buf[p + 7] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = c[data & 1];
+ vic2->fore_coll_buf[p + 6] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = c[data & 1];
+ vic2->fore_coll_buf[p + 5] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = c[data & 1];
+ vic2->fore_coll_buf[p + 4] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = c[data & 1];
+ vic2->fore_coll_buf[p + 3] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = c[data & 1];
+ vic2->fore_coll_buf[p + 2] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = c[data & 1];
+ vic2->fore_coll_buf[p + 1] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = c[data];
+ vic2->fore_coll_buf[p + 0] = data & 1;
+}
+
+INLINE void vic2_draw_multi( vic2_state *vic2, UINT16 p, UINT8 c0, UINT8 c1, UINT8 c2, UINT8 c3 )
+{
+ UINT8 c[4];
+ UINT8 data = vic2->gfx_data;
+
+ c[0] = c0;
+ c[1] = c1;
+ c[2] = c2;
+ c[3] = c3;
+
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = c[data & 3];
+ vic2->fore_coll_buf[p + 7] = data & 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = c[data & 3];
+ vic2->fore_coll_buf[p + 6] = data & 2; data >>= 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = c[data & 3];
+ vic2->fore_coll_buf[p + 5] = data & 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = c[data & 3];
+ vic2->fore_coll_buf[p + 4] = data & 2; data >>= 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = c[data & 3];
+ vic2->fore_coll_buf[p + 3] = data & 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = c[data & 3];
+ vic2->fore_coll_buf[p + 2] = data & 2; data >>= 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = c[data];
+ vic2->fore_coll_buf[p + 1] = data & 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = c[data];
+ vic2->fore_coll_buf[p + 0] = data & 2;
+}
+
+// Graphics display (8 pixels)
+static void vic2_draw_graphics( vic2_state *vic2 )
+{
+ if (vic2->draw_this_line == 0)
+ {
+ UINT16 p = vic2->graphic_x + HORIZONTALPOS;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ }
+ else if (vic2->ud_border_on)
+ {
+ UINT16 p = vic2->graphic_x + HORIZONTALPOS;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ vic2_draw_background(vic2);
+ }
+ else
+ {
+ UINT8 tmp_col;
+ UINT16 p = vic2->graphic_x + HORIZONTALPOS;
+ switch (GFXMODE)
+ {
+ case 0:
+ vic2_draw_mono(vic2, p, vic2->colors[0], vic2->color_data & 0x0f);
+ break;
+ case 1:
+ if (vic2->color_data & 0x08)
+ vic2_draw_multi(vic2, p, vic2->colors[0], vic2->colors[1], vic2->colors[2], vic2->color_data & 0x07);
+ else
+ vic2_draw_mono(vic2, p, vic2->colors[0], vic2->color_data & 0x0f);
+ break;
+ case 2:
+ vic2_draw_mono(vic2, p, vic2->char_data & 0x0f, vic2->char_data >> 4);
+ break;
+ case 3:
+ vic2_draw_multi(vic2, p, vic2->colors[0], vic2->char_data >> 4, vic2->char_data & 0x0f, vic2->color_data & 0x0f);
+ break;
+ case 4:
+ if (vic2->char_data & 0x80)
+ if (vic2->char_data & 0x40)
+ tmp_col = vic2->colors[3];
+ else
+ tmp_col = vic2->colors[2];
+ else
+ if (vic2->char_data & 0x40)
+ tmp_col = vic2->colors[1];
+ else
+ tmp_col = vic2->colors[0];
+ vic2_draw_mono(vic2, p, tmp_col, vic2->color_data & 0x0f);
+ break;
+ case 5:
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = 0;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ break;
+ case 6:
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = 0;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ break;
+ case 7:
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = 0;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ break;
+ }
+ }
+}
+
+static void vic2_draw_sprites( running_machine &machine, vic2_state *vic2 )
+{
+ int i;
+ UINT8 snum, sbit;
+ UINT8 spr_coll = 0, gfx_coll = 0;
+ UINT32 plane0_l, plane0_r, plane1_l, plane1_r;
+ UINT32 sdata_l = 0, sdata_r = 0;
+
+ for (i = 0; i < 0x400; i++)
+ vic2->spr_coll_buf[i] = 0;
+
+ for (snum = 0, sbit = 1; snum < 8; snum++, sbit <<= 1)
+ {
+ if ((vic2->spr_draw & sbit) && (SPRITE_X_POS(snum) <= (403 - (VIC2_FIRSTCOLUMN + 1))))
+ {
+ UINT16 p = SPRITE_X_POS(snum) + VIC2_X_2_EMU(0) + 8;
+ UINT8 color = SPRITE_COLOR(snum);
+ UINT32 sdata = (vic2->spr_draw_data[snum][0] << 24) | (vic2->spr_draw_data[snum][1] << 16) | (vic2->spr_draw_data[snum][2] << 8);
+
+ if (SPRITE_X_EXPAND(snum))
+ {
+ if (SPRITE_X_POS(snum) > (403 - 24 - (VIC2_FIRSTCOLUMN + 1)))
+ continue;
+
+ if (SPRITE_MULTICOLOR(snum))
+ {
+ sdata_l = (vic2->expandx_multi[(sdata >> 24) & 0xff] << 16) | vic2->expandx_multi[(sdata >> 16) & 0xff];
+ sdata_r = vic2->expandx_multi[(sdata >> 8) & 0xff] << 16;
+ plane0_l = (sdata_l & 0x55555555) | (sdata_l & 0x55555555) << 1;
+ plane1_l = (sdata_l & 0xaaaaaaaa) | (sdata_l & 0xaaaaaaaa) >> 1;
+ plane0_r = (sdata_r & 0x55555555) | (sdata_r & 0x55555555) << 1;
+ plane1_r = (sdata_r & 0xaaaaaaaa) | (sdata_r & 0xaaaaaaaa) >> 1;
+ for (i = 0; i < 32; i++, plane0_l <<= 1, plane1_l <<= 1)
+ {
+ UINT8 col;
+
+ if (plane1_l & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ if (plane0_l & 0x80000000)
+ col = vic2->spritemulti[3];
+ else
+ col = color;
+ }
+ else
+ {
+ if (plane0_l & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ col = vic2->spritemulti[1];
+ }
+ else
+ continue;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+
+ for (; i < 48; i++, plane0_r <<= 1, plane1_r <<= 1)
+ {
+ UINT8 col;
+
+ if(plane1_r & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (plane0_r & 0x80000000)
+ col = vic2->spritemulti[3];
+ else
+ col = color;
+ }
+ else
+ {
+ if (plane0_r & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ col = vic2->spritemulti[1];
+ }
+ else
+ continue;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ else
+ {
+ sdata_l = (vic2->expandx[(sdata >> 24) & 0xff] << 16) | vic2->expandx[(sdata >> 16) & 0xff];
+ sdata_r = vic2->expandx[(sdata >> 8) & 0xff] << 16;
+
+ for (i = 0; i < 32; i++, sdata_l <<= 1)
+ if (sdata_l & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+
+ for (; i < 48; i++, sdata_r <<= 1)
+ if (sdata_r & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (SPRITE_MULTICOLOR(snum))
+ {
+ UINT32 plane0 = (sdata & 0x55555555) | (sdata & 0x55555555) << 1;
+ UINT32 plane1 = (sdata & 0xaaaaaaaa) | (sdata & 0xaaaaaaaa) >> 1;
+
+ for (i = 0; i < 24; i++, plane0 <<= 1, plane1 <<= 1)
+ {
+ UINT8 col;
+
+ if (plane1 & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (plane0 & 0x80000000)
+ col = vic2->spritemulti[3];
+ else
+ col = color;
+ }
+ else
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (plane0 & 0x80000000)
+ col = vic2->spritemulti[1];
+ else
+ continue;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < 24; i++, sdata <<= 1)
+ {
+ if (sdata & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ if (vic2->spr_coll_buf[p + i])
+ {
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ }
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (SPRITE_COLL)
+ SPRITE_COLL |= spr_coll;
+ else
+ {
+ SPRITE_COLL = spr_coll;
+ if (SPRITE_COLL)
+ vic2_set_interrupt(machine, 4, vic2);
+ }
+
+ if (SPRITE_BG_COLL)
+ SPRITE_BG_COLL |= gfx_coll;
+ else
+ {
+ SPRITE_BG_COLL = gfx_coll;
+ if (SPRITE_BG_COLL)
+ vic2_set_interrupt(machine, 2, vic2);
+ }
+}
+
+
+static TIMER_CALLBACK( pal_timer_callback )
+{
+ vic2_state *vic2 = (vic2_state *)ptr;
+ int i;
+ UINT8 mask;
+ //static int adjust[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ UINT8 cpu_cycles = vic2->cpu->total_cycles() & 0xff;
+ UINT8 vic_cycles = (vic2->cycles_counter + 1) & 0xff;
+ vic2->cycles_counter++;
+
+// printf("%02x %02x %02x\n",cpu_cycles,vic_cycles,vic2->rdy_cycles);
+#if 0
+if (machine.input().code_pressed(KEYCODE_X))
+{
+if (machine.input().code_pressed_once(KEYCODE_Q)) adjust[1]++;
+if (machine.input().code_pressed_once(KEYCODE_W)) adjust[2]++;
+if (machine.input().code_pressed_once(KEYCODE_E)) adjust[3]++;
+if (machine.input().code_pressed_once(KEYCODE_R)) adjust[4]++;
+if (machine.input().code_pressed_once(KEYCODE_T)) adjust[5]++;
+if (machine.input().code_pressed_once(KEYCODE_Y)) adjust[6]++;
+if (machine.input().code_pressed_once(KEYCODE_U)) adjust[7]++;
+if (machine.input().code_pressed_once(KEYCODE_I)) adjust[8]++;
+if (machine.input().code_pressed_once(KEYCODE_A)) adjust[1]--;
+if (machine.input().code_pressed_once(KEYCODE_S)) adjust[2]--;
+if (machine.input().code_pressed_once(KEYCODE_D)) adjust[3]--;
+if (machine.input().code_pressed_once(KEYCODE_F)) adjust[4]--;
+if (machine.input().code_pressed_once(KEYCODE_G)) adjust[5]--;
+if (machine.input().code_pressed_once(KEYCODE_H)) adjust[6]--;
+if (machine.input().code_pressed_once(KEYCODE_J)) adjust[7]--;
+if (machine.input().code_pressed_once(KEYCODE_K)) adjust[8]--;
+if (machine.input().code_pressed_once(KEYCODE_C)) adjust[0]++;
+if (machine.input().code_pressed_once(KEYCODE_V)) adjust[0]--;
+if (machine.input().code_pressed_once(KEYCODE_Z)) printf("b:%02x 1:%02x 2:%02x 3:%02x 4:%02x 5:%02x 6:%02x 7:%02x 8:%02x\n",
+ adjust[0],adjust[1],adjust[2],adjust[3],adjust[4],adjust[5],adjust[6],adjust[7],adjust[8]);
+}
+#define adjust(x) adjust[x]
+#else
+#define adjust(x) 0
+#endif
+
+ switch(vic2->cycle)
+ {
+
+ // Sprite 3, raster counter, raster IRQ, bad line
+ case 1:
+ if (vic2->rasterline == (VIC2_LINES - 1))
+ {
+ vic2->vblanking = 1;
+
+// if (LIGHTPEN_BUTTON)
+ {
+ /* lightpen timer start */
+ machine.scheduler().timer_set(attotime(0, 0), FUNC(vic2_timer_timeout), 1, vic2);
+ }
+ }
+ else
+ {
+ vic2->rasterline++;
+
+ if (vic2->rasterline == VIC2_FIRST_DMA_LINE)
+ vic2->bad_lines_enabled = SCREENON;
+
+ vic2->is_bad_line = ((vic2->rasterline >= VIC2_FIRST_DMA_LINE) && (vic2->rasterline <= VIC2_LAST_DMA_LINE) &&
+ ((vic2->rasterline & 0x07) == VERTICALPOS) && vic2->bad_lines_enabled);
+
+ vic2->draw_this_line = ((VIC2_RASTER_2_EMU(vic2->rasterline) >= VIC2_RASTER_2_EMU(VIC2_FIRST_DISP_LINE)) &&
+ (VIC2_RASTER_2_EMU(vic2->rasterline ) <= VIC2_RASTER_2_EMU(VIC2_LAST_DISP_LINE)));
+ }
+
+ vic2->border_on_sample[0] = vic2->border_on;
+ vic2_spr_ptr_access(machine, vic2, 3);
+ vic2_spr_data_access(machine, vic2, 3, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x08)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x08) vic2->rdy_cycles += (2 + adjust(1));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 3
+ case 2:
+ if (vic2->vblanking)
+ {
+ // Vertical blank, reset counters
+ vic2->rasterline = vic2->vc_base = 0;
+ vic2->ref_cnt = 0xff;
+ vic2->vblanking = 0;
+
+ // Trigger raster IRQ if IRQ in line 0
+ if (RASTERLINE == 0)
+ {
+ vic2_set_interrupt(machine, 1, vic2);
+ }
+ }
+
+ if (vic2->rasterline == RASTERLINE)
+ {
+ vic2_set_interrupt(machine, 1, vic2);
+ }
+
+ vic2->graphic_x = VIC2_X_2_EMU(0);
+
+ vic2_spr_data_access(machine, vic2, 3, 1);
+ vic2_spr_data_access(machine, vic2, 3, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 4
+ case 3:
+ vic2_spr_ptr_access(machine, vic2, 4);
+ vic2_spr_data_access(machine, vic2, 4, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x10)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x10) vic2->rdy_cycles += (2 + adjust(2));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 4
+ case 4:
+ vic2_spr_data_access(machine, vic2, 4, 1);
+ vic2_spr_data_access(machine, vic2, 4, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 5
+ case 5:
+ vic2_spr_ptr_access(machine, vic2, 5);
+ vic2_spr_data_access(machine, vic2, 5, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x20)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x20) vic2->rdy_cycles += (2 + adjust(3));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 5
+ case 6:
+ vic2_spr_data_access(machine, vic2, 5, 1);
+ vic2_spr_data_access(machine, vic2, 5, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 6
+ case 7:
+ vic2_spr_ptr_access(machine, vic2, 6);
+ vic2_spr_data_access(machine, vic2, 6, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x40)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x40) vic2->rdy_cycles += (2 + adjust(4));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 6
+ case 8:
+ vic2_spr_data_access(machine, vic2, 6, 1);
+ vic2_spr_data_access(machine, vic2, 6, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 7
+ case 9:
+ vic2_spr_ptr_access(machine, vic2, 7);
+ vic2_spr_data_access(machine, vic2, 7, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x80)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x80) vic2->rdy_cycles += (2 + adjust(5));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 7
+ case 10:
+ vic2_spr_data_access(machine, vic2, 7, 1);
+ vic2_spr_data_access(machine, vic2, 7, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh
+ case 11:
+ vic2_refresh_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line
+ case 12:
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, raster_x
+ case 13:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ vic2->raster_x = 0xfffc;
+
+ if ((vic2->in_rdy_workaround_func(0) == 0 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (43+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, RC, VC
+ case 14:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_rc_if_bad_line(vic2);
+
+ vic2->vc = vic2->vc_base;
+
+ if ((vic2->in_rdy_workaround_func(0) == 1 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (42+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, sprite y expansion
+ case 15:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ for (i = 0; i < 8; i++)
+ if (vic2->spr_exp_y & (1 << i))
+ vic2->mc_base[i] += 2;
+
+ vic2->ml_index = 0;
+ vic2_matrix_access(machine, vic2);
+
+ if ((vic2->in_rdy_workaround_func(0) == 2 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (41+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 16:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ if (vic2->spr_exp_y & mask)
+ vic2->mc_base[i]++;
+ if ((vic2->mc_base[i] & 0x3f) == 0x3f)
+ vic2->spr_dma_on &= ~mask;
+ }
+
+ vic2_matrix_access(machine, vic2);
+
+ if ((vic2->in_rdy_workaround_func(0) == 3 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (40+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, check border
+ case 17:
+ if (COLUMNS40)
+ {
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (vic2->rasterline == vic2->dy_start)
+ vic2->border_on = vic2->ud_border_on = 0;
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ } else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ }
+
+ // Second sample of border state
+ vic2->border_on_sample[1] = vic2->border_on;
+
+ vic2_draw_background(vic2);
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+ vic2_matrix_access(machine, vic2);
+
+ if ((vic2->in_rdy_workaround_func(0) == 4 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (40+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Check border
+ case 18:
+ if (!COLUMNS40)
+ {
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (vic2->rasterline == vic2->dy_start)
+ vic2->border_on = vic2->ud_border_on = 0;
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ } else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ }
+
+ // Third sample of border state
+ vic2->border_on_sample[2] = vic2->border_on;
+
+ // Graphics
+
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+ vic2_matrix_access(machine, vic2);
+ vic2->last_char_data = vic2->char_data;
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 55:
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ // sprite y expansion
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if (SPRITE_Y_EXPAND (i))
+ vic2->spr_exp_y ^= mask;
+
+ vic2_check_sprite_dma(vic2);
+
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border, sprite DMA
+ case 56:
+ if (!COLUMNS40)
+ vic2->border_on = 1;
+
+ // Fourth sample of border state
+ vic2->border_on_sample[3] = vic2->border_on;
+
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+ vic2_check_sprite_dma(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border, sprites
+ case 57:
+ if (COLUMNS40)
+ vic2->border_on = 1;
+
+ // Fifth sample of border state
+ vic2->border_on_sample[4] = vic2->border_on;
+
+ // Sample spr_disp_on and spr_data for sprite drawing
+ vic2->spr_draw = vic2->spr_disp_on;
+ if (vic2->spr_draw)
+ memcpy(vic2->spr_draw_data, vic2->spr_data, 8 * 4);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if ((vic2->spr_disp_on & mask) && !(vic2->spr_dma_on & mask))
+ vic2->spr_disp_on &= ~mask;
+
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 0, sprite DMA, MC, RC
+ case 58:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ vic2->mc[i] = vic2->mc_base[i];
+ if ((vic2->spr_dma_on & mask) && ((vic2->rasterline & 0xff) == SPRITE_Y_POS(i)))
+ vic2->spr_disp_on |= mask;
+ }
+
+ vic2_spr_ptr_access(machine, vic2, 0);
+ vic2_spr_data_access(machine, vic2, 0, 0);
+
+ if (vic2->rc == 7)
+ {
+ vic2->vc_base = vic2->vc;
+ vic2->display_state = 0;
+ }
+
+ if (vic2->is_bad_line || vic2->display_state)
+ {
+ vic2->display_state = 1;
+ vic2->rc = (vic2->rc + 1) & 7;
+ }
+
+ if (vic2->spr_dma_on & 0x01)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x01) vic2->rdy_cycles += (2 + adjust(6));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 0
+ case 59:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_spr_data_access(machine, vic2, 0, 1);
+ vic2_spr_data_access(machine, vic2, 0, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 1, draw
+ case 60:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+
+ if (vic2->draw_this_line)
+ {
+ vic2_draw_sprites(machine, vic2);
+
+ if (vic2->border_on_sample[0])
+ for (i = 0; i < 4; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+
+ if (vic2->border_on_sample[1])
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(4 * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[4]);
+
+ if (vic2->border_on_sample[2])
+ for (i = 5; i < 43; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+
+ if (vic2->border_on_sample[3])
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(43 * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[43]);
+
+ if (vic2->border_on_sample[4])
+ {
+ for (i = 44; i < 48; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+ for (i = 48; i < 51; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[47]);
+ }
+ }
+
+ vic2_spr_ptr_access(machine, vic2, 1);
+ vic2_spr_data_access(machine, vic2, 1, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x02)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x02) vic2->rdy_cycles += (2 + adjust(7));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 1
+ case 61:
+ vic2_spr_data_access(machine, vic2, 1, 1);
+ vic2_spr_data_access(machine, vic2, 1, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 2
+ case 62:
+ vic2_spr_ptr_access(machine, vic2, 2);
+ vic2_spr_data_access(machine, vic2, 2, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x04)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x04) vic2->rdy_cycles += (2 + adjust(8));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 2
+ case 63:
+ vic2_spr_data_access(machine, vic2, 2, 1);
+ vic2_spr_data_access(machine, vic2, 2, 2);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ if (SCREENON && (vic2->rasterline == vic2->dy_start))
+ vic2->ud_border_on = 0;
+
+ // Last cycle
+ vic2->cycle = 1;
+ }
+
+ if ((cpu_cycles == vic_cycles) && (vic2->rdy_cycles > 0))
+ {
+ device_spin_until_time (machine.firstcpu, vic2->cpu->cycles_to_attotime(vic2->rdy_cycles));
+ vic2->rdy_cycles = 0;
+ }
+
+ vic2->raster_x += 8;
+ machine.scheduler().timer_set(vic2->cpu->cycles_to_attotime(1), FUNC(pal_timer_callback), 0, vic2);
+}
+
+static TIMER_CALLBACK( ntsc_timer_callback )
+{
+ vic2_state *vic2 = (vic2_state *)ptr;
+ int i;
+ UINT8 mask;
+ vic2->cycles_counter++;
+
+ switch (vic2->cycle)
+ {
+
+ // Sprite 3, raster counter, raster IRQ, bad line
+ case 1:
+ if (vic2->rasterline == (VIC2_LINES - 1))
+ {
+ vic2->vblanking = 1;
+
+// if (LIGHTPEN_BUTTON)
+ {
+ /* lightpen timer starten */
+ machine.scheduler().timer_set(attotime(0, 0), FUNC(vic2_timer_timeout), 1, vic2);
+ }
+ }
+ else
+ {
+ vic2->rasterline++;
+
+ if (vic2->rasterline == VIC2_FIRST_DMA_LINE)
+ vic2->bad_lines_enabled = SCREENON;
+
+ vic2->is_bad_line = ((vic2->rasterline >= VIC2_FIRST_DMA_LINE) && (vic2->rasterline <= VIC2_LAST_DMA_LINE) &&
+ ((vic2->rasterline & 0x07) == VERTICALPOS) && vic2->bad_lines_enabled);
+
+ vic2->draw_this_line = ((VIC2_RASTER_2_EMU(vic2->rasterline) >= VIC2_RASTER_2_EMU(VIC2_FIRST_DISP_LINE)) &&
+ (VIC2_RASTER_2_EMU(vic2->rasterline ) <= VIC2_RASTER_2_EMU(VIC2_LAST_DISP_LINE)));
+ }
+
+ vic2->border_on_sample[0] = vic2->border_on;
+ vic2_spr_ptr_access(machine, vic2, 3);
+ vic2_spr_data_access(machine, vic2, 3, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x08)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 3
+ case 2:
+ if (vic2->vblanking)
+ {
+ // Vertical blank, reset counters
+ vic2->rasterline = vic2->vc_base = 0;
+ vic2->ref_cnt = 0xff;
+ vic2->vblanking = 0;
+
+ // Trigger raster IRQ if IRQ in line 0
+ if (RASTERLINE == 0)
+ {
+ vic2_set_interrupt(machine, 1, vic2);
+ }
+ }
+
+ if (vic2->rasterline == RASTERLINE)
+ {
+ vic2_set_interrupt(machine, 1, vic2);
+ }
+
+ vic2->graphic_x = VIC2_X_2_EMU(0);
+
+ vic2_spr_data_access(machine, vic2, 3, 1);
+ vic2_spr_data_access(machine, vic2, 3, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 4
+ case 3:
+ vic2_spr_ptr_access(machine, vic2, 4);
+ vic2_spr_data_access(machine, vic2, 4, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x10)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 4
+ case 4:
+ vic2_spr_data_access(machine, vic2, 4, 1);
+ vic2_spr_data_access(machine, vic2, 4, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 5
+ case 5:
+ vic2_spr_ptr_access(machine, vic2, 5);
+ vic2_spr_data_access(machine, vic2, 5, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x20)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 5
+ case 6:
+ vic2_spr_data_access(machine, vic2, 5, 1);
+ vic2_spr_data_access(machine, vic2, 5, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 6
+ case 7:
+ vic2_spr_ptr_access(machine, vic2, 6);
+ vic2_spr_data_access(machine, vic2, 6, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x40)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 6
+ case 8:
+ vic2_spr_data_access(machine, vic2, 6, 1);
+ vic2_spr_data_access(machine, vic2, 6, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 7
+ case 9:
+ vic2_spr_ptr_access(machine, vic2, 7);
+ vic2_spr_data_access(machine, vic2, 7, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x80)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 7
+ case 10:
+ vic2_spr_data_access(machine, vic2, 7, 1);
+ vic2_spr_data_access(machine, vic2, 7, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh
+ case 11:
+ vic2_refresh_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line
+ case 12:
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, raster_x
+ case 13:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ vic2->raster_x = 0xfffc;
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, RC, VC
+ case 14:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_rc_if_bad_line(vic2);
+
+ vic2->vc = vic2->vc_base;
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, sprite y expansion
+ case 15:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ for (i = 0; i < 8; i++)
+ if (vic2->spr_exp_y & (1 << i))
+ vic2->mc_base[i] += 2;
+
+ if (vic2->is_bad_line)
+ vic2_suspend_cpu(machine, vic2);
+
+ vic2->ml_index = 0;
+ vic2_matrix_access(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 16:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ if (vic2->spr_exp_y & mask)
+ vic2->mc_base[i]++;
+ if ((vic2->mc_base[i] & 0x3f) == 0x3f)
+ vic2->spr_dma_on &= ~mask;
+ }
+
+ vic2_matrix_access(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, check border
+ case 17:
+ if (COLUMNS40)
+ {
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (vic2->rasterline == vic2->dy_start)
+ vic2->border_on = vic2->ud_border_on = 0;
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ }
+
+ // Second sample of border state
+ vic2->border_on_sample[1] = vic2->border_on;
+
+ vic2_draw_background(vic2);
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+ vic2_matrix_access(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border
+ case 18:
+ if (!COLUMNS40)
+ {
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (vic2->rasterline == vic2->dy_start)
+ vic2->border_on = vic2->ud_border_on = 0;
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ }
+
+ // Third sample of border state
+ vic2->border_on_sample[2] = vic2->border_on;
+
+ // Graphics
+
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+ vic2_matrix_access(machine, vic2);
+ vic2->last_char_data = vic2->char_data;
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 55:
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ // sprite y expansion
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if (SPRITE_Y_EXPAND (i))
+ vic2->spr_exp_y ^= mask;
+
+ vic2_check_sprite_dma(vic2);
+
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border, sprite DMA
+ case 56:
+ if (!COLUMNS40)
+ vic2->border_on = 1;
+
+ // Fourth sample of border state
+ vic2->border_on_sample[3] = vic2->border_on;
+
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+ vic2_check_sprite_dma(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border, sprites
+ case 57:
+ if (COLUMNS40)
+ vic2->border_on = 1;
+
+ // Fifth sample of border state
+ vic2->border_on_sample[4] = vic2->border_on;
+
+ // Sample spr_disp_on and spr_data for sprite drawing
+ vic2->spr_draw = vic2->spr_disp_on;
+ if (vic2->spr_draw)
+ memcpy(vic2->spr_draw_data, vic2->spr_data, 8 * 4);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if ((vic2->spr_disp_on & mask) && !(vic2->spr_dma_on & mask))
+ vic2->spr_disp_on &= ~mask;
+
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // for NTSC 6567R8
+ case 58:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // for NTSC 6567R8
+ case 59:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 0, sprite DMA, MC, RC
+ case 60:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ vic2->mc[i] = vic2->mc_base[i];
+ if ((vic2->spr_dma_on & mask) && ((vic2->rasterline & 0xff) == SPRITE_Y_POS(i)))
+ vic2->spr_disp_on |= mask;
+ }
+
+ vic2_spr_ptr_access(machine, vic2, 0);
+ vic2_spr_data_access(machine, vic2, 0, 0);
+
+ if (vic2->rc == 7)
+ {
+ vic2->vc_base = vic2->vc;
+ vic2->display_state = 0;
+ }
+
+ if (vic2->is_bad_line || vic2->display_state)
+ {
+ vic2->display_state = 1;
+ vic2->rc = (vic2->rc + 1) & 7;
+ }
+
+ if (vic2->spr_dma_on & 0x01)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 0
+ case 61:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_spr_data_access(machine, vic2, 0, 1);
+ vic2_spr_data_access(machine, vic2, 0, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 1, draw
+ case 62:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+
+ if (vic2->draw_this_line)
+ {
+ vic2_draw_sprites(machine, vic2);
+
+ if (vic2->border_on_sample[0])
+ for (i = 0; i < 4; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+
+ if (vic2->border_on_sample[1])
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(4 * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[4]);
+
+ if (vic2->border_on_sample[2])
+ for (i = 5; i < 43; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+
+ if (vic2->border_on_sample[3])
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(43 * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[43]);
+
+ if (vic2->border_on_sample[4])
+ {
+ for (i = 44; i < 48; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+ for (i = 48; i < 53; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[47]);
+ }
+ }
+
+ vic2_spr_ptr_access(machine, vic2, 1);
+ vic2_spr_data_access(machine, vic2, 1, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x02)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 1
+ case 63:
+ vic2_spr_data_access(machine, vic2, 1, 1);
+ vic2_spr_data_access(machine, vic2, 1, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 2
+ case 64:
+ vic2_spr_ptr_access(machine, vic2, 2);
+ vic2_spr_data_access(machine, vic2, 2, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x04)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 2
+ case 65:
+ vic2_spr_data_access(machine, vic2, 2, 1);
+ vic2_spr_data_access(machine, vic2, 2, 2);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ if (SCREENON && (vic2->rasterline == vic2->dy_start))
+ vic2->ud_border_on = 0;
+
+ // Last cycle
+ vic2->cycle = 1;
+ }
+
+ vic2->raster_x += 8;
+ machine.scheduler().timer_set(vic2->cpu->cycles_to_attotime(1), FUNC(ntsc_timer_callback), 0, vic2);
+}
+
+
+/*****************************************************************************
+ I/O HANDLERS
+*****************************************************************************/
+
+void vic2_set_rastering( device_t *device, int onoff )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ vic2->on = onoff;
+}
+
+int vic2e_k0_r( device_t *device )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ return VIC2E_K0_LEVEL;
+}
+
+int vic2e_k1_r( device_t *device )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ return VIC2E_K1_LEVEL;
+}
+
+int vic2e_k2_r( device_t *device )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ return VIC2E_K2_LEVEL;
+}
+
+
+WRITE8_DEVICE_HANDLER( vic2_port_w )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ running_machine &machine = device->machine();
+
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ offset &= 0x3f;
+
+ switch (offset)
+ {
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ case 0x09:
+ case 0x0b:
+ case 0x0d:
+ case 0x0f:
+ vic2->reg[offset] = data; /* sprite y positions */
+ break;
+
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ case 0x08:
+ case 0x0a:
+ case 0x0c:
+ case 0x0e:
+ vic2->reg[offset] = data; /* sprite x positions */
+ break;
+
+ case 0x10:
+ vic2->reg[offset] = data; /* sprite x positions */
+ break;
+
+ case 0x17: /* sprite y size */
+ vic2->spr_exp_y |= ~data;
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x1d: /* sprite x size */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x1b: /* sprite background priority */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x1c: /* sprite multicolor mode select */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ /* sprite colors */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x25: /* sprite multicolor */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->spritemulti[1] = SPRITE_MULTICOLOR1;
+ }
+ break;
+
+ case 0x26: /* sprite multicolor */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->spritemulti[3] = SPRITE_MULTICOLOR2;
+ }
+ break;
+
+ case 0x19:
+ vic2_clear_interrupt(machine, data & 0x0f, vic2);
+ break;
+
+ case 0x1a: /* irq mask */
+ vic2->reg[offset] = data;
+ vic2_set_interrupt(machine, 0, vic2); // beamrider needs this
+ break;
+
+ case 0x11:
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ if (data & 8)
+ {
+ vic2->dy_start = ROW25_YSTART;
+ vic2->dy_stop = ROW25_YSTOP;
+ }
+ else
+ {
+ vic2->dy_start = ROW24_YSTART;
+ vic2->dy_stop = ROW24_YSTOP;
+ }
+ }
+ break;
+
+ case 0x12:
+ if (data != vic2->reg[offset])
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x16:
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x18:
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->videoaddr = VIDEOADDR;
+ vic2->chargenaddr = CHARGENADDR;
+ vic2->bitmapaddr = BITMAPADDR;
+ }
+ break;
+
+ case 0x21: /* background color */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->colors[0] = BACKGROUNDCOLOR;
+ }
+ break;
+
+ case 0x22: /* background color 1 */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->colors[1] = MULTICOLOR1;
+ }
+ break;
+
+ case 0x23: /* background color 2 */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->colors[2] = MULTICOLOR2;
+ }
+ break;
+
+ case 0x24: /* background color 3 */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->colors[3] = FOREGROUNDCOLOR;
+ }
+ break;
+
+ case 0x20: /* framecolor */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x2f:
+ if (vic2->type == VIC8564 || vic2->type == VIC8566)
+ {
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x30:
+ if (vic2->type == VIC8564 || vic2->type == VIC8566)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ vic2->reg[offset] = data;
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ break;
+
+ default:
+ vic2->reg[offset] = data;
+ break;
+ }
+}
+
+READ8_DEVICE_HANDLER( vic2_port_r )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ running_machine &machine = device->machine();
+ int val = 0;
+
+ offset &= 0x3f;
+
+ switch (offset)
+ {
+ case 0x11:
+ val = (vic2->reg[offset] & ~0x80) | ((vic2->rasterline & 0x100) >> 1);
+ break;
+
+ case 0x12:
+ val = vic2->rasterline & 0xff;
+ break;
+
+ case 0x16:
+ val = vic2->reg[offset] | 0xc0;
+ break;
+
+ case 0x18:
+ val = vic2->reg[offset] | 0x01;
+ break;
+
+ case 0x19: /* interrupt flag register */
+ /* vic2_clear_interrupt(0xf); */
+ val = vic2->reg[offset] | 0x70;
+ break;
+
+ case 0x1a:
+ val = vic2->reg[offset] | 0xf0;
+ break;
+
+ case 0x1e: /* sprite to sprite collision detect */
+ val = vic2->reg[offset];
+ vic2->reg[offset] = 0;
+ vic2_clear_interrupt(machine, 4, vic2);
+ break;
+
+ case 0x1f: /* sprite to background collision detect */
+ val = vic2->reg[offset];
+ vic2->reg[offset] = 0;
+ vic2_clear_interrupt(machine, 2, vic2);
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ val = vic2->reg[offset];
+ break;
+
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ case 0x10:
+ case 0x17:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ val = vic2->reg[offset];
+ break;
+
+ case 0x2f:
+ case 0x30:
+ if (vic2->type == VIC8564 || vic2->type == VIC8566)
+ {
+ val = vic2->reg[offset];
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ }
+ else
+ val = 0xff;
+ break;
+
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f: /* not used */
+ // val = vic2->reg[offset]; //
+ val = 0xff;
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ break;
+
+ default:
+ val = vic2->reg[offset];
+ }
+
+ if ((offset != 0x11) && (offset != 0x12))
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ return val;
+}
+
+UINT32 vic2_video_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect )
+{
+ vic2_state *vic2 = get_safe_token(device);
+
+ if (vic2->on)
+ copybitmap(bitmap, *vic2->bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( vic2 )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ const vic2_interface *intf = (vic2_interface *)device->static_config();
+ int width, height;
+ int i;
+
+ // resolve callbacks
+ vic2->in_lightpen_x_func.resolve(intf->in_x_cb, *device);
+ vic2->in_lightpen_y_func.resolve(intf->in_y_cb, *device);
+ vic2->in_lightpen_button_func.resolve(intf->in_button_cb, *device);
+ vic2->in_dma_read_func.resolve(intf->in_dma_read_cb, *device);
+ vic2->in_dma_read_color_func.resolve(intf->in_dma_read_color_cb, *device);
+ vic2->out_interrupt_func.resolve(intf->out_irq_cb, *device);
+ vic2->in_rdy_workaround_func.resolve(intf->in_rdy_cb, *device);
+
+ vic2->cpu = device->machine().device<cpu_device>(intf->cpu);
+
+ vic2->screen = device->machine().device<screen_device>(intf->screen);
+ width = vic2->screen->width();
+ height = vic2->screen->height();
+
+ vic2->bitmap = auto_bitmap_ind16_alloc(device->machine(), width, height);
+
+ vic2->type = intf->type;
+
+ // immediately call the timer to handle the first line
+ if (vic2->type == VIC6569 || vic2->type == VIC8566)
+ device->machine().scheduler().timer_set(downcast<cpu_device *>(vic2->cpu)->cycles_to_attotime(0), FUNC(pal_timer_callback), 0, vic2);
+ else
+ device->machine().scheduler().timer_set(downcast<cpu_device *>(vic2->cpu)->cycles_to_attotime(0), FUNC(ntsc_timer_callback), 0, vic2);
+
+ for (i = 0; i < 256; i++)
+ {
+ vic2->expandx[i] = 0;
+ if (i & 1)
+ vic2->expandx[i] |= 3;
+ if (i & 2)
+ vic2->expandx[i] |= 0xc;
+ if (i & 4)
+ vic2->expandx[i] |= 0x30;
+ if (i & 8)
+ vic2->expandx[i] |= 0xc0;
+ if (i & 0x10)
+ vic2->expandx[i] |= 0x300;
+ if (i & 0x20)
+ vic2->expandx[i] |= 0xc00;
+ if (i & 0x40)
+ vic2->expandx[i] |= 0x3000;
+ if (i & 0x80)
+ vic2->expandx[i] |= 0xc000;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ vic2->expandx_multi[i] = 0;
+ if (i & 1)
+ vic2->expandx_multi[i] |= 5;
+ if (i & 2)
+ vic2->expandx_multi[i] |= 0xa;
+ if (i & 4)
+ vic2->expandx_multi[i] |= 0x50;
+ if (i & 8)
+ vic2->expandx_multi[i] |= 0xa0;
+ if (i & 0x10)
+ vic2->expandx_multi[i] |= 0x500;
+ if (i & 0x20)
+ vic2->expandx_multi[i] |= 0xa00;
+ if (i & 0x40)
+ vic2->expandx_multi[i] |= 0x5000;
+ if (i & 0x80)
+ vic2->expandx_multi[i] |= 0xa000;
+ }
+
+ device->save_item(NAME(vic2->reg));
+
+ device->save_item(NAME(vic2->on));
+
+ //device->save_item(NAME(vic2->bitmap));
+
+ device->save_item(NAME(vic2->chargenaddr));
+ device->save_item(NAME(vic2->videoaddr));
+ device->save_item(NAME(vic2->bitmapaddr));
+
+ device->save_item(NAME(vic2->colors));
+ device->save_item(NAME(vic2->spritemulti));
+
+ device->save_item(NAME(vic2->rasterline));
+ device->save_item(NAME(vic2->cycles_counter));
+ device->save_item(NAME(vic2->cycle));
+ device->save_item(NAME(vic2->raster_x));
+ device->save_item(NAME(vic2->graphic_x));
+
+ device->save_item(NAME(vic2->dy_start));
+ device->save_item(NAME(vic2->dy_stop));
+
+ device->save_item(NAME(vic2->draw_this_line));
+ device->save_item(NAME(vic2->is_bad_line));
+ device->save_item(NAME(vic2->bad_lines_enabled));
+ device->save_item(NAME(vic2->display_state));
+ device->save_item(NAME(vic2->char_data));
+ device->save_item(NAME(vic2->gfx_data));
+ device->save_item(NAME(vic2->color_data));
+ device->save_item(NAME(vic2->last_char_data));
+ device->save_item(NAME(vic2->matrix_line));
+ device->save_item(NAME(vic2->color_line));
+ device->save_item(NAME(vic2->vblanking));
+ device->save_item(NAME(vic2->ml_index));
+ device->save_item(NAME(vic2->rc));
+ device->save_item(NAME(vic2->vc));
+ device->save_item(NAME(vic2->vc_base));
+ device->save_item(NAME(vic2->ref_cnt));
+
+ device->save_item(NAME(vic2->spr_coll_buf));
+ device->save_item(NAME(vic2->fore_coll_buf));
+ device->save_item(NAME(vic2->spr_exp_y));
+ device->save_item(NAME(vic2->spr_dma_on));
+ device->save_item(NAME(vic2->spr_draw));
+ device->save_item(NAME(vic2->spr_disp_on));
+ device->save_item(NAME(vic2->spr_ptr));
+ device->save_item(NAME(vic2->mc_base));
+ device->save_item(NAME(vic2->mc));
+
+ for (i = 0; i < 8; i++)
+ {
+ device->save_item(NAME(vic2->spr_data[i]), i);
+ device->save_item(NAME(vic2->spr_draw_data[i]), i);
+ }
+
+ device->save_item(NAME(vic2->border_on));
+ device->save_item(NAME(vic2->ud_border_on));
+ device->save_item(NAME(vic2->border_on_sample));
+ device->save_item(NAME(vic2->border_color_sample));
+
+ device->save_item(NAME(vic2->first_ba_cycle));
+ device->save_item(NAME(vic2->device_suspended));
+}
+
+static DEVICE_RESET( vic2 )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ int i, j;
+
+ memset(vic2->reg, 0, ARRAY_LENGTH(vic2->reg));
+
+ for (i = 0; i < ARRAY_LENGTH(vic2->mc); i++)
+ vic2->mc[i] = 63;
+
+ // from 0 to 311 (0 first, PAL) or from 0 to 261 (? first, NTSC 6567R56A) or from 0 to 262 (? first, NTSC 6567R8)
+ vic2->rasterline = 0; // VIC2_LINES - 1;
+
+ vic2->cycles_counter = -1;
+ vic2->cycle = 63;
+
+ vic2->on = 1;
+
+ vic2->dy_start = ROW24_YSTART;
+ vic2->dy_stop = ROW24_YSTOP;
+
+ vic2->draw_this_line = 0;
+ vic2->is_bad_line = 0;
+ vic2->bad_lines_enabled = 0;
+ vic2->display_state = 0;
+ vic2->char_data = 0;
+ vic2->gfx_data = 0;
+ vic2->color_data = 0;
+ vic2->last_char_data = 0;
+ vic2->vblanking = 0;
+ vic2->ml_index = 0;
+ vic2->rc = 0;
+ vic2->vc = 0;
+ vic2->vc_base = 0;
+ vic2->ref_cnt = 0;
+
+ vic2->spr_exp_y = 0;
+ vic2->spr_dma_on = 0;
+ vic2->spr_draw = 0;
+ vic2->spr_disp_on = 0;
+
+
+ vic2->border_on = 0;
+ vic2->ud_border_on = 0;
+
+ vic2->first_ba_cycle = 0;
+ vic2->device_suspended = 0;
+
+ memset(vic2->matrix_line, 0, ARRAY_LENGTH(vic2->matrix_line));
+ memset(vic2->color_line, 0, ARRAY_LENGTH(vic2->color_line));
+
+ memset(vic2->spr_coll_buf, 0, ARRAY_LENGTH(vic2->spr_coll_buf));
+ memset(vic2->fore_coll_buf, 0, ARRAY_LENGTH(vic2->fore_coll_buf));
+ memset(vic2->border_on_sample, 0, ARRAY_LENGTH(vic2->border_on_sample));
+ memset(vic2->border_color_sample, 0, ARRAY_LENGTH(vic2->border_color_sample));
+
+ for (i = 0; i < 8; i++)
+ {
+ vic2->spr_ptr[i] = 0;
+ vic2->mc_base[i] = 0;
+ vic2->mc[i] = 0;
+ for (j = 0; j < 4; j++)
+ {
+ vic2->spr_draw_data[i][j] = 0;
+ vic2->spr_data[i][j] = 0;
+ }
+ }
+
+}
+
+
+/*-------------------------------------------------
+ device definition
+-------------------------------------------------*/
+
+static const char DEVTEMPLATE_SOURCE[] = __FILE__;
+
+#define DEVTEMPLATE_ID(p,s) p##vic2##s
+#define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET
+#define DEVTEMPLATE_NAME "6567 / 6569 VIC II"
+#define DEVTEMPLATE_FAMILY "6567 / 6569 VIC II"
+#include "devtempl.h"
+
+DEFINE_LEGACY_DEVICE(VIC2, vic2);
diff --git a/src/mess/video/vic6567.h b/src/mess/video/vic6567.h
new file mode 100644
index 00000000000..f54a676e299
--- /dev/null
+++ b/src/mess/video/vic6567.h
@@ -0,0 +1,164 @@
+/*****************************************************************************
+ *
+ * video/vic6567.h
+ *
+ ****************************************************************************/
+
+#ifndef __VIC6567_H__
+#define __VIC6567_H__
+
+#include "devcb.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef enum
+{
+ VIC6567, // VIC II NTSC
+ VIC6569, // VIC II PAL
+ VIC8564, // VIC IIe NTSC
+ VIC8566 // VIC IIe PAL
+} vic2_type;
+
+typedef struct _vic2_interface vic2_interface;
+struct _vic2_interface
+{
+ const char *screen;
+ const char *cpu;
+
+ vic2_type type;
+
+ devcb_read8 in_x_cb;
+ devcb_read8 in_y_cb;
+ devcb_read8 in_button_cb;
+
+ devcb_read8 in_dma_read_cb;
+ devcb_read8 in_dma_read_color_cb;
+ devcb_write_line out_irq_cb;
+
+ devcb_read8 in_rdy_cb;
+};
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define VIC6566_CLOCK (XTAL_8MHz / 8) // 1000000
+#define VIC6567R56A_CLOCK (XTAL_8MHz / 8) // 1000000
+#define VIC6567_CLOCK (XTAL_14_31818MHz / 14) // 1022727
+#define VIC6569_CLOCK (XTAL_17_734472MHz / 18) // 985248
+
+#define VIC6566_DOTCLOCK (VIC6566_CLOCK * 8) // 8000000
+#define VIC6567R56A_DOTCLOCK (VIC6567R56A_CLOCK * 8) // 8000000
+#define VIC6567_DOTCLOCK (VIC6567_CLOCK * 8) // 8181818
+#define VIC6569_DOTCLOCK (VIC6569_CLOCK * 8) // 7881988
+
+#define VIC6567_CYCLESPERLINE 65
+#define VIC6569_CYCLESPERLINE 63
+
+#define VIC6567_LINES 263
+#define VIC6569_LINES 312
+
+#define VIC6566_VRETRACERATE ((float)VIC6566_CLOCK / 262 / 64)
+#define VIC6567R56A_VRETRACERATE ((float)VIC6567R56A_CLOCK / 262 / 64)
+#define VIC6567_VRETRACERATE ((float)VIC6567_CLOCK / 263 / 65)
+#define VIC6569_VRETRACERATE ((float)VIC6569_CLOCK / 312 / 63)
+
+#define VIC6566_HRETRACERATE (VIC6566_CLOCK / VIC6566_CYCLESPERLINE)
+#define VIC6567_HRETRACERATE (VIC6567_CLOCK / VIC6567_CYCLESPERLINE)
+#define VIC6569_HRETRACERATE (VIC6569_CLOCK / VIC6569_CYCLESPERLINE)
+
+#define VIC2_HSIZE 320
+#define VIC2_VSIZE 200
+
+#define VIC6567_VISIBLELINES 235
+#define VIC6569_VISIBLELINES 284
+
+#define VIC6567_FIRST_DMA_LINE 0x30
+#define VIC6569_FIRST_DMA_LINE 0x30
+
+#define VIC6567_LAST_DMA_LINE 0xf7
+#define VIC6569_LAST_DMA_LINE 0xf7
+
+#define VIC6567_FIRST_DISP_LINE 0x29
+#define VIC6569_FIRST_DISP_LINE 0x10
+
+#define VIC6567_LAST_DISP_LINE (VIC6567_FIRST_DISP_LINE + VIC6567_VISIBLELINES - 1)
+#define VIC6569_LAST_DISP_LINE (VIC6569_FIRST_DISP_LINE + VIC6569_VISIBLELINES - 1)
+
+#define VIC6567_RASTER_2_EMU(a) ((a >= VIC6567_FIRST_DISP_LINE) ? (a - VIC6567_FIRST_DISP_LINE) : (a + 222))
+#define VIC6569_RASTER_2_EMU(a) (a - VIC6569_FIRST_DISP_LINE)
+
+#define VIC6567_FIRSTCOLUMN 50
+#define VIC6569_FIRSTCOLUMN 50
+
+#define VIC6567_VISIBLECOLUMNS 418
+#define VIC6569_VISIBLECOLUMNS 403
+
+#define VIC6567_X_2_EMU(a) (a)
+#define VIC6569_X_2_EMU(a) (a)
+
+#define VIC6567_STARTVISIBLELINES ((VIC6567_LINES - VIC6567_VISIBLELINES)/2)
+#define VIC6569_STARTVISIBLELINES 16 /* ((VIC6569_LINES - VIC6569_VISIBLELINES)/2) */
+
+#define VIC6567_FIRSTRASTERLINE 34
+#define VIC6569_FIRSTRASTERLINE 0
+
+#define VIC6567_COLUMNS 512
+#define VIC6569_COLUMNS 504
+
+
+#define VIC6567_STARTVISIBLECOLUMNS ((VIC6567_COLUMNS - VIC6567_VISIBLECOLUMNS)/2)
+#define VIC6569_STARTVISIBLECOLUMNS ((VIC6569_COLUMNS - VIC6569_VISIBLECOLUMNS)/2)
+
+#define VIC6567_FIRSTRASTERCOLUMNS 412
+#define VIC6569_FIRSTRASTERCOLUMNS 404
+
+#define VIC6569_FIRST_X 0x194
+#define VIC6567_FIRST_X 0x19c
+
+#define VIC6569_FIRST_VISIBLE_X 0x1e0
+#define VIC6567_FIRST_VISIBLE_X 0x1e8
+
+#define VIC6569_MAX_X 0x1f7
+#define VIC6567_MAX_X 0x1ff
+
+#define VIC6569_LAST_VISIBLE_X 0x17c
+#define VIC6567_LAST_VISIBLE_X 0x184
+
+#define VIC6569_LAST_X 0x193
+#define VIC6567_LAST_X 0x19b
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(VIC2, vic2);
+
+#define MCFG_VIC2_ADD(_tag, _interface) \
+ MCFG_DEVICE_ADD(_tag, VIC2, 0) \
+ MCFG_DEVICE_CONFIG(_interface)
+
+
+/*----------- defined in video/vic6567.c -----------*/
+
+WRITE8_DEVICE_HANDLER ( vic2_port_w );
+READ8_DEVICE_HANDLER ( vic2_port_r );
+
+int vic2e_k0_r(device_t *device);
+int vic2e_k1_r(device_t *device);
+int vic2e_k2_r(device_t *device);
+
+void vic2_raster_interrupt_gen( device_t *device );
+UINT32 vic2_video_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect );
+
+
+extern void vic2_set_rastering(device_t *device, int onoff);
+extern void vic2_lightpen_write(device_t *device, int level);
+
+
+
+#endif /* __VIC6567_H__ */
diff --git a/src/mess/video/vtech2.c b/src/mess/video/vtech2.c
new file mode 100644
index 00000000000..f24e0d786e3
--- /dev/null
+++ b/src/mess/video/vtech2.c
@@ -0,0 +1,313 @@
+/***************************************************************************
+ vtech2.c
+
+ video hardware
+ Juergen Buchmueller <pullmoll@t-online.de> MESS driver, Jan 2000
+ Davide Moretti <dave@rimini.com> ROM dump and hardware description
+
+****************************************************************************/
+
+#include "emu.h"
+
+#include "includes/vtech2.h"
+
+#define BORDER_H 64
+#define BORDER_V 32
+
+/* public */
+
+/*
+ * when in text mode (bit 3 of I/O area = 0)
+ * bit 3 2 1 0 mode
+ * 0 x x 0 40 columns x 24 rows display RAM at bank 7 1F800-1FFFF
+ * 1 x x 0 40 columns x 24 rows display RAM at bank 3 0F800-0FFFF
+ * 0 x x 1 80 columns x 24 rows display RAM at bank 7 1F800-1FFFF
+ * 1 x x 1 80 columns x 24 rows display RAM at bank 3 0F800-0FFFF
+ *
+ * when in graphics mode (bit 3 of I/O area = 1)
+ * bit 3 2 1 0 mode
+ * 0 0 0 x GR5 bank 7 1C000-1FFFF
+ * 1 0 0 x GR5 bank 3 0C000-0FFFF
+ * 0 0 1 0 GR4 bank 7 1C000-1FFFF
+ * 1 0 1 0 GR4 bank 3 0C000-0FFFF
+ * 0 0 1 1 GR3 bank 7 1C000-1FFFF
+ * 1 0 1 1 GR3 bank 3 1C000-1FFFF
+ * 0 1 0 x GR0 bank 7 1E000-1FFFF
+ * 1 1 0 x GR0 bank 3 0E000-0FFFF
+ * 0 1 1 0 GR2 bank 7 1E000-1FFFF
+ * 1 1 1 0 GR2 bank 3 0E000-0FFFF
+ * 0 1 1 1 GR1 bank 7 1E000-1FFFF
+ * 1 1 1 1 GR1 bank 3 0E000-0FFFF
+ */
+
+VIDEO_START( laser )
+{
+}
+
+static const int offs_2[192] = {
+ 0x0000,0x0800,0x1000,0x1800,0x2000,0x2800,0x3000,0x3800,
+ 0x0100,0x0900,0x1100,0x1900,0x2100,0x2900,0x3100,0x3900,
+ 0x0200,0x0a00,0x1200,0x1a00,0x2200,0x2a00,0x3200,0x3a00,
+ 0x0300,0x0b00,0x1300,0x1b00,0x2300,0x2b00,0x3300,0x3b00,
+ 0x0400,0x0c00,0x1400,0x1c00,0x2400,0x2c00,0x3400,0x3c00,
+ 0x0500,0x0d00,0x1500,0x1d00,0x2500,0x2d00,0x3500,0x3d00,
+ 0x0600,0x0e00,0x1600,0x1e00,0x2600,0x2e00,0x3600,0x3e00,
+ 0x0700,0x0f00,0x1700,0x1f00,0x2700,0x2f00,0x3700,0x3f00,
+ 0x0050,0x0850,0x1050,0x1850,0x2050,0x2850,0x3050,0x3850,
+ 0x0150,0x0950,0x1150,0x1950,0x2150,0x2950,0x3150,0x3950,
+ 0x0250,0x0a50,0x1250,0x1a50,0x2250,0x2a50,0x3250,0x3a50,
+ 0x0350,0x0b50,0x1350,0x1b50,0x2350,0x2b50,0x3350,0x3b50,
+ 0x0450,0x0c50,0x1450,0x1c50,0x2450,0x2c50,0x3450,0x3c50,
+ 0x0550,0x0d50,0x1550,0x1d50,0x2550,0x2d50,0x3550,0x3d50,
+ 0x0650,0x0e50,0x1650,0x1e50,0x2650,0x2e50,0x3650,0x3e50,
+ 0x0750,0x0f50,0x1750,0x1f50,0x2750,0x2f50,0x3750,0x3f50,
+ 0x00a0,0x08a0,0x10a0,0x18a0,0x20a0,0x28a0,0x30a0,0x38a0,
+ 0x01a0,0x09a0,0x11a0,0x19a0,0x21a0,0x29a0,0x31a0,0x39a0,
+ 0x02a0,0x0aa0,0x12a0,0x1aa0,0x22a0,0x2aa0,0x32a0,0x3aa0,
+ 0x03a0,0x0ba0,0x13a0,0x1ba0,0x23a0,0x2ba0,0x33a0,0x3ba0,
+ 0x04a0,0x0ca0,0x14a0,0x1ca0,0x24a0,0x2ca0,0x34a0,0x3ca0,
+ 0x05a0,0x0da0,0x15a0,0x1da0,0x25a0,0x2da0,0x35a0,0x3da0,
+ 0x06a0,0x0ea0,0x16a0,0x1ea0,0x26a0,0x2ea0,0x36a0,0x3ea0,
+ 0x07a0,0x0fa0,0x17a0,0x1fa0,0x27a0,0x2fa0,0x37a0,0x3fa0
+};
+
+static const int offs_1[192] = {
+ 0x2000,0x2080,0x2800,0x2880,0x3000,0x3080,0x3800,0x3880,
+ 0x2100,0x2180,0x2900,0x2980,0x3100,0x3180,0x3900,0x3980,
+ 0x2200,0x2280,0x2a00,0x2a80,0x3200,0x3280,0x3a00,0x3a80,
+ 0x2300,0x2380,0x2b00,0x2b80,0x3300,0x3380,0x3b00,0x3b80,
+ 0x2400,0x2480,0x2c00,0x2c80,0x3400,0x3480,0x3c00,0x3c80,
+ 0x2500,0x2580,0x2d00,0x2d80,0x3500,0x3580,0x3d00,0x3d80,
+ 0x2600,0x2680,0x2e00,0x2e80,0x3600,0x3680,0x3e00,0x3e80,
+ 0x2700,0x2780,0x2f00,0x2f80,0x3700,0x3780,0x3f00,0x3f80,
+ 0x2028,0x20a8,0x2828,0x28a8,0x3028,0x30a8,0x3828,0x38a8,
+ 0x2128,0x21a8,0x2928,0x29a8,0x3128,0x31a8,0x3928,0x39a8,
+ 0x2228,0x22a8,0x2a28,0x2aa8,0x3228,0x32a8,0x3a28,0x3aa8,
+ 0x2328,0x23a8,0x2b28,0x2ba8,0x3328,0x33a8,0x3b28,0x3ba8,
+ 0x2428,0x24a8,0x2c28,0x2ca8,0x3428,0x34a8,0x3c28,0x3ca8,
+ 0x2528,0x25a8,0x2d28,0x2da8,0x3528,0x35a8,0x3d28,0x3da8,
+ 0x2628,0x26a8,0x2e28,0x2ea8,0x3628,0x36a8,0x3e28,0x3ea8,
+ 0x2728,0x27a8,0x2f28,0x2fa8,0x3728,0x37a8,0x3f28,0x3fa8,
+ 0x2050,0x20d0,0x2850,0x28d0,0x3050,0x30d0,0x3850,0x38d0,
+ 0x2150,0x21d0,0x2950,0x29d0,0x3150,0x31d0,0x3950,0x39d0,
+ 0x2250,0x22d0,0x2a50,0x2ad0,0x3250,0x32d0,0x3a50,0x3ad0,
+ 0x2350,0x23d0,0x2b50,0x2bd0,0x3350,0x33d0,0x3b50,0x3bd0,
+ 0x2450,0x24d0,0x2c50,0x2cd0,0x3450,0x34d0,0x3c50,0x3cd0,
+ 0x2550,0x25d0,0x2d50,0x2dd0,0x3550,0x35d0,0x3d50,0x3dd0,
+ 0x2650,0x26d0,0x2e50,0x2ed0,0x3650,0x36d0,0x3e50,0x3ed0,
+ 0x2750,0x27d0,0x2f50,0x2fd0,0x3750,0x37d0,0x3f50,0x3fd0
+};
+
+static const int offs_0[96] = {
+ 0x2000,0x2800,0x3000,0x3800,0x2100,0x2900,0x3100,0x3900,
+ 0x2200,0x2a00,0x3200,0x3a00,0x2300,0x2b00,0x3300,0x3b00,
+ 0x2400,0x2c00,0x3400,0x3c00,0x2500,0x2d00,0x3500,0x3d00,
+ 0x2600,0x2e00,0x3600,0x3e00,0x2700,0x2f00,0x3700,0x3f00,
+ 0x2050,0x2850,0x3050,0x3850,0x2150,0x2950,0x3150,0x3950,
+ 0x2250,0x2a50,0x3250,0x3a50,0x2350,0x2b50,0x3350,0x3b50,
+ 0x2450,0x2c50,0x3450,0x3c50,0x2550,0x2d50,0x3550,0x3d50,
+ 0x2650,0x2e50,0x3650,0x3e50,0x2750,0x2f50,0x3750,0x3f50,
+ 0x20a0,0x28a0,0x30a0,0x38a0,0x21a0,0x29a0,0x31a0,0x39a0,
+ 0x22a0,0x2aa0,0x32a0,0x3aa0,0x23a0,0x2ba0,0x33a0,0x3ba0,
+ 0x24a0,0x2ca0,0x34a0,0x3ca0,0x25a0,0x2da0,0x35a0,0x3da0,
+ 0x26a0,0x2ea0,0x36a0,0x3ea0,0x27a0,0x2fa0,0x37a0,0x3fa0
+};
+
+SCREEN_UPDATE_IND16( laser )
+{
+ vtech2_state *state = screen.machine().driver_data<vtech2_state>();
+ UINT8 *videoram = state->m_videoram;
+ int offs, x, y;
+ int full_refresh = 1;
+
+ if( full_refresh )
+ bitmap.fill(((state->m_laser_bg_mode >> 4) & 15)<<1, cliprect);
+
+ if (state->m_laser_latch & 0x08)
+ {
+ /* graphics modes */
+ switch (state->m_laser_bg_mode & 7)
+ {
+ case 0:
+ case 1:
+ /*
+ * GR 5
+ * 640x192 1bpp
+ */
+ for( y = 0; y < 192; y++ )
+ {
+ offs = offs_2[y];
+ for( x = 0; x < 80; x++, offs++ )
+ {
+ int sx, sy, code, color = state->m_laser_two_color;
+ sy = BORDER_V/2 + y;
+ sx = BORDER_H/2 + x * 8;
+ code = videoram[offs];
+ drawgfx_opaque(bitmap,cliprect,screen.machine().gfx[2],code,color,0,0,sx,sy);
+ }
+ }
+ break;
+
+ case 2:
+ /*
+ * GR 4
+ * 320x192 1bpp with two colors per 8 pixels
+ */
+ for( y = 0; y < 192; y++ )
+ {
+ offs = offs_2[y];
+ for( x = 0; x < 40; x++, offs += 2 )
+ {
+ int sx, sy, code, color;
+ sy = BORDER_V/2 + y;
+ sx = BORDER_H/2 + x * 16;
+ code = videoram[offs];
+ color = videoram[offs+1];
+ drawgfx_opaque(bitmap,cliprect,screen.machine().gfx[3],code,color,0,0,sx,sy);
+ }
+ }
+ break;
+
+ case 3:
+ /*
+ * GR 3
+ * 160x192 4bpp
+ */
+ for( y = 0; y < 192; y++ )
+ {
+ offs = offs_2[y];
+ for( x = 0; x < 80; x++, offs++ )
+ {
+ int sx, sy, code;
+ sy = BORDER_V/2 + y;
+ sx = BORDER_H/2 + x * 8;
+ code = videoram[offs];
+ drawgfx_opaque(bitmap,cliprect,screen.machine().gfx[5],code,0,0,0,sx,sy);
+ }
+ }
+ break;
+
+ case 4:
+ case 5:
+ /*
+ * GR 0
+ * 160x96 4bpp
+ */
+ for( y = 0; y < 96; y++ )
+ {
+ offs = offs_0[y];
+ for( x = 0; x < 80; x++, offs++ )
+ {
+ int sx, sy, code;
+ sy = BORDER_V/2 + y * 2;
+ sx = BORDER_H/2 + x * 8;
+ code = videoram[offs];
+ drawgfx_opaque(bitmap,cliprect,screen.machine().gfx[6],code,0,0,0,sx,sy);
+ }
+ }
+ break;
+
+ case 6:
+ /*
+ * GR 2
+ * 320x192 1bpp
+ */
+ for( y = 0; y < 192; y++ )
+ {
+ offs = offs_1[y];
+ for( x = 0; x < 40; x++, offs++ )
+ {
+ int sx, sy, code, color = state->m_laser_two_color;
+ sy = BORDER_V/2 + y;
+ sx = BORDER_H/2 + x * 16;
+ code = videoram[offs];
+ drawgfx_opaque(bitmap,cliprect,screen.machine().gfx[3],code,color,0,0,sx,sy);
+ }
+ }
+ break;
+
+ case 7:
+ /*
+ * GR 1
+ * 160x192 1bpp with two colors per 8 pixels
+ */
+ for( y = 0; y < 192; y++ )
+ {
+ offs = offs_1[y];
+ for( x = 0; x < 20; x++, offs += 2 )
+ {
+ int sx, sy, code, color;
+ sy = BORDER_V/2 + y;
+ sx = BORDER_H/2 + x * 32;
+ code = videoram[offs];
+ color = videoram[offs+1];
+ drawgfx_opaque(bitmap,cliprect,screen.machine().gfx[4],code,color,0,0,sx,sy);
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ /* text modes */
+ if (state->m_laser_bg_mode & 1)
+ {
+ /* 80 columns text mode */
+ for( y = 0; y < 24; y++ )
+ {
+ offs = ((y & 7) << 8) + ((y >> 3) * 80);
+ for( x = 0; x < 80; x++, offs++ )
+ {
+ int sx, sy, code, color = state->m_laser_two_color;
+ sy = BORDER_V/2 + y * 8;
+ sx = BORDER_H/2 + x * 8;
+ code = videoram[0x3800+offs];
+ drawgfx_opaque(bitmap,cliprect,screen.machine().gfx[0],code,color,0,0,sx,sy);
+ }
+ }
+ }
+ else
+ {
+ /* 40 columns text mode */
+ for( y = 0; y < 24; y++ )
+ {
+ offs = ((y & 7) << 8) + ((y >> 3) * 80);
+ for( x = 0; x < 40; x++, offs += 2 )
+ {
+ int sx, sy, code, color = 0;
+ sy = BORDER_V/2 + y * 8;
+ sx = BORDER_H/2 + x * 16;
+ code = videoram[0x3800+offs];
+ color = videoram[0x3801+offs];
+ drawgfx_opaque(bitmap,cliprect,screen.machine().gfx[1],code,color,0,0,sx,sy);
+ }
+ }
+ }
+ }
+
+ if( state->m_laser_frame_time > 0 )
+ {
+ popmessage("%s", state->m_laser_frame_message);
+ }
+ return 0;
+}
+
+WRITE8_MEMBER(vtech2_state::laser_bg_mode_w)
+{
+ if (m_laser_bg_mode != data)
+ {
+ m_laser_bg_mode = data;
+ logerror("laser border:$%X mode:$%X\n", data >> 4, data & 15);
+ }
+}
+
+WRITE8_MEMBER(vtech2_state::laser_two_color_w)
+{
+ if (m_laser_two_color != data)
+ {
+ m_laser_two_color = data;
+ logerror("laser foreground:$%X background:$%X\n", data >> 4, data & 15);
+ }
+}
+
+
diff --git a/src/mess/video/vtvideo.c b/src/mess/video/vtvideo.c
new file mode 100644
index 00000000000..2316fbc8637
--- /dev/null
+++ b/src/mess/video/vtvideo.c
@@ -0,0 +1,477 @@
+/**********************************************************************
+
+ DEC VT Terminal video emulation
+ [ DC012 and DC011 emulation ]
+
+ 01/05/2009 Initial implementation [Miodrag Milanovic]
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "vtvideo.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define VERBOSE 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _vt_video_t vt_video_t;
+struct _vt_video_t
+{
+ devcb_resolved_read8 in_ram_func;
+ devcb_resolved_write8 clear_video_interrupt;
+
+ screen_device *screen; /* screen */
+ UINT8 *gfx; /* content of char rom */
+
+ int lba7;
+
+ // dc012 attributes
+ UINT8 scroll_latch;
+ UINT8 blink_flip_flop;
+ UINT8 reverse_field;
+ UINT8 basic_attribute;
+ // dc011 attributes
+ UINT8 columns;
+ UINT8 height;
+ UINT8 skip_lines;
+ UINT8 frequency;
+ UINT8 interlaced;
+};
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE vt_video_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == VT100_VIDEO);
+
+ return (vt_video_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+INLINE const vt_video_interface *get_interface(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == VT100_VIDEO);
+
+ return (const vt_video_interface *) device->static_config();
+}
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static void vt_video_recompute_parameters(device_t *device)
+{
+ vt_video_t *vt = get_safe_token(device);
+ int horiz_pix_total = 0;
+ int vert_pix_total = 0;
+ rectangle visarea;
+
+ horiz_pix_total = vt->columns * 10;
+ vert_pix_total = 25 * 10;
+
+ visarea.set(0, horiz_pix_total - 1, 0, vert_pix_total - 1);
+
+ vt->screen->configure(horiz_pix_total, vert_pix_total, visarea,
+ vt->screen->frame_period().attoseconds);
+}
+READ8_DEVICE_HANDLER( vt_video_lba7_r )
+{
+ vt_video_t *vt = get_safe_token(device);
+ return vt->lba7;
+}
+
+
+WRITE8_DEVICE_HANDLER( vt_video_dc012_w )
+{
+ vt_video_t *vt = get_safe_token(device);
+
+ if ((data & 0x08)==0) {
+ if ((data & 0x04)==0) {
+ // set lower part scroll
+ vt->scroll_latch = (vt->scroll_latch & 0x0c) | (data & 0x03);
+ } else {
+ // set higher part scroll
+ vt->scroll_latch = (vt->scroll_latch & 0x03) | ((data & 0x03) << 2);
+ }
+ } else {
+ switch( data & 0x0f) {
+ case 0x08:
+ // toggle blink flip flop
+ vt->blink_flip_flop = (vt->blink_flip_flop==0) ? 1 : 0;
+ break;
+ case 0x09:
+ // clear vertical frequency interrupt;
+ vt->clear_video_interrupt(0, 0);
+ break;
+ case 0x0A:
+ // set reverse field on
+ vt->reverse_field = 1;
+ break;
+ case 0x0B:
+ // set reverse field off
+ vt->reverse_field = 0;
+ break;
+ case 0x0C:
+ // set basic attribute to underline
+ vt->basic_attribute = 0;
+ vt->blink_flip_flop = 0;
+ break;
+ case 0x0D:
+ // set basic attribute to reverse video
+ vt->basic_attribute = 1;
+ vt->blink_flip_flop = 0;
+ break;
+ case 0x0E:
+ case 0x0F:
+ // reserved for future specification
+ vt->blink_flip_flop = 0;
+ break;
+ }
+ }
+}
+
+
+WRITE8_DEVICE_HANDLER( vt_video_dc011_w )
+{
+ vt_video_t *vt = get_safe_token(device);
+ if (BIT(data,5)==0) {
+ UINT8 col = vt->columns;
+ if (BIT(data,4)==0) {
+ vt->columns = 80;
+ } else {
+ vt->columns = 132;
+ }
+ if (col!=vt->columns) {
+ vt_video_recompute_parameters(device);
+ }
+ vt->interlaced = 1;
+ } else {
+ if (BIT(data,4)==0) {
+ vt->frequency = 60;
+ vt->skip_lines = 2;
+ } else {
+ vt->frequency = 50;
+ vt->skip_lines = 5;
+ }
+ vt->interlaced = 0;
+ }
+}
+
+WRITE8_DEVICE_HANDLER( vt_video_brightness_w )
+{
+ //palette_set_color_rgb(device->machine(), 1, data, data, data);
+}
+
+static void vt_video_display_char(device_t *device,bitmap_ind16 &bitmap, UINT8 code,
+ int x, int y,UINT8 scroll_region,UINT8 display_type)
+{
+ UINT8 line=0;
+ int i,b,bit=0,prevbit,invert=0,j;
+ int double_width = (display_type==2) ? 1 : 0;
+ vt_video_t *vt = get_safe_token(device);
+
+ for (i = 0; i < 10; i++)
+ {
+
+ switch(display_type) {
+ case 0 : // bottom half, double height
+ j = (i >> 1)+5; break;
+ case 1 : // top half, double height
+ j = (i >> 1); break;
+ case 2 : // double width
+ case 3 : // normal
+ j = i; break;
+ default : j = 0; break;
+ }
+ // modify line since that is how it is stored in rom
+ if (j==0) j=15; else j=j-1;
+
+ line = vt->gfx[(code & 0x7f)*16 + j];
+ if (vt->basic_attribute==1) {
+ if ((code & 0x80)==0x80)
+ invert = 1;
+ else
+ invert = 0;
+ }
+
+ for (b = 0; b < 8; b++)
+ {
+ prevbit = bit;
+ bit = (((line << b) & 0x80) ? 1 : 0);
+ if (double_width) {
+ bitmap.pix16(y*10+i, x*20+b*2) = (bit|prevbit)^invert;
+ bitmap.pix16(y*10+i, x*20+b*2+1) = bit^invert;
+ } else {
+ bitmap.pix16(y*10+i, x*10+b) = (bit|prevbit)^invert;
+ }
+ }
+ prevbit = bit;
+ // char interleave is filled with last bit
+ if (double_width) {
+ bitmap.pix16(y*10+i, x*20+16) = (bit|prevbit)^invert;
+ bitmap.pix16(y*10+i, x*20+17) = bit^invert;
+ bitmap.pix16(y*10+i, x*20+18) = bit^invert;
+ bitmap.pix16(y*10+i, x*20+19) = bit^invert;
+ } else {
+ bitmap.pix16(y*10+i, x*10+8) = (bit|prevbit)^invert;
+ bitmap.pix16(y*10+i, x*10+9) = bit^invert;
+ }
+ }
+}
+
+void vt_video_update(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ vt_video_t *vt = get_safe_token(device);
+
+ UINT16 addr = 0;
+ int line = 0;
+ int xpos = 0;
+ int ypos = 0;
+ UINT8 code;
+ int x = 0;
+ UINT8 scroll_region = 1; // binary 1
+ UINT8 display_type = 3; // binary 11
+ UINT16 temp =0;
+
+ if (vt->in_ram_func(0) !=0x7f) return;
+
+ while(line < (vt->height + vt->skip_lines)) {
+ code = vt->in_ram_func(addr + xpos);
+ if (code == 0x7f) {
+ // end of line, fill empty till end of line
+ if (line >= vt->skip_lines) {
+ for(x = xpos; x < ((display_type==2) ? (vt->columns / 2) : vt->columns); x++ )
+ {
+ vt_video_display_char(device,bitmap,code,x,ypos,scroll_region,display_type);
+ }
+ }
+ // move to new data
+ temp = vt->in_ram_func(addr+xpos+1)*256 + vt->in_ram_func(addr+xpos+2);
+ addr = (temp) & 0x1fff;
+ // if A12 is 1 then it is 0x2000 block, if 0 then 0x4000 (AVO)
+ if (addr & 0x1000) addr &= 0xfff; else addr |= 0x2000;
+ scroll_region = (temp >> 15) & 1;
+ display_type = (temp >> 13) & 3;
+ if (line >= vt->skip_lines) {
+ ypos++;
+ }
+ xpos=0;
+ line++;
+ } else {
+ // display regular char
+ if (line >= vt->skip_lines) {
+ vt_video_display_char(device,bitmap,code,xpos,ypos,scroll_region,display_type);
+ }
+ xpos++;
+ if (xpos > vt->columns) {
+ line++;
+ xpos=0;
+ }
+ }
+ }
+
+}
+
+static void rainbow_video_display_char(device_t *device,bitmap_ind16 &bitmap, UINT8 code,
+ int x, int y,UINT8 scroll_region,UINT8 display_type)
+{
+ UINT8 line=0;
+ int i,b,bit=0,j;
+ int double_width = (display_type==2) ? 1 : 0;
+ vt_video_t *vt = get_safe_token(device);
+
+ for (i = 0; i < 10; i++)
+ {
+
+ switch(display_type) {
+ case 0 : // bottom half, double height
+ j = (i >> 1)+5; break;
+ case 1 : // top half, double height
+ j = (i >> 1); break;
+ case 2 : // double width
+ case 3 : // normal
+ j = i; break;
+ default : j = 0; break;
+ }
+ // modify line since that is how it is stored in rom
+ if (j==0) j=15; else j=j-1;
+
+ line = vt->gfx[code*16 + j];
+ if (vt->basic_attribute==1) {
+ if ((code & 0x80)==0x80) {
+ line = line ^ 0xff;
+ }
+ }
+
+ for (b = 0; b < 8; b++)
+ {
+ bit = ((line << b) & 0x80) ? 1 : 0;
+ if (double_width) {
+ bitmap.pix16(y*10+i, x*20+b*2) = bit;
+ bitmap.pix16(y*10+i, x*20+b*2+1) = bit;
+ } else {
+ bitmap.pix16(y*10+i, x*10+b) = bit;
+ }
+ }
+ // char interleave is filled with last bit
+ if (double_width) {
+ bitmap.pix16(y*10+i, x*20+16) = bit;
+ bitmap.pix16(y*10+i, x*20+17) = bit;
+ bitmap.pix16(y*10+i, x*20+18) = bit;
+ bitmap.pix16(y*10+i, x*20+19) = bit;
+ } else {
+ bitmap.pix16(y*10+i, x*10+8) = bit;
+ bitmap.pix16(y*10+i, x*10+9) = bit;
+ }
+ }
+}
+void rainbow_video_update(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ vt_video_t *vt = get_safe_token(device);
+
+ UINT16 addr = 0;
+ UINT16 attr_addr = 0;
+ int line = 0;
+ int xpos = 0;
+ int ypos = 0;
+ UINT8 code;
+ int x = 0;
+ UINT8 scroll_region = 1; // binary 1
+ UINT8 display_type = 3; // binary 11
+ UINT16 temp =0;
+
+ while(line < (vt->height + vt->skip_lines)) {
+ code = vt->in_ram_func(addr + xpos);
+ if (code == 0xff) {
+ // end of line, fill empty till end of line
+ if (line >= vt->skip_lines) {
+ for(x = xpos; x < ((display_type==2) ? (vt->columns / 2) : vt->columns); x++ )
+ {
+ rainbow_video_display_char(device,bitmap,code,x,ypos,scroll_region,display_type);
+ }
+ }
+ // move to new data
+ temp = vt->in_ram_func(addr+xpos+2)*256 + vt->in_ram_func(addr+xpos+1);
+ addr = (temp) & 0x0fff;
+ attr_addr = ((temp) & 0x1fff) - 2;
+ // if A12 is 1 then it is 0x2000 block, if 0 then 0x4000 (AVO)
+ if (temp & 0x1000) attr_addr &= 0xfff; else attr_addr |= 0x1000;
+ temp = vt->in_ram_func(attr_addr);
+ scroll_region = (temp) & 1;
+ display_type = (temp>> 1) & 3;
+ if (line >= vt->skip_lines) {
+ ypos++;
+ }
+ xpos=0;
+ line++;
+ } else {
+ // display regular char
+ if (line >= vt->skip_lines) {
+ rainbow_video_display_char(device,bitmap,code,xpos,ypos,scroll_region,display_type);
+ }
+ xpos++;
+ if (xpos > vt->columns) {
+ line++;
+ xpos=0;
+ }
+ }
+ }
+
+}
+/*-------------------------------------------------
+ DEVICE_START( vt_video )
+-------------------------------------------------*/
+static TIMER_CALLBACK(lba7_change)
+{
+ device_t *device = (device_t *)ptr;
+ vt_video_t *vt = get_safe_token(device);
+
+ vt->lba7 = (vt->lba7) ? 0 : 1;
+}
+
+static DEVICE_START( vt_video )
+{
+ vt_video_t *vt = get_safe_token(device);
+ const vt_video_interface *intf = get_interface(device);
+
+ /* resolve callbacks */
+ vt->in_ram_func.resolve(intf->in_ram_func, *device);
+ vt->clear_video_interrupt.resolve(intf->clear_video_interrupt, *device);
+
+ /* get the screen device */
+ vt->screen = device->machine().device<screen_device>(intf->screen_tag);
+ assert(vt->screen != NULL);
+
+ vt->gfx = device->machine().root_device().memregion(intf->char_rom_region_tag)->base();
+ assert(vt->gfx != NULL);
+
+ // LBA7 is scan line frequency update
+ device->machine().scheduler().timer_pulse(attotime::from_nsec(31778), FUNC(lba7_change), 0, (void *) device);
+}
+
+
+/*-------------------------------------------------
+ DEVICE_RESET( vt_video )
+-------------------------------------------------*/
+
+static DEVICE_RESET( vt_video )
+{
+ vt_video_t *vt = get_safe_token(device);
+ palette_set_color_rgb(device->machine(), 0, 0x00, 0x00, 0x00); // black
+ palette_set_color_rgb(device->machine(), 1, 0xff, 0xff, 0xff); // white
+
+ vt->height = 25;
+ vt->lba7 = 0;
+
+ vt->scroll_latch = 0;
+ vt->blink_flip_flop = 0;
+ vt->reverse_field = 0;
+ vt->basic_attribute = 0;
+
+ vt->columns = 80;
+ vt->frequency = 60;
+ vt->interlaced = 1;
+ vt->skip_lines = 2; // for 60Hz
+}
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( vt100_video )
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( vt100_video )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(vt_video_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(vt_video); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(vt_video); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "VT100 Video"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "VTxxx Video"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(VT100_VIDEO, vt100_video);
diff --git a/src/mess/video/vtvideo.h b/src/mess/video/vtvideo.h
new file mode 100644
index 00000000000..422e816300b
--- /dev/null
+++ b/src/mess/video/vtvideo.h
@@ -0,0 +1,57 @@
+/**********************************************************************
+
+ DEC VT Terminal video emulation
+ [ DC012 and DC011 emulation ]
+
+ 01/05/2009 Initial implementation [Miodrag Milanovic]
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#ifndef __VT_VIDEO__
+#define __VT_VIDEO__
+
+#include "emu.h"
+#include "devcb.h"
+
+/***************************************************************************
+ MACROS / CONSTANTS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(VT100_VIDEO, vt100_video);
+
+#define MCFG_VT100_VIDEO_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, VT100_VIDEO, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _vt_video_interface vt_video_interface;
+struct _vt_video_interface
+{
+ const char *screen_tag; /* screen we are acting on */
+ const char *char_rom_region_tag; /* character rom region */
+
+ /* this gets called for every memory read */
+ devcb_read8 in_ram_func;
+ devcb_write8 clear_video_interrupt;
+};
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+/* register access */
+READ8_DEVICE_HANDLER ( vt_video_lba7_r );
+WRITE8_DEVICE_HANDLER ( vt_video_dc012_w );
+WRITE8_DEVICE_HANDLER ( vt_video_dc011_w );
+WRITE8_DEVICE_HANDLER ( vt_video_brightness_w );
+
+
+/* screen update */
+void vt_video_update(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect);
+void rainbow_video_update(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+#endif
diff --git a/src/mess/video/wswan.c b/src/mess/video/wswan.c
new file mode 100644
index 00000000000..be08c8c7d39
--- /dev/null
+++ b/src/mess/video/wswan.c
@@ -0,0 +1,584 @@
+/***************************************************************************
+
+ wswan.c
+
+ File to handle video emulation of the Bandai WonderSwan.
+
+ Anthony Kruize
+ Wilbert Pol
+
+***************************************************************************/
+
+#include "includes/wswan.h"
+
+static void wswan_setup_palettes(wswan_state *state) {
+ int i,j;
+
+ if ( state->m_vdp.color_mode ) {
+ for( i = 0; i < 16; i++ ) {
+ for( j = 0; j < 16; j++ ) {
+ state->m_pal[i][j] = ( ( state->m_vdp.palette_vram[ ( i << 5 ) + j*2 + 1 ] << 8 ) | state->m_vdp.palette_vram[ ( i << 5 ) + j*2 ] ) & 0x0FFF;
+ }
+ }
+ } else {
+ for( i = 0; i < 16; i++ ) {
+ state->m_pal[i][0] = state->m_ws_portram[ 0x20 + ( i << 1 ) ] & 0x07;
+ state->m_pal[i][1] = ( state->m_ws_portram[ 0x20 + ( i << 1 ) ] >> 4 ) & 0x07;
+ state->m_pal[i][2] = state->m_ws_portram[ 0x21 + ( i << 1 ) ] & 0x07;
+ state->m_pal[i][3] = ( state->m_ws_portram[ 0x21 + ( i << 1 ) ] >> 4 ) & 0x07;
+ }
+ }
+}
+
+static void wswan_draw_background( running_machine &machine ) {
+ wswan_state *state = machine.driver_data<wswan_state>();
+ UINT16 map_addr;
+ UINT8 start_column;
+ int column;
+
+ map_addr = state->m_vdp.layer_bg_address + ( ( ( state->m_vdp.current_line + state->m_vdp.layer_bg_scroll_y ) & 0xF8 ) << 3 );
+ start_column = ( state->m_vdp.layer_bg_scroll_x >> 3 );
+ for( column = 0; column < 29; column++ ) {
+ int tile_data, tile_number, tile_palette, tile_line, tile_address;
+ UINT32 plane0=0, plane1=0, plane2=0, plane3=0;
+ int x, x_offset;
+
+ tile_data = ( state->m_vdp.vram[ map_addr + ( ( ( start_column + column ) & 0x1F ) << 1 ) + 1 ] << 8 )
+ | state->m_vdp.vram[ map_addr + ( ( ( start_column + column ) & 0x1F ) << 1 ) ];
+ tile_number = tile_data & 0x01FF;
+ tile_palette = ( tile_data >> 9 ) & 0x0F;
+
+ tile_line = ( state->m_vdp.current_line + state->m_vdp.layer_bg_scroll_y ) & 0x07;
+ if ( tile_data & 0x8000 ) {
+ tile_line = 7 - tile_line;
+ }
+
+ if ( state->m_vdp.colors_16 ) {
+ tile_address = ( ( tile_data & 0x2000 ) ? 0x8000 : 0x4000 ) + ( tile_number * 32 ) + ( tile_line << 2 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 24 ) | ( state->m_vdp.vram[ tile_address + 1 ] << 16 ) | ( state->m_vdp.vram[ tile_address + 2 ] << 8 ) | state->m_vdp.vram[ tile_address + 3 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = state->m_vdp.vram[ tile_address + 2 ] << 2;
+ plane3 = state->m_vdp.vram[ tile_address + 3 ] << 3;
+ }
+ } else {
+ tile_address = 0x2000 + ( tile_number * 16 ) + ( tile_line << 1 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 8 ) | state->m_vdp.vram[ tile_address + 1 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = 0;
+ plane3 = 0;
+ }
+ }
+
+ for( x = 0; x < 8; x++ ) {
+ int col;
+ if ( state->m_vdp.tile_packed ) {
+ if ( state->m_vdp.colors_16 ) {
+ col = plane0 & 0x0F;
+ plane0 = plane0 >> 4;
+ } else {
+ col = plane0 & 0x03;
+ plane0 = plane0 >> 2;
+ }
+ } else {
+ col = ( plane3 & 8 ) | ( plane2 & 4 ) | ( plane1 & 2 ) | ( plane0 & 1 );
+ plane3 = plane3 >> 1;
+ plane2 = plane2 >> 1;
+ plane1 = plane1 >> 1;
+ plane0 = plane0 >> 1;
+ }
+ if ( tile_data & 0x4000 ) {
+ x_offset = x + ( column << 3 ) - ( state->m_vdp.layer_bg_scroll_x & 0x07 );
+ } else {
+ x_offset = 7 - x + ( column << 3 ) - ( state->m_vdp.layer_bg_scroll_x & 0x07 );
+ }
+ if ( x_offset >= 0 && x_offset < WSWAN_X_PIXELS ) {
+ if ( state->m_vdp.colors_16 ) {
+ if ( col ) {
+ if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ } else {
+ /* Hmmmm, what should we do here... Is this correct?? */
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ }
+ }
+ } else {
+ if ( col || !(tile_palette & 4 ) ) {
+ if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ } else {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_vdp.main_palette[state->m_pal[tile_palette][col]];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void wswan_draw_foreground_0( running_machine &machine ) {
+ wswan_state *state = machine.driver_data<wswan_state>();
+ UINT16 map_addr;
+ UINT8 start_column;
+ int column;
+ map_addr = state->m_vdp.layer_fg_address + ( ( ( state->m_vdp.current_line + state->m_vdp.layer_fg_scroll_y ) & 0xF8 ) << 3 );
+ start_column = ( state->m_vdp.layer_fg_scroll_x >> 3 );
+ for( column = 0; column < 29; column++ ) {
+ UINT32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0;
+ int x, x_offset, tile_line, tile_address;
+ int tile_data = ( state->m_vdp.vram[ map_addr + ( ( ( start_column + column ) & 0x1F ) << 1 ) + 1 ] << 8 )
+ | state->m_vdp.vram[ map_addr + ( ( ( start_column + column ) & 0x1F ) << 1 ) ];
+ int tile_number = tile_data & 0x01FF;
+ int tile_palette = ( tile_data >> 9 ) & 0x0F;
+
+ tile_line = ( state->m_vdp.current_line + state->m_vdp.layer_fg_scroll_y ) & 0x07;
+ if ( tile_data & 0x8000 ) {
+ tile_line = 7 - tile_line;
+ }
+
+ if ( state->m_vdp.colors_16 ) {
+ tile_address = ( ( tile_data & 0x2000 ) ? 0x8000 : 0x4000 ) + ( tile_number * 32 ) + ( tile_line << 2 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 24 ) | ( state->m_vdp.vram[ tile_address + 1 ] << 16 ) | ( state->m_vdp.vram[ tile_address + 2 ] << 8 ) | state->m_vdp.vram[ tile_address + 3 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = state->m_vdp.vram[ tile_address + 2 ] << 2;
+ plane3 = state->m_vdp.vram[ tile_address + 3 ] << 3;
+ }
+ } else {
+ tile_address = 0x2000 + ( tile_number * 16 ) + ( tile_line << 1 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 8 ) | state->m_vdp.vram[ tile_address + 1 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = 0;
+ plane3 = 0;
+ }
+ }
+
+ for( x = 0; x < 8; x++ ) {
+ int col;
+ if ( state->m_vdp.tile_packed ) {
+ if ( state->m_vdp.colors_16 ) {
+ col = plane0 & 0x0F;
+ plane0 = plane0 >> 4;
+ } else {
+ col = plane0 & 0x03;
+ plane0 = plane0 >> 2;
+ }
+ } else {
+ col = ( plane3 & 8 ) | ( plane2 & 4 ) | ( plane1 & 2 ) | ( plane0 & 1 );
+ plane3 = plane3 >> 1;
+ plane2 = plane2 >> 1;
+ plane1 = plane1 >> 1;
+ plane0 = plane0 >> 1;
+ }
+ if ( tile_data & 0x4000 ) {
+ x_offset = x + ( column << 3 ) - ( state->m_vdp.layer_fg_scroll_x & 0x07 );
+ } else {
+ x_offset = 7 - x + ( column << 3 ) - ( state->m_vdp.layer_fg_scroll_x & 0x07 );
+ }
+ if ( x_offset >= 0 && x_offset < WSWAN_X_PIXELS ) {
+ if ( state->m_vdp.colors_16 ) {
+ if ( col ) {
+// if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+// } else {
+// /* Hmmmm, what should we do here... Is this correct?? */
+// state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+// }
+ }
+ } else {
+ if ( col || !(tile_palette & 4 ) ) {
+ if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ } else {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_vdp.main_palette[state->m_pal[tile_palette][col]];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void wswan_draw_foreground_2( running_machine &machine ) {
+ wswan_state *state = machine.driver_data<wswan_state>();
+ UINT16 map_addr;
+ UINT8 start_column;
+ int column;
+ map_addr = state->m_vdp.layer_fg_address + ( ( ( state->m_vdp.current_line + state->m_vdp.layer_fg_scroll_y ) & 0xF8 ) << 3 );
+ start_column = ( state->m_vdp.layer_fg_scroll_x >> 3 );
+ for( column = 0; column < 29; column++ ) {
+ UINT32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0;
+ int x, x_offset, tile_line, tile_address;
+ int tile_data = ( state->m_vdp.vram[ map_addr + ( ( ( start_column + column ) & 0x1F ) << 1 ) + 1 ] << 8 )
+ | state->m_vdp.vram[ map_addr + ( ( ( start_column + column ) & 0x1F ) << 1 ) ];
+ int tile_number = tile_data & 0x01FF;
+ int tile_palette = ( tile_data >> 9 ) & 0x0F;
+
+ tile_line = ( state->m_vdp.current_line + state->m_vdp.layer_fg_scroll_y ) & 0x07;
+ if ( tile_data & 0x8000 ) {
+ tile_line = 7 - tile_line;
+ }
+
+ if ( state->m_vdp.colors_16 ) {
+ tile_address = ( ( tile_data & 0x2000 ) ? 0x8000 : 0x4000 ) + ( tile_number * 32 ) + ( tile_line << 2 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 24 ) | ( state->m_vdp.vram[ tile_address + 1 ] << 16 ) | ( state->m_vdp.vram[ tile_address + 2 ] << 8 ) | state->m_vdp.vram[ tile_address + 3 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = state->m_vdp.vram[ tile_address + 2 ] << 2;
+ plane3 = state->m_vdp.vram[ tile_address + 3 ] << 3;
+ }
+ } else {
+ tile_address = 0x2000 + ( tile_number * 16 ) + ( tile_line << 1 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 8 ) | state->m_vdp.vram[ tile_address + 1 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = 0;
+ plane3 = 0;
+ }
+ }
+
+ for( x = 0; x < 8; x++ ) {
+ int col;
+ if ( state->m_vdp.tile_packed ) {
+ if ( state->m_vdp.colors_16 ) {
+ col = plane0 & 0x0F;
+ plane0 = plane0 >> 4;
+ } else {
+ col = plane0 & 0x03;
+ plane0 = plane0 >> 2;
+ }
+ } else {
+ col = ( plane3 & 8 ) | ( plane2 & 4 ) | ( plane1 & 2 ) | ( plane0 & 1 );
+ plane3 = plane3 >> 1;
+ plane2 = plane2 >> 1;
+ plane1 = plane1 >> 1;
+ plane0 = plane0 >> 1;
+ }
+ if ( tile_data & 0x4000 ) {
+ x_offset = x + ( column << 3 ) - ( state->m_vdp.layer_fg_scroll_x & 0x07 );
+ } else {
+ x_offset = 7 - x + ( column << 3 ) - ( state->m_vdp.layer_fg_scroll_x & 0x07 );
+ }
+ if ( x_offset >= 0 && x_offset >= state->m_vdp.window_fg_left && x_offset < state->m_vdp.window_fg_right && x_offset < WSWAN_X_PIXELS ) {
+ if ( state->m_vdp.colors_16 ) {
+ if ( col ) {
+ if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ } else {
+ /* Hmmmm, what should we do here... Is this correct?? */
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ }
+ }
+ } else {
+ if ( col || !(tile_palette & 4 ) ) {
+ if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ } else {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_vdp.main_palette[state->m_pal[tile_palette][col]];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void wswan_draw_foreground_3( running_machine &machine ) {
+ wswan_state *state = machine.driver_data<wswan_state>();
+ UINT16 map_addr;
+ UINT8 start_column;
+ int column;
+ map_addr = state->m_vdp.layer_fg_address + ( ( ( state->m_vdp.current_line + state->m_vdp.layer_fg_scroll_y ) & 0xF8 ) << 3 );
+ start_column = ( state->m_vdp.layer_fg_scroll_x >> 3 );
+ for( column = 0; column < 29; column++ ) {
+ UINT32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0;
+ int x, x_offset, tile_line, tile_address;
+ int tile_data = ( state->m_vdp.vram[ map_addr + ( ( ( start_column + column ) & 0x1F ) << 1 ) + 1 ] << 8 )
+ | state->m_vdp.vram[ map_addr + ( ( ( start_column + column ) & 0x1F ) << 1 ) ];
+ int tile_number = tile_data & 0x01FF;
+ int tile_palette = ( tile_data >> 9 ) & 0x0F;
+
+ tile_line = ( state->m_vdp.current_line + state->m_vdp.layer_fg_scroll_y ) & 0x07;
+ if ( tile_data & 0x8000 ) { // vflip
+ tile_line = 7 - tile_line;
+ }
+
+ if ( state->m_vdp.colors_16 ) {
+ tile_address = ( ( tile_data & 0x2000 ) ? 0x8000 : 0x4000 ) + ( tile_number * 32 ) + ( tile_line << 2 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 24 ) | ( state->m_vdp.vram[ tile_address + 1 ] << 16 ) | ( state->m_vdp.vram[ tile_address + 2 ] << 8 ) | state->m_vdp.vram[ tile_address + 3 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = state->m_vdp.vram[ tile_address + 2 ] << 2;
+ plane3 = state->m_vdp.vram[ tile_address + 3 ] << 3;
+ }
+ } else {
+ tile_address = 0x2000 + ( tile_number * 16 ) + ( tile_line << 1 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 8 ) | state->m_vdp.vram[ tile_address + 1 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = 0;
+ plane3 = 0;
+ }
+ }
+
+ for( x = 0; x < 8; x++ ) {
+ int col;
+ if ( state->m_vdp.tile_packed ) {
+ if ( state->m_vdp.colors_16 ) {
+ col = plane0 & 0x0F;
+ plane0 = plane0 >> 4;
+ } else {
+ col = plane0 & 0x03;
+ plane0 = plane0 >> 2;
+ }
+ } else {
+ col = ( plane3 & 8 ) | ( plane2 & 4 ) | ( plane1 & 2 ) | ( plane0 & 1 );
+ plane3 = plane3 >> 1;
+ plane2 = plane2 >> 1;
+ plane1 = plane1 >> 1;
+ plane0 = plane0 >> 1;
+ }
+ if ( tile_data & 0x4000 ) {
+ x_offset = x + ( column << 3 ) - ( state->m_vdp.layer_fg_scroll_x & 0x07 );
+ } else {
+ x_offset = 7 - x + ( column << 3 ) - ( state->m_vdp.layer_fg_scroll_x & 0x07 );
+ }
+ if ( ( x_offset >= 0 && x_offset < state->m_vdp.window_fg_left ) || ( x_offset >= state->m_vdp.window_fg_right && x_offset < WSWAN_X_PIXELS ) ) {
+ if ( state->m_vdp.colors_16 ) {
+ if ( col ) {
+ if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ } else {
+ /* Hmmmm, what should we do here... Is this correct?? */
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ }
+ }
+ } else {
+ if ( col || !(tile_palette & 4 ) ) {
+ if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ } else {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_vdp.main_palette[state->m_pal[tile_palette][col]];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void wswan_handle_sprites( running_machine &machine, int mask ) {
+ wswan_state *state = machine.driver_data<wswan_state>();
+ int i;
+ if ( state->m_vdp.sprite_count == 0 )
+ return;
+ for( i = state->m_vdp.sprite_first + state->m_vdp.sprite_count - 1; i >= state->m_vdp.sprite_first; i-- ) {
+ UINT8 x, y;
+ UINT16 tile_data;
+ int tile_line;
+
+ tile_data = ( state->m_vdp.sprite_table_buffer[ i * 4 + 1 ] << 8 ) | state->m_vdp.sprite_table_buffer[ i * 4 ];
+ y = state->m_vdp.sprite_table_buffer[ i * 4 + 2 ];
+ x = state->m_vdp.sprite_table_buffer[ i * 4 + 3 ];
+ tile_line = state->m_vdp.current_line - y;
+ tile_line = tile_line & 0xFF;
+ if ( ( tile_line >= 0 ) && ( tile_line < 8 ) && ( ( tile_data & 0x2000 ) == mask ) ) {
+ UINT32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0;
+ int j, x_offset, tile_address;
+ int tile_number = tile_data & 0x01FF;
+ int tile_palette = 8 + ( ( tile_data >> 9 ) & 0x07 );
+ int check_clip = 0;
+ if ( tile_data & 0x8000 ) {
+ tile_line = 7 - tile_line;
+ }
+
+ if ( state->m_vdp.colors_16 ) {
+ tile_address = 0x4000 + ( tile_number * 32 ) + ( tile_line << 2 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 24 ) | ( state->m_vdp.vram[ tile_address + 1 ] << 16 ) | ( state->m_vdp.vram[ tile_address + 2 ] << 8 ) | state->m_vdp.vram[ tile_address + 3 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = state->m_vdp.vram[ tile_address + 2 ] << 2;
+ plane3 = state->m_vdp.vram[ tile_address + 3 ] << 3;
+ }
+ } else {
+ tile_address = 0x2000 + ( tile_number * 16 ) + ( tile_line << 1 );
+ if ( state->m_vdp.tile_packed ) {
+ plane0 = ( state->m_vdp.vram[ tile_address + 0 ] << 8 ) | state->m_vdp.vram[ tile_address + 1 ];
+ } else {
+ plane0 = state->m_vdp.vram[ tile_address + 0 ];
+ plane1 = state->m_vdp.vram[ tile_address + 1 ] << 1;
+ plane2 = 0;
+ plane3 = 0;
+ }
+ }
+
+ if ( state->m_vdp.window_sprites_enable ) {
+ if ( tile_data & 0x1000 ) {
+ if ( state->m_vdp.current_line >= state->m_vdp.window_sprites_top && state->m_vdp.current_line <= state->m_vdp.window_sprites_bottom ) {
+ check_clip = 1;
+ }
+ } else {
+ if ( state->m_vdp.current_line < state->m_vdp.window_sprites_top || state->m_vdp.current_line > state->m_vdp.window_sprites_bottom ) {
+ continue;
+ }
+ }
+ }
+
+ for ( j = 0; j < 8; j++ ) {
+ int col;
+ if ( state->m_vdp.tile_packed ) {
+ if ( state->m_vdp.colors_16 ) {
+ col = plane0 & 0x0F;
+ plane0 = plane0 >> 4;
+ } else {
+ col = plane0 & 0x03;
+ plane0 = plane0 >> 2;
+ }
+ } else {
+ col = ( plane3 & 8 ) | ( plane2 & 4 ) | ( plane1 & 2 ) | ( plane0 & 1 );
+ plane3 = plane3 >> 1;
+ plane2 = plane2 >> 1;
+ plane1 = plane1 >> 1;
+ plane0 = plane0 >> 1;
+ }
+ if ( tile_data & 0x4000 ) {
+ x_offset = x + j;
+ } else {
+ x_offset = x + 7 - j;
+ }
+ x_offset = x_offset & 0xFF;
+ if ( state->m_vdp.window_sprites_enable ) {
+ if ( tile_data & 0x1000 && check_clip ) {
+ if ( x_offset >= state->m_vdp.window_sprites_left && x_offset <= state->m_vdp.window_sprites_right ) {
+ continue;
+ }
+ } else {
+ if ( x_offset < state->m_vdp.window_sprites_left || x_offset > state->m_vdp.window_sprites_right ) {
+// continue;
+ }
+ }
+ }
+ if ( x_offset >= 0 && x_offset < WSWAN_X_PIXELS ) {
+ if ( state->m_vdp.colors_16 ) {
+ if ( col ) {
+ if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ } else {
+ /* Hmmmm, what should we do here... Is this correct?? */
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ }
+ }
+ } else {
+ if ( col || !(tile_palette & 4 ) ) {
+ if ( state->m_vdp.color_mode ) {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_pal[tile_palette][col];
+ } else {
+ state->m_bitmap.pix16(state->m_vdp.current_line, x_offset) = state->m_vdp.main_palette[state->m_pal[tile_palette][col]];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void wswan_refresh_scanline( running_machine &machine )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+
+ wswan_setup_palettes(state);
+
+ rectangle rec(0, WSWAN_X_PIXELS, state->m_vdp.current_line, state->m_vdp.current_line);
+ if ( state->m_ws_portram[0x14] ) {
+ /* Not sure if these background color checks and settings are correct */
+ if ( state->m_vdp.color_mode && state->m_vdp.colors_16 ) {
+ state->m_bitmap.fill( state->m_pal[state->m_ws_portram[0x01]>>4][state->m_ws_portram[0x01]&0x0F], rec );
+ } else {
+ state->m_bitmap.fill( state->m_vdp.main_palette[state->m_ws_portram[0x01]&0x07], rec );
+ }
+ } else {
+ state->m_bitmap.fill( 0, rec );
+ return;
+ }
+
+ /*
+ * Draw background layer
+ */
+ if ( state->m_vdp.layer_bg_enable ) {
+ wswan_draw_background(machine);
+ }
+
+ /*
+ * Draw sprites between background and foreground layers
+ */
+ if ( state->m_vdp.sprites_enable ) {
+ wswan_handle_sprites( machine, 0 );
+ }
+
+ /*
+ * Draw foreground layer, taking window settings into account
+ */
+ if ( state->m_vdp.layer_fg_enable ) {
+ switch( state->m_vdp.window_fg_mode ) {
+ case 0: /* FG inside & outside window area */
+ wswan_draw_foreground_0(machine);
+ break;
+ case 1: /* ??? */
+ logerror( "Unknown foreground mode 1 set\n" );
+ break;
+ case 2: /* FG only inside window area */
+ if ( state->m_vdp.current_line >= state->m_vdp.window_fg_top && state->m_vdp.current_line <= state->m_vdp.window_fg_bottom ) {
+ wswan_draw_foreground_2(machine);
+ }
+ break;
+ case 3: /* FG only outside window area */
+ if ( state->m_vdp.current_line < state->m_vdp.window_fg_top || state->m_vdp.current_line > state->m_vdp.window_fg_bottom ) {
+ wswan_draw_foreground_0(machine);
+ } else {
+ wswan_draw_foreground_3(machine);
+ }
+ break;
+ }
+ }
+
+ /*
+ * Draw sprites in front of foreground layer
+ */
+ if ( state->m_vdp.sprites_enable ) {
+ wswan_handle_sprites( machine, 0x2000 );
+ }
+}
+
+
+void wswan_state::video_start()
+{
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+}
+
+UINT32 wswan_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
diff --git a/src/mess/video/x68k.c b/src/mess/video/x68k.c
new file mode 100644
index 00000000000..41c778fb7c4
--- /dev/null
+++ b/src/mess/video/x68k.c
@@ -0,0 +1,1322 @@
+/*
+
+ Sharp X68000 video functions
+ driver by Barry Rodewald
+
+ X68000 video hardware (there are some minor revisions to these custom chips across various X680x0 models):
+ Custom sprite controller "Cynthia"
+ Custom CRT controller "Vinas / Vicon"
+ Custom video controller "VSOP / VIPS"
+ Custom video data selector "Cathy"
+
+ In general terms:
+ 1 "Text" layer - effectively a 4bpp bitmap split into 4 planes at 1bpp each
+ 512kB "text" VRAM
+ can write to multiple planes at once
+ can copy one character line to another character line
+ is 1024x1024 in size
+ Up to 4 graphic layers - can be 4 layers with a 16 colour palette, 2 layers with a 256 colour palette,
+ or 1 layer at 16-bit RGB.
+ 512k graphic VRAM
+ all layers are 512x512, but at 16 colours, the 4 layers can be combined into 1 1024x1024 layer
+ one or more layers can be cleared at once quickly with a simple hardware function
+ 2 tilemapped layers - can be 8x8 or 16x16, 16 colours per tile, max 256 colours overall
+ 1 sprite layer - up to 128 16x16 sprites, 16 colours per sprite, maximum 16 sprites per scanline (not yet implemented).
+
+*/
+
+#include "emu.h"
+#include "machine/mc68901.h"
+#include "includes/x68k.h"
+#include "machine/ram.h"
+
+
+
+
+static void x68k_crtc_refresh_mode(running_machine &machine);
+
+INLINE void x68k_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
+{
+ bitmap.pix16(y, x) = (UINT16)color;
+}
+/*
+static bitmap_ind16* x68k_get_gfx_page(int pri,int type)
+{
+ if(type == GFX16)
+ {
+ switch(pri)
+ {
+ case 0:
+ return x68k_gfx_0_bitmap_16;
+ case 1:
+ return x68k_gfx_1_bitmap_16;
+ case 2:
+ return x68k_gfx_2_bitmap_16;
+ case 3:
+ return x68k_gfx_3_bitmap_16;
+ default:
+ return x68k_gfx_0_bitmap_16; // should never reach here.
+ }
+ }
+ if(type == GFX256)
+ {
+ switch(pri)
+ {
+ case 0:
+ case 1:
+ return x68k_gfx_0_bitmap_256;
+ case 2:
+ case 3:
+ return x68k_gfx_1_bitmap_256;
+ default:
+ return x68k_gfx_0_bitmap_256; // should never reach here.
+ }
+ }
+ if(type == GFX65536)
+ return x68k_gfx_0_bitmap_65536;
+
+ return NULL; // should never reach here either.
+}
+*/
+static void x68k_crtc_text_copy(x68k_state *state, int src, int dest)
+{
+ // copys one raster in T-VRAM to another raster
+ UINT16* tvram;
+ int src_ram = src * 256; // 128 bytes per scanline
+ int dest_ram = dest * 256;
+ int line;
+
+ if(state->m_is_32bit)
+ tvram = (UINT16*)state->m_tvram32.target();
+ else
+ tvram = (UINT16*)state->m_tvram16.target();
+
+ if(dest > 250)
+ return; // for some reason, Salamander causes a SIGSEGV in a debug build in this function.
+
+ for(line=0;line<8;line++)
+ {
+ // update RAM in each plane
+ memcpy(tvram+dest_ram,tvram+src_ram,128);
+ memcpy(tvram+dest_ram+0x10000,tvram+src_ram+0x10000,128);
+ memcpy(tvram+dest_ram+0x20000,tvram+src_ram+0x20000,128);
+ memcpy(tvram+dest_ram+0x30000,tvram+src_ram+0x30000,128);
+
+ src_ram+=64;
+ dest_ram+=64;
+ }
+
+}
+
+static TIMER_CALLBACK(x68k_crtc_operation_end)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ int bit = param;
+ state->m_crtc.operation &= ~bit;
+}
+
+static void x68k_crtc_refresh_mode(running_machine &machine)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+// rectangle rect;
+// double scantime;
+ rectangle scr,visiblescr;
+ int length;
+
+ // Calculate data from register values
+ state->m_crtc.vmultiple = 1;
+ if((state->m_crtc.reg[20] & 0x10) != 0 && (state->m_crtc.reg[20] & 0x0c) == 0)
+ state->m_crtc.vmultiple = 2; // 31.5kHz + 256 lines = doublescan
+ if(state->m_crtc.interlace != 0)
+ state->m_crtc.vmultiple = 0.5f; // 31.5kHz + 1024 lines or 15kHz + 512 lines = interlaced
+ state->m_crtc.htotal = (state->m_crtc.reg[0] + 1) * 8;
+ state->m_crtc.vtotal = (state->m_crtc.reg[4] + 1) / state->m_crtc.vmultiple; // default is 567 (568 scanlines)
+ state->m_crtc.hbegin = (state->m_crtc.reg[2] * 8) + 1;
+ state->m_crtc.hend = (state->m_crtc.reg[3] * 8);
+ state->m_crtc.vbegin = (state->m_crtc.reg[6]) / state->m_crtc.vmultiple;
+ state->m_crtc.vend = (state->m_crtc.reg[7] - 1) / state->m_crtc.vmultiple;
+ state->m_crtc.hsync_end = (state->m_crtc.reg[1]) * 8;
+ state->m_crtc.vsync_end = (state->m_crtc.reg[5]) / state->m_crtc.vmultiple;
+ state->m_crtc.hsyncadjust = state->m_crtc.reg[8];
+ scr.set(0, state->m_crtc.htotal - 8, 0, state->m_crtc.vtotal);
+ if(scr.max_y <= state->m_crtc.vend)
+ scr.max_y = state->m_crtc.vend + 2;
+ if(scr.max_x <= state->m_crtc.hend)
+ scr.max_x = state->m_crtc.hend + 2;
+ visiblescr.set(state->m_crtc.hbegin, state->m_crtc.hend, state->m_crtc.vbegin, state->m_crtc.vend);
+
+ // expand visible area to the size indicated by CRTC reg 20
+ length = state->m_crtc.hend - state->m_crtc.hbegin;
+ if (length < state->m_crtc.width)
+ {
+ visiblescr.min_x = state->m_crtc.hbegin - ((state->m_crtc.width - length)/2);
+ visiblescr.max_x = state->m_crtc.hend + ((state->m_crtc.width - length)/2);
+ }
+ length = state->m_crtc.vend - state->m_crtc.vbegin;
+ if (length < state->m_crtc.height)
+ {
+ visiblescr.min_y = state->m_crtc.vbegin - ((state->m_crtc.height - length)/2);
+ visiblescr.max_y = state->m_crtc.vend + ((state->m_crtc.height - length)/2);
+ }
+ // bounds check
+ if(visiblescr.min_x < 0)
+ visiblescr.min_x = 0;
+ if(visiblescr.min_y < 0)
+ visiblescr.min_y = 0;
+ if(visiblescr.max_x >= scr.max_x)
+ visiblescr.max_x = scr.max_x - 2;
+ if(visiblescr.max_y >= scr.max_y - 1)
+ visiblescr.max_y = scr.max_y - 2;
+
+// logerror("CRTC regs - %i %i %i %i - %i %i %i %i - %i - %i\n",state->m_crtc.reg[0],state->m_crtc.reg[1],state->m_crtc.reg[2],state->m_crtc.reg[3],
+// state->m_crtc.reg[4],state->m_crtc.reg[5],state->m_crtc.reg[6],state->m_crtc.reg[7],state->m_crtc.reg[8],state->m_crtc.reg[9]);
+ logerror("video_screen_configure(machine.primary_screen,%i,%i,[%i,%i,%i,%i],55.45)\n",scr.max_x,scr.max_y,visiblescr.min_x,visiblescr.min_y,visiblescr.max_x,visiblescr.max_y);
+ machine.primary_screen->configure(scr.max_x,scr.max_y,visiblescr,HZ_TO_ATTOSECONDS(55.45));
+}
+
+TIMER_CALLBACK(x68k_hsync)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ int hstate = param;
+ attotime hsync_time;
+
+ state->m_crtc.hblank = hstate;
+ state->m_mfpdev->i7_w(!state->m_crtc.hblank);
+ if(state->m_crtc.vmultiple == 2) // 256-line (doublescan)
+ {
+ if(hstate == 1)
+ {
+ if(state->m_oddscanline == 1)
+ {
+ int scan = machine.primary_screen->vpos();
+ if(scan > state->m_crtc.vend)
+ scan = state->m_crtc.vbegin;
+ hsync_time = machine.primary_screen->time_until_pos(scan,(state->m_crtc.htotal + state->m_crtc.hend) / 2);
+ state->m_scanline_timer->adjust(hsync_time);
+ if(scan != 0)
+ {
+ if((machine.root_device().ioport("options")->read() & 0x04))
+ {
+ machine.primary_screen->update_partial(scan);
+ }
+ }
+ }
+ else
+ {
+ int scan = machine.primary_screen->vpos();
+ if(scan > state->m_crtc.vend)
+ scan = state->m_crtc.vbegin;
+ hsync_time = machine.primary_screen->time_until_pos(scan,state->m_crtc.hend / 2);
+ state->m_scanline_timer->adjust(hsync_time);
+ if(scan != 0)
+ {
+ if((machine.root_device().ioport("options")->read() & 0x04))
+ {
+ machine.primary_screen->update_partial(scan);
+ }
+ }
+ }
+ }
+ if(hstate == 0)
+ {
+ if(state->m_oddscanline == 1)
+ {
+ int scan = machine.primary_screen->vpos();
+ if(scan > state->m_crtc.vend)
+ scan = state->m_crtc.vbegin;
+ else
+ scan++;
+ hsync_time = machine.primary_screen->time_until_pos(scan,state->m_crtc.hbegin / 2);
+ state->m_scanline_timer->adjust(hsync_time, 1);
+ state->m_oddscanline = 0;
+ }
+ else
+ {
+ hsync_time = machine.primary_screen->time_until_pos(machine.primary_screen->vpos(),(state->m_crtc.htotal + state->m_crtc.hbegin) / 2);
+ state->m_scanline_timer->adjust(hsync_time, 1);
+ state->m_oddscanline = 1;
+ }
+ }
+ }
+ else // 512-line
+ {
+ if(hstate == 1)
+ {
+ int scan = machine.primary_screen->vpos();
+ if(scan > state->m_crtc.vend)
+ scan = 0;
+ hsync_time = machine.primary_screen->time_until_pos(scan,state->m_crtc.hend);
+ state->m_scanline_timer->adjust(hsync_time);
+ if(scan != 0)
+ {
+ if((machine.root_device().ioport("options")->read() & 0x04))
+ {
+ machine.primary_screen->update_partial(scan);
+ }
+ }
+ }
+ if(hstate == 0)
+ {
+ hsync_time = machine.primary_screen->time_until_pos(machine.primary_screen->vpos()+1,state->m_crtc.hbegin);
+ state->m_scanline_timer->adjust(hsync_time, 1);
+ // if(!(state->m_mfp.gpio & 0x40)) // if GPIP6 is active, clear it
+ // state->m_mfp.gpio |= 0x40;
+ }
+ }
+}
+
+static TIMER_CALLBACK(x68k_crtc_raster_end)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ state->m_mfp.gpio |= 0x40;
+ state->m_mfpdev->i6_w(1);
+}
+
+TIMER_CALLBACK(x68k_crtc_raster_irq)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ int scan = param;
+ attotime irq_time;
+ attotime end_time;
+
+ if(scan <= state->m_crtc.vtotal)
+ {
+ state->m_mfp.gpio &= ~0x40; // GPIP6
+ state->m_mfpdev->i6_w(0);
+ machine.primary_screen->update_partial(scan);
+ irq_time = machine.primary_screen->time_until_pos(scan,state->m_crtc.hbegin);
+ // end of HBlank period clears GPIP6 also?
+ end_time = machine.primary_screen->time_until_pos(scan,state->m_crtc.hend);
+ state->m_raster_irq->adjust(irq_time, scan);
+ machine.scheduler().timer_set(end_time, FUNC(x68k_crtc_raster_end));
+ logerror("GPIP6: Raster triggered at line %i (%i)\n",scan,machine.primary_screen->vpos());
+ }
+}
+
+TIMER_CALLBACK(x68k_crtc_vblank_irq)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ device_t *x68k_mfp = machine.device(MC68901_TAG);
+ int val = param;
+ attotime irq_time;
+ int vblank_line;
+
+ if(val == 1) // V-DISP on
+ {
+ state->m_crtc.vblank = 1;
+ vblank_line = state->m_crtc.vbegin;
+ irq_time = machine.primary_screen->time_until_pos(vblank_line,2);
+ state->m_vblank_irq->adjust(irq_time);
+ logerror("CRTC: VBlank on\n");
+ }
+ if(val == 0) // V-DISP off
+ {
+ state->m_crtc.vblank = 0;
+ vblank_line = state->m_crtc.vend;
+ if(vblank_line > state->m_crtc.vtotal)
+ vblank_line = state->m_crtc.vtotal;
+ irq_time = machine.primary_screen->time_until_pos(vblank_line,2);
+ state->m_vblank_irq->adjust(irq_time, 1);
+ logerror("CRTC: VBlank off\n");
+ }
+
+ if (x68k_mfp != NULL)
+ {
+ state->m_mfpdev->tai_w(!state->m_crtc.vblank);
+ state->m_mfpdev->i4_w(!state->m_crtc.vblank);
+ }
+}
+
+
+// CRTC "VINAS 1+2 / VICON" at 0xe80000
+/* 0xe80000 - Registers (all are 16-bit):
+ * 0 - Horizontal Total (in characters)
+ * 1 - Horizontal Sync End
+ * 2 - Horizontal Display Begin
+ * 3 - Horizontal Display End
+ * 4 - Vertical Total (in scanlines)
+ * 5 - Vertical Sync End
+ * 6 - Vertical Display Begin
+ * 7 - Vertical Display End
+ * 8 - Fine Horizontal Sync Adjustment
+ * 9 - Raster Line (for Raster IRQ mapped to MFP GPIP6)
+ * 10/11 - Text Layer X and Y Scroll
+ * 12/13 - Graphic Layer 0 X and Y Scroll
+ * 14/15 - Graphic Layer 1 X and Y Scroll
+ * 16/17 - Graphic Layer 2 X and Y Scroll
+ * 18/19 - Graphic Layer 3 X and Y Scroll
+ * 20 - bit 12 - Text VRAM mode : 0 = display, 1 = buffer
+ * bit 11 - Graphic VRAM mode : 0 = display, 1 = buffer
+ * bit 10 - "Real" screen size : 0 = 512x512, 1 = 1024x1024
+ * bits 8,9 - Colour mode :
+ * 00 = 16 colour 01 = 256 colour
+ * 10 = Undefined 11 = 65,536 colour
+ * bit 4 - Horizontal Frequency : 0 = 15.98kHz, 1 = 31.50kHz
+ * bits 2,3 - Vertical dots :
+ * 00 = 256 01 = 512
+ * 10 or 11 = 1024 (interlaced)
+ * bits 0,1 - Horizontal dots :
+ * 00 = 256 01 = 512
+ * 10 = 768 11 = 50MHz clock mode (Compact XVI or later)
+ * 21 - bit 9 - Text Screen Access Mask Enable
+ * bit 8 - Text Screen Simultaneous Plane Access Enable
+ * bits 4-7 - Text Screen Simultaneous Plane Access Select
+ * bits 0-3 - Text Screen Line Copy Plane Select
+ * Graphic Screen High-speed Clear Page Select
+ * 22 - Text Screen Line Copy
+ * bits 15-8 - Source Line
+ * bits 7-0 - Destination Line
+ * 23 - Text Screen Mask Pattern
+ *
+ * 0xe80481 - Operation Port (8-bit):
+ * bit 3 - Text Screen Line Copy Begin
+ * bit 1 - Graphic Screen High-speed Clear Begin
+ * bit 0 - Image Taking Begin (?)
+ * Operation Port bits are cleared automatically when the requested
+ * operation is completed.
+ */
+WRITE16_HANDLER( x68k_crtc_w )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+ COMBINE_DATA(state->m_crtc.reg+offset);
+ switch(offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ x68k_crtc_refresh_mode(space->machine());
+ break;
+ case 9: // CRTC raster IRQ (GPIP6)
+ {
+ attotime irq_time;
+ irq_time = space->machine().primary_screen->time_until_pos((data) / state->m_crtc.vmultiple,2);
+
+ if(irq_time.as_double() > 0)
+ state->m_raster_irq->adjust(irq_time, (data) / state->m_crtc.vmultiple);
+ }
+ logerror("CRTC: Write to raster IRQ register - %i\n",data);
+ break;
+ case 20:
+ if(ACCESSING_BITS_0_7)
+ {
+ state->m_crtc.interlace = 0;
+ switch(data & 0x0c)
+ {
+ case 0x00:
+ state->m_crtc.height = 256;
+ break;
+ case 0x08:
+ case 0x0c: // TODO: 1024 vertical, if horizontal freq = 31kHz
+ state->m_crtc.height = 512;
+ state->m_crtc.interlace = 1; // if 31kHz, 1024 lines = interlaced
+ break;
+ case 0x04:
+ state->m_crtc.height = 512;
+ if(!(state->m_crtc.reg[20] & 0x0010)) // if 15kHz, 512 lines = interlaced
+ state->m_crtc.interlace = 1;
+ break;
+ }
+ switch(data & 0x03)
+ {
+ case 0x00:
+ state->m_crtc.width = 256;
+ break;
+ case 0x01:
+ state->m_crtc.width = 512;
+ break;
+ case 0x02:
+ case 0x03: // 0x03 = 50MHz clock mode (XVI only)
+ state->m_crtc.width = 768;
+ break;
+ }
+ }
+/* if(ACCESSING_BITS_8_15)
+ {
+ state->m_crtc.interlace = 0;
+ if(data & 0x0400)
+ state->m_crtc.interlace = 1;
+ }*/
+ x68k_crtc_refresh_mode(space->machine());
+ break;
+ case 576: // operation register
+ state->m_crtc.operation = data;
+ if(data & 0x08) // text screen raster copy
+ {
+ x68k_crtc_text_copy(state, (state->m_crtc.reg[22] & 0xff00) >> 8,(state->m_crtc.reg[22] & 0x00ff));
+ space->machine().scheduler().timer_set(attotime::from_msec(1), FUNC(x68k_crtc_operation_end), 0x02); // time taken to do operation is a complete guess.
+ }
+ if(data & 0x02) // high-speed graphic screen clear
+ {
+ if(state->m_is_32bit)
+ memset(state->m_gvram32,0,0x40000);
+ else
+ memset(state->m_gvram16,0,0x40000);
+ space->machine().scheduler().timer_set(attotime::from_msec(10), FUNC(x68k_crtc_operation_end), 0x02); // time taken to do operation is a complete guess.
+ }
+ break;
+ }
+// logerror("CRTC: [%08x] Wrote %04x to CRTC register %i\n",cpu_get_pc(space->machine().device("maincpu")),data,offset);
+}
+
+READ16_HANDLER( x68k_crtc_r )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+#if 0
+ switch(offset)
+ {
+ default:
+ logerror("CRTC: [%08x] Read from CRTC register %i\n",activecpu_get_pc(),offset);
+ return 0xff;
+ }
+#endif
+
+ if(offset < 24)
+ {
+// logerror("CRTC: [%08x] Read %04x from CRTC register %i\n",cpu_get_pc(space->machine().device("maincpu")),state->m_crtc.reg[offset],offset);
+ switch(offset)
+ {
+ case 9:
+ return 0;
+ case 10: // Text X/Y scroll
+ case 11:
+ case 12: // Graphic layer 0 scroll
+ case 13:
+ return state->m_crtc.reg[offset] & 0x3ff;
+ case 14: // Graphic layer 1 scroll
+ case 15:
+ case 16: // Graphic layer 2 scroll
+ case 17:
+ case 18: // Graphic layer 3 scroll
+ case 19:
+ return state->m_crtc.reg[offset] & 0x1ff;
+ default:
+ return state->m_crtc.reg[offset];
+ }
+ }
+ if(offset == 576) // operation port, operation bits are set to 0 when operation is complete
+ return state->m_crtc.operation;
+// logerror("CRTC: [%08x] Read from unknown CRTC register %i\n",activecpu_get_pc(),offset);
+ return 0xffff;
+}
+
+WRITE16_HANDLER( x68k_gvram_w )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+ UINT16* gvram;
+// int xloc,yloc,pageoffset;
+ /*
+ G-VRAM usage is determined by colour depth and "real" screen size.
+
+ For screen size of 1024x1024, all G-VRAM space is used, in one big page.
+ At 1024x1024 real screen size, colour depth is always 4bpp, and ranges from
+ 0xc00000-0xdfffff.
+
+ For screen size of 512x512, the colour depth determines the page usage.
+ 16 colours = 4 pages
+ 256 colours = 2 pages
+ 65,536 colours = 1 page
+ Page 1 - 0xc00000-0xc7ffff Page 2 - 0xc80000-0xcfffff
+ Page 3 - 0xd00000-0xd7ffff Page 4 - 0xd80000-0xdfffff
+ */
+
+ if(state->m_is_32bit)
+ gvram = (UINT16*)state->m_gvram32.target();
+ else
+ gvram = (UINT16*)state->m_gvram16.target();
+
+ // handle different G-VRAM page setups
+ if(state->m_crtc.reg[20] & 0x08) // G-VRAM set to buffer
+ {
+ if(offset < 0x40000)
+ COMBINE_DATA(gvram+offset);
+ }
+ else
+ {
+ switch(state->m_crtc.reg[20] & 0x0300)
+ {
+ case 0x0300:
+ if(offset < 0x40000)
+ COMBINE_DATA(gvram+offset);
+ break;
+ case 0x0100:
+ if(offset < 0x40000)
+ {
+ gvram[offset] = (gvram[offset] & 0xff00) | (data & 0x00ff);
+ }
+ if(offset >= 0x40000 && offset < 0x80000)
+ {
+ gvram[offset-0x40000] = (gvram[offset-0x40000] & 0x00ff) | ((data & 0x00ff) << 8);
+ }
+ break;
+ case 0x0000:
+ if(offset < 0x40000)
+ {
+ gvram[offset] = (gvram[offset] & 0xfff0) | (data & 0x000f);
+ }
+ if(offset >= 0x40000 && offset < 0x80000)
+ {
+ gvram[offset-0x40000] = (gvram[offset-0x40000] & 0xff0f) | ((data & 0x000f) << 4);
+ }
+ if(offset >= 0x80000 && offset < 0xc0000)
+ {
+ gvram[offset-0x80000] = (gvram[offset-0x80000] & 0xf0ff) | ((data & 0x000f) << 8);
+ }
+ if(offset >= 0xc0000 && offset < 0x100000)
+ {
+ gvram[offset-0xc0000] = (gvram[offset-0xc0000] & 0x0fff) | ((data & 0x000f) << 12);
+ }
+ break;
+ default:
+ logerror("G-VRAM written while layer setup is undefined.\n");
+ }
+ }
+}
+
+WRITE16_HANDLER( x68k_tvram_w )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+ UINT16* tvram;
+ UINT16 text_mask;
+
+ if(state->m_is_32bit)
+ tvram = (UINT16*)state->m_tvram32.target();
+ else
+ tvram = (UINT16*)state->m_tvram16.target();
+
+ text_mask = ~(state->m_crtc.reg[23]) & mem_mask;
+
+ if(!(state->m_crtc.reg[21] & 0x0200)) // text access mask enable
+ text_mask = 0xffff & mem_mask;
+
+ mem_mask = text_mask;
+
+ if(state->m_crtc.reg[21] & 0x0100)
+ { // simultaneous T-VRAM plane access (I think ;))
+ int plane,wr;
+ offset = offset & 0x00ffff;
+ wr = (state->m_crtc.reg[21] & 0x00f0) >> 4;
+ for(plane=0;plane<4;plane++)
+ {
+ if(wr & (1 << plane))
+ {
+ COMBINE_DATA(tvram+offset+(0x10000*plane));
+ }
+ }
+ }
+ else
+ {
+ COMBINE_DATA(tvram+offset);
+ }
+}
+
+READ16_HANDLER( x68k_gvram_r )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+ const UINT16* gvram;
+ UINT16 ret = 0;
+
+ if(state->m_is_32bit)
+ gvram = (const UINT16*)state->m_gvram32.target();
+ else
+ gvram = (const UINT16*)state->m_gvram16.target();
+
+ if(state->m_crtc.reg[20] & 0x08) // G-VRAM set to buffer
+ return gvram[offset];
+
+ switch(state->m_crtc.reg[20] & 0x0300) // colour setup determines G-VRAM use
+ {
+ case 0x0300: // 65,536 colour (RGB) - 16-bits per word
+ if(offset < 0x40000)
+ ret = gvram[offset];
+ else
+ ret = 0xffff;
+ break;
+ case 0x0100: // 256 colour (paletted) - 8 bits per word
+ if(offset < 0x40000)
+ ret = gvram[offset] & 0x00ff;
+ if(offset >= 0x40000 && offset < 0x80000)
+ ret = (gvram[offset-0x40000] & 0xff00) >> 8;
+ if(offset >= 0x80000)
+ ret = 0xffff;
+ break;
+ case 0x0000: // 16 colour (paletted) - 4 bits per word
+ if(offset < 0x40000)
+ ret = gvram[offset] & 0x000f;
+ if(offset >= 0x40000 && offset < 0x80000)
+ ret = (gvram[offset-0x40000] & 0x00f0) >> 4;
+ if(offset >= 0x80000 && offset < 0xc0000)
+ ret = (gvram[offset-0x80000] & 0x0f00) >> 8;
+ if(offset >= 0xc0000 && offset < 0x100000)
+ ret = (gvram[offset-0xc0000] & 0xf000) >> 12;
+ break;
+ default:
+ logerror("G-VRAM read while layer setup is undefined.\n");
+ ret = 0xffff;
+ }
+
+ return ret;
+}
+
+READ16_HANDLER( x68k_tvram_r )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+ const UINT16* tvram;
+
+ if(state->m_is_32bit)
+ tvram = (const UINT16*)state->m_tvram32.target();
+ else
+ tvram = (const UINT16*)state->m_tvram16.target();
+
+ return tvram[offset];
+}
+
+READ32_HANDLER( x68k_tvram32_r )
+{
+ UINT32 ret = 0;
+
+ if(ACCESSING_BITS_0_15)
+ ret |= (x68k_tvram_r(space,(offset*2)+1,0xffff));
+ if(ACCESSING_BITS_16_31)
+ ret |= x68k_tvram_r(space,offset*2,0xffff) << 16;
+
+ return ret;
+}
+
+READ32_HANDLER( x68k_gvram32_r )
+{
+ UINT32 ret = 0;
+
+ if(ACCESSING_BITS_0_15)
+ ret |= x68k_gvram_r(space,offset*2+1,0xffff);
+ if(ACCESSING_BITS_16_31)
+ ret |= x68k_gvram_r(space,offset*2,0xffff) << 16;
+
+ return ret;
+}
+
+WRITE32_HANDLER( x68k_tvram32_w )
+{
+ if(ACCESSING_BITS_0_7)
+ x68k_tvram_w(space,(offset*2)+1,data,0x00ff);
+ if(ACCESSING_BITS_8_15)
+ x68k_tvram_w(space,(offset*2)+1,data,0xff00);
+ if(ACCESSING_BITS_16_23)
+ x68k_tvram_w(space,offset*2,data >> 16,0x00ff);
+ if(ACCESSING_BITS_24_31)
+ x68k_tvram_w(space,offset*2,data >> 16,0xff00);
+}
+
+WRITE32_HANDLER( x68k_gvram32_w )
+{
+ if(ACCESSING_BITS_0_7)
+ x68k_gvram_w(space,(offset*2)+1,data,0x00ff);
+ if(ACCESSING_BITS_8_15)
+ x68k_gvram_w(space,(offset*2)+1,data,0xff00);
+ if(ACCESSING_BITS_16_23)
+ x68k_gvram_w(space,offset*2,data >> 16,0x00ff);
+ if(ACCESSING_BITS_24_31)
+ x68k_gvram_w(space,offset*2,data >> 16,0xff00);
+}
+
+WRITE16_HANDLER( x68k_spritereg_w )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+ COMBINE_DATA(state->m_spritereg+offset);
+ switch(offset)
+ {
+ case 0x400:
+ state->m_bg0_8->set_scrollx(0,(data - state->m_crtc.hbegin - state->m_crtc.bg_hshift) & 0x3ff);
+ state->m_bg0_16->set_scrollx(0,(data - state->m_crtc.hbegin - state->m_crtc.bg_hshift) & 0x3ff);
+ break;
+ case 0x401:
+ state->m_bg0_8->set_scrolly(0,(data - state->m_crtc.vbegin) & 0x3ff);
+ state->m_bg0_16->set_scrolly(0,(data - state->m_crtc.vbegin) & 0x3ff);
+ break;
+ case 0x402:
+ state->m_bg1_8->set_scrollx(0,(data - state->m_crtc.hbegin - state->m_crtc.bg_hshift) & 0x3ff);
+ state->m_bg1_16->set_scrollx(0,(data - state->m_crtc.hbegin - state->m_crtc.bg_hshift) & 0x3ff);
+ break;
+ case 0x403:
+ state->m_bg1_8->set_scrolly(0,(data - state->m_crtc.vbegin) & 0x3ff);
+ state->m_bg1_16->set_scrolly(0,(data - state->m_crtc.vbegin) & 0x3ff);
+ break;
+ case 0x406: // BG H-DISP (normally equals CRTC reg 2 value + 4)
+ if(data != 0x00ff)
+ {
+ state->m_crtc.bg_visible_width = (state->m_crtc.reg[3] - ((data & 0x003f) - 4)) * 8;
+ state->m_crtc.bg_hshift = ((data - (state->m_crtc.reg[2]+4)) * 8);
+ if(state->m_crtc.bg_hshift > 0)
+ state->m_crtc.bg_hshift = 0;
+ }
+ break;
+ case 0x407: // BG V-DISP (like CRTC reg 6)
+ state->m_crtc.bg_vshift = state->m_crtc.vshift;
+ break;
+ case 0x408: // BG H/V-Res
+ state->m_crtc.bg_hvres = data & 0x1f;
+ if(data != 0xff)
+ { // Handle when the PCG is using 256 and the CRTC is using 512
+ if((state->m_crtc.bg_hvres & 0x0c) == 0x00 && (state->m_crtc.reg[20] & 0x0c) == 0x04)
+ state->m_crtc.bg_double = 2;
+ else
+ state->m_crtc.bg_double = 1;
+ }
+ else
+ state->m_crtc.bg_double = 1;
+ break;
+ }
+}
+
+READ16_HANDLER( x68k_spritereg_r )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+ if(offset >= 0x400 && offset < 0x404)
+ return state->m_spritereg[offset] & 0x3ff;
+ return state->m_spritereg[offset];
+}
+
+WRITE16_HANDLER( x68k_spriteram_w )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+ COMBINE_DATA(state->m_spriteram+offset);
+ state->m_video.tile8_dirty[offset / 16] = 1;
+ state->m_video.tile16_dirty[offset / 64] = 1;
+ if(offset < 0x2000)
+ {
+ state->m_bg1_8->mark_all_dirty();
+ state->m_bg1_16->mark_all_dirty();
+ state->m_bg0_8->mark_all_dirty();
+ state->m_bg0_16->mark_all_dirty();
+ }
+ if(offset >= 0x2000 && offset < 0x3000)
+ {
+ state->m_bg1_8->mark_tile_dirty(offset & 0x0fff);
+ state->m_bg1_16->mark_tile_dirty(offset & 0x0fff);
+ }
+ if(offset >= 0x3000)
+ {
+ state->m_bg0_8->mark_tile_dirty(offset & 0x0fff);
+ state->m_bg0_16->mark_tile_dirty(offset & 0x0fff);
+ }
+}
+
+READ16_HANDLER( x68k_spriteram_r )
+{
+ x68k_state *state = space->machine().driver_data<x68k_state>();
+ return state->m_spriteram[offset];
+}
+
+static void x68k_draw_text(running_machine &machine,bitmap_ind16 &bitmap, int xscr, int yscr, rectangle rect)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ const UINT16* tvram;
+ unsigned int line,pixel; // location on screen
+ UINT32 loc; // location in TVRAM
+ UINT32 colour;
+ int bit;
+
+ if(state->m_is_32bit)
+ tvram = (const UINT16*)state->m_tvram32.target();
+ else
+ tvram = (const UINT16*)state->m_tvram16.target();
+
+ for(line=rect.min_y;line<=rect.max_y;line++) // per scanline
+ {
+ // adjust for scroll registers
+ loc = (((line - state->m_crtc.vbegin) + yscr) & 0x3ff) * 64;
+ loc += (xscr / 16) & 0x7f;
+ loc &= 0xffff;
+ bit = 15 - (xscr & 0x0f);
+ for(pixel=rect.min_x;pixel<=rect.max_x;pixel++) // per pixel
+ {
+ colour = (((tvram[loc] >> bit) & 0x01) ? 1 : 0)
+ + (((tvram[loc+0x10000] >> bit) & 0x01) ? 2 : 0)
+ + (((tvram[loc+0x20000] >> bit) & 0x01) ? 4 : 0)
+ + (((tvram[loc+0x30000] >> bit) & 0x01) ? 8 : 0);
+ if(state->m_video.text_pal[colour] != 0x0000) // any colour but black
+ {
+ // Colour 0 is displayable if the text layer is at the priority level 2
+ if(colour == 0 && (state->m_video.reg[1] & 0x0c00) == 0x0800)
+ bitmap.pix16(line, pixel) = 512 + (state->m_video.text_pal[colour] >> 1);
+ else
+ if(colour != 0)
+ bitmap.pix16(line, pixel) = 512 + (state->m_video.text_pal[colour] >> 1);
+ }
+ bit--;
+ if(bit < 0)
+ {
+ bit = 15;
+ loc++;
+ loc &= 0xffff;
+ }
+ }
+ }
+}
+
+static void x68k_draw_gfx_scanline(running_machine &machine, bitmap_ind16 &bitmap, rectangle cliprect, UINT8 priority)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ const UINT16* gvram;
+ int pixel;
+ int page;
+ UINT32 loc; // location in GVRAM
+ UINT32 lineoffset;
+ UINT16 xscr,yscr;
+ UINT16 colour = 0;
+ int shift;
+ int scanline;
+
+ if(state->m_is_32bit)
+ gvram = (const UINT16*)state->m_gvram32.target();
+ else
+ gvram = (const UINT16*)state->m_gvram16.target();
+
+ for(scanline=cliprect.min_y;scanline<=cliprect.max_y;scanline++) // per scanline
+ {
+ if(state->m_crtc.reg[20] & 0x0400) // 1024x1024 "real" screen size - use 1024x1024 16-colour gfx layer
+ {
+ // adjust for scroll registers
+ if(state->m_video.reg[2] & 0x0010 && priority == state->m_video.gfxlayer_pri[0])
+ {
+ xscr = (state->m_crtc.reg[12] & 0x3ff);
+ yscr = (state->m_crtc.reg[13] & 0x3ff);
+ lineoffset = (((scanline - state->m_crtc.vbegin) + yscr) & 0x3ff) * 1024;
+ loc = xscr & 0x3ff;
+ for(pixel=state->m_crtc.hbegin;pixel<=state->m_crtc.hend;pixel++)
+ {
+ switch(lineoffset & 0xc0000)
+ {
+ case 0x00000:
+ colour = gvram[lineoffset + (loc & 0x3ff)] & 0x000f;
+ break;
+ case 0x40000:
+ colour = (gvram[(lineoffset - 0x40000) + (loc & 0x3ff)] & 0x00f0) >> 4;
+ break;
+ case 0x80000:
+ colour = (gvram[(lineoffset - 0x80000) + (loc & 0x3ff)] & 0x0f00) >> 8;
+ break;
+ case 0xc0000:
+ colour = (gvram[(lineoffset - 0xc0000) + (loc & 0x3ff)] & 0xf000) >> 12;
+ break;
+ }
+ if(colour != 0)
+ bitmap.pix16(scanline, pixel) = 512 + (state->m_video.gfx_pal[colour] >> 1);
+ loc++;
+ loc &= 0x3ff;
+ }
+ }
+ }
+ else // else 512x512 "real" screen size
+ {
+ if(state->m_video.reg[2] & (1 << priority))
+ {
+ page = state->m_video.gfxlayer_pri[priority];
+ // adjust for scroll registers
+ switch(state->m_video.reg[0] & 0x03)
+ {
+ case 0x00: // 16 colours
+ xscr = ((state->m_crtc.reg[12+(page*2)])) & 0x1ff;
+ yscr = ((state->m_crtc.reg[13+(page*2)])) & 0x1ff;
+ lineoffset = (((scanline - state->m_crtc.vbegin) + yscr) & 0x1ff) * 512;
+ loc = xscr & 0x1ff;
+ shift = 4;
+ for(pixel=state->m_crtc.hbegin;pixel<=state->m_crtc.hend;pixel++)
+ {
+ colour = ((gvram[lineoffset + loc] >> page*shift) & 0x000f);
+ if(colour != 0)
+ bitmap.pix16(scanline, pixel) = 512 + (state->m_video.gfx_pal[colour & 0x0f] >> 1);
+ loc++;
+ loc &= 0x1ff;
+ }
+ break;
+ case 0x01: // 256 colours
+ if(page == 0 || page == 2)
+ {
+ xscr = ((state->m_crtc.reg[12+(page*2)])) & 0x1ff;
+ yscr = ((state->m_crtc.reg[13+(page*2)])) & 0x1ff;
+ lineoffset = (((scanline - state->m_crtc.vbegin) + yscr) & 0x1ff) * 512;
+ loc = xscr & 0x1ff;
+ shift = 4;
+ for(pixel=state->m_crtc.hbegin;pixel<=state->m_crtc.hend;pixel++)
+ {
+ colour = ((gvram[lineoffset + loc] >> page*shift) & 0x00ff);
+ if(colour != 0)
+ bitmap.pix16(scanline, pixel) = 512 + (state->m_video.gfx_pal[colour & 0xff] >> 1);
+ loc++;
+ loc &= 0x1ff;
+ }
+ }
+ break;
+ case 0x03: // 65536 colours
+ xscr = ((state->m_crtc.reg[12])) & 0x1ff;
+ yscr = ((state->m_crtc.reg[13])) & 0x1ff;
+ lineoffset = (((scanline - state->m_crtc.vbegin) + yscr) & 0x1ff) * 512;
+ loc = xscr & 0x1ff;
+ for(pixel=state->m_crtc.hbegin;pixel<=state->m_crtc.hend;pixel++)
+ {
+ colour = gvram[lineoffset + loc];
+ if(colour != 0)
+ bitmap.pix16(scanline, pixel) = 512 + (colour >> 1);
+ loc++;
+ loc &= 0x1ff;
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void x68k_draw_gfx(running_machine &machine, bitmap_ind16 &bitmap,rectangle cliprect)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ int priority;
+ //rectangle rect;
+ //int xscr,yscr;
+ //int gpage;
+
+ if(state->m_crtc.reg[20] & 0x0800) // if graphic layers are set to buffer, then they aren't visible
+ return;
+
+ for(priority=3;priority>=0;priority--)
+ {
+ x68k_draw_gfx_scanline(machine, bitmap,cliprect,priority);
+ }
+}
+
+// Sprite controller "Cynthia" at 0xeb0000
+static void x68k_draw_sprites(running_machine &machine, bitmap_ind16 &bitmap, int priority, rectangle cliprect)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ /*
+ 0xeb0000 - 0xeb07ff - Sprite registers (up to 128)
+ + 00 : b9-0, Sprite X position
+ + 02 : b9-0, Sprite Y position
+ + 04 : b15, Vertical Reversing (flipping?)
+ b14, Horizontal Reversing
+ b11-8, Sprite colour
+ b7-0, Sprite tile code (in PCG)
+ + 06 : b1-0, Priority
+ 00 = Sprite not displayed
+
+ 0xeb0800 - BG0 X Scroll (10-bit)
+ 0xeb0802 - BG0 Y Scroll
+ 0xeb0804 - BG1 X Scroll
+ 0xeb0806 - BG1 Y Scroll
+ 0xeb0808 - BG control
+ b9, BG/Sprite display (RAM and register access is faster if 1)
+ b4, PCG area 1 available
+ b3, BG1 display enable
+ b1, PCG area 0 available
+ b0, BG0 display enable
+ 0xeb080a - Horizontal total (like CRTC reg 0 - is 0xff if in 256x256?)
+ 0xeb080c - Horizontal display position (like CRTC reg 2 - +4)
+ 0xeb080e - Vertical display position (like CRTC reg 6)
+ 0xeb0810 - Resolution setting
+ b4, "L/H" (apparently 15kHz/31kHz switch for sprites/BG?)
+ b3-2, V-Res
+ b1-0, H-Res (0 = 8x8 tilemaps, 1 = 16x16 tilemaps, 2 or 3 = unknown)
+ */
+ int ptr,pri;
+
+ for(ptr=508;ptr>=0;ptr-=4) // stepping through sprites
+ {
+ pri = state->m_spritereg[ptr+3] & 0x03;
+#ifdef MAME_DEBUG
+ if(!(machine.input().code_pressed(KEYCODE_I)))
+#endif
+ if(pri == priority)
+ { // if at the right priority level, draw the sprite
+ rectangle rect;
+ int code = state->m_spritereg[ptr+2] & 0x00ff;
+ int colour = (state->m_spritereg[ptr+2] & 0x0f00) >> 8;
+ int xflip = state->m_spritereg[ptr+2] & 0x4000;
+ int yflip = state->m_spritereg[ptr+2] & 0x8000;
+ int sx = (state->m_spritereg[ptr+0] & 0x3ff) - 16;
+ int sy = (state->m_spritereg[ptr+1] & 0x3ff) - 16;
+
+ rect.min_x=state->m_crtc.hshift;
+ rect.min_y=state->m_crtc.vshift;
+ rect.max_x=rect.min_x + state->m_crtc.visible_width-1;
+ rect.max_y=rect.min_y + state->m_crtc.visible_height-1;
+
+ sx += state->m_crtc.bg_hshift;
+ sx += state->m_sprite_shift;
+
+ drawgfxzoom_transpen(bitmap,cliprect,machine.gfx[1],code,colour+0x10,xflip,yflip,state->m_crtc.hbegin+sx,state->m_crtc.vbegin+(sy*state->m_crtc.bg_double),0x10000,0x10000*state->m_crtc.bg_double,0x00);
+ }
+ }
+}
+
+PALETTE_INIT( x68000 )
+{
+ int pal;
+ int r,g,b;
+
+ for(pal=0;pal<32768;pal++)
+ { // create 64k colour lookup
+ g = (pal & 0x7c00) >> 7;
+ r = (pal & 0x03e0) >> 2;
+ b = (pal & 0x001f) << 3;
+ palette_set_color_rgb(machine,pal+512,r,g,b);
+ }
+}
+
+static const gfx_layout x68k_pcg_8 =
+{
+ 8,8,
+ 256,
+ 4,
+ { 0,1,2,3 },
+ { 8,12,0,4,24,28,16,20 },
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
+ 32*8
+};
+
+static const gfx_layout x68k_pcg_16 =
+{
+ 16,16,
+ 256,
+ 4,
+ { 0,1,2,3 },
+ { 8,12,0,4,24,28,16,20,8+64*8,12+64*8,64*8,4+64*8,24+64*8,28+64*8,16+64*8,20+64*8 },
+ { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32,
+ 8*32, 9*32, 10*32, 11*32, 12*32, 13*32, 14*32, 15*32 },
+ 128*8
+};
+
+#if 0
+static GFXDECODEINFO_START( x68k )
+ GFXDECODE_ENTRY( "user1", 0, x68k_pcg_8, 0x100, 16 ) // 8x8 sprite tiles
+ GFXDECODE_ENTRY( "user1", 0, x68k_pcg_16, 0x100, 16 ) // 16x16 sprite tiles
+GFXDECODEINFO_END
+#endif
+
+static TILE_GET_INFO(x68k_get_bg0_tile)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ int code = state->m_spriteram[0x3000+tile_index] & 0x00ff;
+ int colour = (state->m_spriteram[0x3000+tile_index] & 0x0f00) >> 8;
+ int flags = (state->m_spriteram[0x3000+tile_index] & 0xc000) >> 14;
+ SET_TILE_INFO(0,code,colour+16,flags);
+}
+
+static TILE_GET_INFO(x68k_get_bg1_tile)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ int code = state->m_spriteram[0x2000+tile_index] & 0x00ff;
+ int colour = (state->m_spriteram[0x2000+tile_index] & 0x0f00) >> 8;
+ int flags = (state->m_spriteram[0x2000+tile_index] & 0xc000) >> 14;
+ SET_TILE_INFO(0,code,colour+16,flags);
+}
+
+static TILE_GET_INFO(x68k_get_bg0_tile_16)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ int code = state->m_spriteram[0x3000+tile_index] & 0x00ff;
+ int colour = (state->m_spriteram[0x3000+tile_index] & 0x0f00) >> 8;
+ int flags = (state->m_spriteram[0x3000+tile_index] & 0xc000) >> 14;
+ SET_TILE_INFO(1,code,colour+16,flags);
+}
+
+static TILE_GET_INFO(x68k_get_bg1_tile_16)
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ int code = state->m_spriteram[0x2000+tile_index] & 0x00ff;
+ int colour = (state->m_spriteram[0x2000+tile_index] & 0x0f00) >> 8;
+ int flags = (state->m_spriteram[0x2000+tile_index] & 0xc000) >> 14;
+ SET_TILE_INFO(1,code,colour+16,flags);
+}
+
+VIDEO_START( x68000 )
+{
+ x68k_state *state = machine.driver_data<x68k_state>();
+ int gfx_index;
+
+ for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
+ if (machine.gfx[gfx_index] == 0)
+ break;
+
+ /* create the char set (gfx will then be updated dynamically from RAM) */
+ machine.gfx[gfx_index] = gfx_element_alloc(machine, &x68k_pcg_8, machine.root_device().memregion("user1")->base(), 32, 0);
+
+ gfx_index++;
+
+ machine.gfx[gfx_index] = gfx_element_alloc(machine, &x68k_pcg_16, state->memregion("user1")->base(), 32, 0);
+ machine.gfx[gfx_index]->total_colors = 32;
+
+ /* Tilemaps */
+ state->m_bg0_8 = tilemap_create(machine, x68k_get_bg0_tile,tilemap_scan_rows,8,8,64,64);
+ state->m_bg1_8 = tilemap_create(machine, x68k_get_bg1_tile,tilemap_scan_rows,8,8,64,64);
+ state->m_bg0_16 = tilemap_create(machine, x68k_get_bg0_tile_16,tilemap_scan_rows,16,16,64,64);
+ state->m_bg1_16 = tilemap_create(machine, x68k_get_bg1_tile_16,tilemap_scan_rows,16,16,64,64);
+
+ state->m_bg0_8->set_transparent_pen(0);
+ state->m_bg1_8->set_transparent_pen(0);
+ state->m_bg0_16->set_transparent_pen(0);
+ state->m_bg1_16->set_transparent_pen(0);
+
+// state->m_scanline_timer->adjust(attotime::zero, 0, attotime::from_hz(55.45)/568);
+}
+
+SCREEN_UPDATE_IND16( x68000 )
+{
+ x68k_state *state = screen.machine().driver_data<x68k_state>();
+ rectangle rect(0,0,0,0);
+ int priority;
+ int xscr,yscr;
+ int x;
+ tilemap_t* x68k_bg0;
+ tilemap_t* x68k_bg1;
+ //UINT8 *rom;
+
+ if((state->m_spritereg[0x408] & 0x03) == 0x00) // Sprite/BG H-Res 0=8x8, 1=16x16, 2 or 3 = undefined.
+ {
+ x68k_bg0 = state->m_bg0_8;
+ x68k_bg1 = state->m_bg1_8;
+ }
+ else
+ {
+ x68k_bg0 = state->m_bg0_16;
+ x68k_bg1 = state->m_bg1_16;
+ }
+// rect.max_x=state->m_crtc.width;
+// rect.max_y=state->m_crtc.height;
+ bitmap.fill(0, cliprect);
+
+ if(state->m_sysport.contrast == 0) // if monitor contrast is 0, then don't bother displaying anything
+ return 0;
+
+ rect.min_x=state->m_crtc.hbegin;
+ rect.min_y=state->m_crtc.vbegin;
+// rect.max_x=rect.min_x + state->m_crtc.visible_width-1;
+// rect.max_y=rect.min_y + state->m_crtc.visible_height-1;
+ rect.max_x=state->m_crtc.hend;
+ rect.max_y=state->m_crtc.vend;
+
+ if(rect.min_y < cliprect.min_y)
+ rect.min_y = cliprect.min_y;
+ if(rect.max_y > cliprect.max_y)
+ rect.max_y = cliprect.max_y;
+
+ // update tiles
+ //rom = screen.machine().root_device().memregion("user1")->base();
+ for(x=0;x<256;x++)
+ {
+ if(state->m_video.tile16_dirty[x] != 0)
+ {
+ gfx_element_mark_dirty(screen.machine().gfx[1], x);
+ state->m_video.tile16_dirty[x] = 0;
+ }
+ if(state->m_video.tile8_dirty[x] != 0)
+ {
+ gfx_element_mark_dirty(screen.machine().gfx[0], x);
+ state->m_video.tile8_dirty[x] = 0;
+ }
+ }
+
+ for(priority=3;priority>=0;priority--)
+ {
+ // Graphics screen(s)
+ if(priority == state->m_video.gfx_pri)
+ x68k_draw_gfx(screen.machine(),bitmap,rect);
+
+ // Sprite / BG Tiles
+ if(priority == state->m_video.sprite_pri /*&& (state->m_spritereg[0x404] & 0x0200)*/ && (state->m_video.reg[2] & 0x0040))
+ {
+ x68k_draw_sprites(screen.machine(), bitmap,1,rect);
+ if((state->m_spritereg[0x404] & 0x0008))
+ {
+ if((state->m_spritereg[0x404] & 0x0030) == 0x10) // BG1 TXSEL
+ {
+ x68k_bg0->set_scrollx(0,(state->m_spritereg[0x402] - state->m_crtc.hbegin - state->m_crtc.bg_hshift) & 0x3ff);
+ x68k_bg0->set_scrolly(0,(state->m_spritereg[0x403] - state->m_crtc.vbegin) & 0x3ff);
+ x68k_bg0->draw(bitmap,rect,0,0);
+ }
+ else
+ {
+ x68k_bg1->set_scrollx(0,(state->m_spritereg[0x402] - state->m_crtc.hbegin - state->m_crtc.bg_hshift) & 0x3ff);
+ x68k_bg1->set_scrolly(0,(state->m_spritereg[0x403] - state->m_crtc.vbegin) & 0x3ff);
+ x68k_bg1->draw(bitmap,rect,0,0);
+ }
+ }
+ x68k_draw_sprites(screen.machine(),bitmap,2,rect);
+ if((state->m_spritereg[0x404] & 0x0001))
+ {
+ if((state->m_spritereg[0x404] & 0x0006) == 0x02) // BG0 TXSEL
+ {
+ x68k_bg0->set_scrollx(0,(state->m_spritereg[0x400] - state->m_crtc.hbegin - state->m_crtc.bg_hshift) & 0x3ff);
+ x68k_bg0->set_scrolly(0,(state->m_spritereg[0x401] - state->m_crtc.vbegin) & 0x3ff);
+ x68k_bg0->draw(bitmap,rect,0,0);
+ }
+ else
+ {
+ x68k_bg1->set_scrollx(0,(state->m_spritereg[0x400] - state->m_crtc.hbegin - state->m_crtc.bg_hshift) & 0x3ff);
+ x68k_bg1->set_scrolly(0,(state->m_spritereg[0x401] - state->m_crtc.vbegin) & 0x3ff);
+ x68k_bg1->draw(bitmap,rect,0,0);
+ }
+ }
+ x68k_draw_sprites(screen.machine(),bitmap,3,rect);
+ }
+
+ // Text screen
+ if(state->m_video.reg[2] & 0x0020 && priority == state->m_video.text_pri)
+ {
+ xscr = (state->m_crtc.reg[10] & 0x3ff);
+ yscr = (state->m_crtc.reg[11] & 0x3ff);
+ if(!(state->m_crtc.reg[20] & 0x1000)) // if text layer is set to buffer, then it's not visible
+ x68k_draw_text(screen.machine(),bitmap,xscr,yscr,rect);
+ }
+ }
+
+#ifdef MAME_DEBUG
+ if(screen.machine().input().code_pressed(KEYCODE_I))
+ {
+ state->m_mfp.isra = 0;
+ state->m_mfp.isrb = 0;
+// mfp_trigger_irq(MFP_IRQ_GPIP6);
+// cputag_set_input_line_and_vector(machine, "maincpu",6,ASSERT_LINE,0x43);
+ }
+ if(screen.machine().input().code_pressed(KEYCODE_9))
+ {
+ state->m_sprite_shift--;
+ popmessage("Sprite shift = %i",state->m_sprite_shift);
+ }
+ if(screen.machine().input().code_pressed(KEYCODE_0))
+ {
+ state->m_sprite_shift++;
+ popmessage("Sprite shift = %i",state->m_sprite_shift);
+ }
+
+#endif
+
+#ifdef MAME_DEBUG
+// popmessage("Layer priorities [%04x] - Txt: %i Spr: %i Gfx: %i Layer Pri0-3: %i %i %i %i",state->m_video.reg[1],state->m_video.text_pri,state->m_video.sprite_pri,
+// state->m_video.gfx_pri,state->m_video.gfxlayer_pri[0],state->m_video.gfxlayer_pri[1],state->m_video.gfxlayer_pri[2],state->m_video.gfxlayer_pri[3]);
+// popmessage("CRTC regs - %i %i %i %i - %i %i %i %i - %i - %i",state->m_crtc.reg[0],state->m_crtc.reg[1],state->m_crtc.reg[2],state->m_crtc.reg[3],
+// state->m_crtc.reg[4],state->m_crtc.reg[5],state->m_crtc.reg[6],state->m_crtc.reg[7],state->m_crtc.reg[8],state->m_crtc.reg[9]);
+// popmessage("Visible resolution = %ix%i (%s) Screen size = %ix%i",state->m_crtc.visible_width,state->m_crtc.visible_height,state->m_crtc.interlace ? "Interlaced" : "Non-interlaced",state->m_crtc.video_width,state->m_crtc.video_height);
+// popmessage("VBlank : scanline = %i",state->m_scanline);
+// popmessage("CRTC/BG compare H-TOTAL %i/%i H-DISP %i/%i V-DISP %i/%i BG Res %02x",state->m_crtc.reg[0],state->m_spritereg[0x405],state->m_crtc.reg[2],state->m_spritereg[0x406],
+// state->m_crtc.reg[6],state->m_spritereg[0x407],state->m_spritereg[0x408]);
+// popmessage("IER %02x %02x IPR %02x %02x ISR %02x %02x IMR %02x %02x", state->m_mfp.iera,state->m_mfp.ierb,state->m_mfp.ipra,state->m_mfp.iprb,
+// state->m_mfp.isra,state->m_mfp.isrb,state->m_mfp.imra,state->m_mfp.imrb);
+// popmessage("BG Scroll - BG0 X %i Y %i BG1 X %i Y %i",state->m_spriteram[0x400],state->m_spriteram[0x401],state->m_spriteram[0x402],state->m_spriteram[0x403]);
+// popmessage("Keyboard buffer position = %i",state->m_keyboard.headpos);
+// popmessage("IERA = 0x%02x, IERB = 0x%02x",state->m_mfp.iera,state->m_mfp.ierb);
+// popmessage("IPRA = 0x%02x, IPRB = 0x%02x",state->m_mfp.ipra,state->m_mfp.iprb);
+// popmessage("uPD72065 status = %02x",upd765_status_r(machine, 0));
+// popmessage("Layer enable - 0x%02x",state->m_video.reg[2] & 0xff);
+// popmessage("Graphic layer scroll - %i, %i - %i, %i - %i, %i - %i, %i",
+// state->m_crtc.reg[12],state->m_crtc.reg[13],state->m_crtc.reg[14],state->m_crtc.reg[15],state->m_crtc.reg[16],state->m_crtc.reg[17],state->m_crtc.reg[18],state->m_crtc.reg[19]);
+// popmessage("IOC IRQ status - %02x",state->m_ioc.irqstatus);
+// popmessage("RAM: mouse data - %02x %02x %02x %02x",machine.device<ram_device>(RAM_TAG)->pointer()[0x931],machine.device<ram_device>(RAM_TAG)->pointer()[0x930],machine.device<ram_device>(RAM_TAG)->pointer()[0x933],machine.device<ram_device>(RAM_TAG)->pointer()[0x932]);
+#endif
+ return 0;
+}
diff --git a/src/mess/video/z88.c b/src/mess/video/z88.c
new file mode 100644
index 00000000000..bb9548455e8
--- /dev/null
+++ b/src/mess/video/z88.c
@@ -0,0 +1,173 @@
+/***************************************************************************
+
+ z88.c
+
+ Functions to emulate the video hardware of the Cambridge Z88
+
+***************************************************************************/
+
+#include "includes/z88.h"
+
+
+inline void z88_state::plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT16 color)
+{
+ if (x<Z88_SCREEN_WIDTH)
+ bitmap.pix16(y, x) = color;
+}
+
+// convert absolute offset into correct address to get data from
+inline UINT8* z88_state::convert_address(UINT32 offset)
+{
+ return (offset < 0x80000 ? m_bios : m_ram_base) + (offset & 0x7ffff);
+}
+
+/***************************************************************************
+ Start the video hardware emulation.
+***************************************************************************/
+
+// Initialise the palette
+PALETTE_INIT( z88 )
+{
+ palette_set_color(machine, 0, MAKE_RGB(138, 146, 148));
+ palette_set_color(machine, 1, MAKE_RGB(92, 83, 88));
+ palette_set_color(machine, 2, MAKE_RGB(122, 126, 129));
+}
+
+/* temp - change to gfxelement structure */
+
+void z88_state::vh_render_8x8(bitmap_ind16 &bitmap, int x, int y, UINT16 pen0, UINT16 pen1, UINT8 *gfx)
+{
+ for (int h=0; h<8; h++)
+ {
+ UINT8 data = gfx[h];
+
+ for (int b=0; b<8; b++)
+ {
+ plot_pixel(bitmap, x+b, y+h, (data & 0x80) ? pen1 : pen0);
+
+ data = data<<1;
+ }
+ }
+}
+
+void z88_state::vh_render_6x8(bitmap_ind16 &bitmap, int x, int y, UINT16 pen0, UINT16 pen1, UINT8 *gfx)
+{
+ for (int h=0; h<8; h++)
+ {
+ UINT8 data = gfx[h]<<2;
+
+ for (int b=0; b<6; b++)
+ {
+ plot_pixel(bitmap, x+1+b, y+h, (data & 0x80) ? pen1 : pen0);
+ data = data<<1;
+ }
+ }
+}
+
+void z88_state::vh_render_line(bitmap_ind16 &bitmap, int x, int y, UINT16 pen)
+{
+ for (int i=0; i<8; i++)
+ plot_pixel(bitmap, x + i, y + 7, pen);
+}
+
+void z88_state::lcd_update(bitmap_ind16 &bitmap, UINT16 sbf, UINT16 hires0, UINT16 hires1, UINT16 lores0, UINT16 lores1, int flash)
+{
+ if (sbf == 0)
+ {
+ // LCD disabled
+ bitmap.fill(0);
+ }
+ else
+ {
+ UINT8 *vram = convert_address(sbf<<11);
+
+ for (int y=0; y<(Z88_SCREEN_HEIGHT>>3); y++)
+ {
+ int x = 0, c = 0;
+
+ while (x < Z88_SCREEN_WIDTH)
+ {
+ UINT16 pen0, pen1;
+ UINT8 *char_gfx;
+ UINT8 byte0 = vram[(y * 0x100) + c];
+ UINT8 byte1 = vram[(y * 0x100) + c + 1];
+
+ // inverted graphics?
+ if (byte1 & Z88_SCR_HW_REV)
+ {
+ pen0 = (byte1 & Z88_SCR_HW_GRY) ? 2 : 1;
+ pen1 = 0;
+ }
+ else
+ {
+ pen0 = 0;
+ pen1 = (byte1 & Z88_SCR_HW_GRY) ? 2 : 1;
+ }
+
+ if ((byte1 & Z88_SCR_HW_NULL) == Z88_SCR_HW_NULL)
+ {
+ // hidden
+ }
+ else if (!(byte1 & Z88_SCR_HW_HRS) || (((byte1 & Z88_SCR_HW_CURS) == Z88_SCR_HW_CURS)))
+ {
+ // low-res 6x8
+ UINT16 ch = (byte0 | (byte1<<8)) & 0x1ff;
+
+ if ((ch & 0x01c0) == 0x01c0)
+ {
+ ch &= 0x3f;
+
+ char_gfx = convert_address(lores0<<9);
+ }
+ else
+ {
+ char_gfx = convert_address(lores1<<12);
+ }
+
+ char_gfx += (ch<<3);
+
+ // cursor flash
+ if (flash && (byte1 & Z88_SCR_HW_CURS) == Z88_SCR_HW_CURS)
+ vh_render_6x8(bitmap, x,(y<<3), pen1, pen0, char_gfx);
+ else
+ vh_render_6x8(bitmap, x,(y<<3), pen0, pen1, char_gfx);
+
+ // underline?
+ if (byte1 & Z88_SCR_HW_UND)
+ vh_render_line(bitmap, x, (y<<3), pen1);
+
+ x += 6;
+ }
+ else if ((byte1 & Z88_SCR_HW_HRS) && !(byte1 & Z88_SCR_HW_REV))
+ {
+ // high-res 8x8
+ UINT16 ch = (byte0 | (byte1<<8)) & 0x3ff;
+
+ if (ch & 0x0100)
+ {
+ ch &= 0xff;
+ char_gfx = convert_address(hires1<<11);
+ }
+ else
+ {
+ ch &= 0xff;
+ char_gfx = convert_address(hires0<<13);
+ }
+
+ char_gfx += (ch<<3);
+
+ // flash
+ if ((byte1 & Z88_SCR_HW_FLS) && flash)
+ pen0 = pen1 = 0;
+
+ vh_render_8x8(bitmap, x,(y<<3), pen0, pen1, char_gfx);
+
+ x += 8;
+ }
+
+ // every char takes 2 bytes
+ c += 2;
+ }
+ }
+ }
+}
diff --git a/src/mess/video/zx.c b/src/mess/video/zx.c
new file mode 100644
index 00000000000..8edb75ba4f2
--- /dev/null
+++ b/src/mess/video/zx.c
@@ -0,0 +1,217 @@
+/***************************************************************************
+ zx.c
+
+ video hardware
+ Juergen Buchmueller <pullmoll@t-online.de>, Dec 1999
+
+ The ZX has a very unorthodox video RAM system. To start a scanline,
+ the CPU must jump to video RAM at 0xC000, which is a mirror of the
+ RAM at 0x4000. The video chip (ULA?) pulls a switcharoo and changes
+ the video bytes as they are fetched by the CPU.
+
+ The video chip draws the scanline until a HALT instruction (0x76) is
+ reached, which indicates no further video RAM for this scanline. Any
+ other video byte is used to generate a tile and at the same time,
+ appears to the CPU as a NOP (0x00) instruction.
+
+****************************************************************************/
+
+#include "includes/zx.h"
+
+emu_timer *ula_nmi = NULL;
+//emu_timer *ula_irq = NULL;
+//int ula_nmi_active;
+int ula_frame_vsync = 0;
+//int ula_scancode_count = 0;
+int ula_scanline_count = 0;
+
+/*
+ * Toggle the video output between black and white.
+ * This happens whenever the ULA scanline IRQs are enabled/disabled.
+ * Normally this is done during the synchronized zx_ula_r() function,
+ * which outputs 8 pixels per code, but if the video sync is off
+ * (during tape IO or sound output) zx_ula_bkgnd() is used to
+ * simulate the display of a ZX80/ZX81.
+ */
+void zx_state::zx_ula_bkgnd(UINT8 color)
+{
+ screen_device *screen = machine().first_screen();
+ int width = screen->width();
+ int height = screen->height();
+ const rectangle &visarea = screen->visible_area();
+
+ if (m_ula_frame_vsync == 0 && color != m_old_c)
+ {
+ int y, new_x, new_y;
+ rectangle r;
+ bitmap_ind16 &bitmap = m_bitmap;
+
+ new_y = machine().primary_screen->vpos();
+ new_x = machine().primary_screen->hpos();
+/* logerror("zx_ula_bkgnd: %3d,%3d - %3d,%3d\n", state->m_old_x, state->m_old_y, new_x, new_y);*/
+ y = m_old_y;
+ for (;;)
+ {
+ if (y == new_y)
+ {
+ r.set(m_old_x, new_x, y, y);
+ bitmap.fill(color, r);
+ break;
+ }
+ else
+ {
+ r.set(m_old_x, visarea.max_x, y, y);
+ bitmap.fill(color, r);
+ m_old_x = 0;
+ }
+ if (++y == height)
+ y = 0;
+ }
+ m_old_x = (new_x + 1) % width;
+ m_old_y = new_y;
+ m_old_c = color;
+ }
+}
+
+/*
+ * PAL: 310 total lines,
+ * 0.. 55 vblank
+ * 56..247 192 visible lines
+ * 248..303 vblank
+ * 304... vsync
+ * NTSC: 262 total lines
+ * 0.. 31 vblank
+ * 32..223 192 visible lines
+ * 224..233 vblank
+ */
+static TIMER_CALLBACK(zx_ula_nmi)
+{
+ zx_state *state = machine.driver_data<zx_state>();
+ /*
+ * An NMI is issued on the ZX81 every 64us for the blanked
+ * scanlines at the top and bottom of the display.
+ */
+ screen_device *screen = machine.first_screen();
+ int height = screen->height();
+ const rectangle& r1 = screen->visible_area();
+ rectangle r;
+
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ r.set(r1.min_x, r1.max_x, state->m_ula_scanline_count, state->m_ula_scanline_count);
+ bitmap.fill(1, r);
+// logerror("ULA %3d[%d] NMI, R:$%02X, $%04x\n", machine.primary_screen->vpos(), ula_scancode_count, (unsigned) cpu_get_reg(machine.device("maincpu"), Z80_R), (unsigned) cpu_get_reg(machine.device("maincpu"), Z80_PC));
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, PULSE_LINE);
+ if (++state->m_ula_scanline_count == height)
+ state->m_ula_scanline_count = 0;
+}
+
+static TIMER_CALLBACK(zx_ula_irq)
+{
+ zx_state *state = machine.driver_data<zx_state>();
+
+ /*
+ * An IRQ is issued on the ZX80/81 whenever the R registers
+ * bit 6 goes low. In MESS this IRQ timed from the first read
+ * from the copy of the DFILE in the upper 32K in zx_ula_r().
+ */
+ if (state->m_ula_irq_active)
+ {
+// logerror("ULA %3d[%d] IRQ, R:$%02X, $%04x\n", machine.primary_screen->vpos(), ula_scancode_count, (unsigned) cpu_get_reg(machine.device("maincpu"), Z80_R), (unsigned) cpu_get_reg(machine.device("maincpu"), Z80_PC));
+
+ state->m_ula_irq_active = 0;
+ cputag_set_input_line(machine, "maincpu", 0, HOLD_LINE);
+ }
+}
+
+void zx_ula_r(running_machine &machine, int offs, const char *region, const UINT8 param)
+{
+ zx_state *state = machine.driver_data<zx_state>();
+ screen_device *screen = machine.first_screen();
+ int offs0 = offs & 0x7fff;
+ UINT8 *rom = machine.root_device().memregion("maincpu")->base();
+ UINT8 chr = rom[offs0];
+
+ if ((!state->m_ula_irq_active) && (chr == 0x76))
+ {
+ bitmap_ind16 &bitmap = state->m_bitmap;
+ UINT16 y, *scanline;
+ UINT16 ireg = cpu_get_reg(machine.device("maincpu"), Z80_I) << 8;
+ UINT8 data, *chrgen, creg;
+
+ if (param)
+ creg = cpu_get_reg(machine.device("maincpu"), Z80_B);
+ else
+ creg = cpu_get_reg(machine.device("maincpu"), Z80_C);
+
+ chrgen = state->memregion(region)->base();
+
+ if ((++state->m_ula_scanline_count == screen->height()) || (creg == 32))
+ {
+ state->m_ula_scanline_count = 0;
+ state->m_offs1 = offs0;
+ }
+
+ state->m_ula_frame_vsync = 3;
+
+ state->m_charline_ptr = 0;
+
+ for (y = state->m_offs1+1; ((y < offs0) && (state->m_charline_ptr < ARRAY_LENGTH(state->m_charline))); y++)
+ {
+ state->m_charline[state->m_charline_ptr] = rom[y];
+ state->m_charline_ptr++;
+ }
+ for (y = state->m_charline_ptr; y < ARRAY_LENGTH(state->m_charline); y++)
+ state->m_charline[y] = 0;
+
+ machine.scheduler().timer_set(machine.device<cpu_device>("maincpu")->cycles_to_attotime(((32 - state->m_charline_ptr) << 2)), FUNC(zx_ula_irq));
+ state->m_ula_irq_active++;
+
+ scanline = &bitmap.pix16(state->m_ula_scanline_count);
+ y = 0;
+
+ for (state->m_charline_ptr = 0; state->m_charline_ptr < ARRAY_LENGTH(state->m_charline); state->m_charline_ptr++)
+ {
+ chr = state->m_charline[state->m_charline_ptr];
+ data = chrgen[ireg | ((chr & 0x3f) << 3) | ((8 - creg)&7) ];
+ if (chr & 0x80) data ^= 0xff;
+
+ scanline[y++] = (data >> 7) & 1;
+ scanline[y++] = (data >> 6) & 1;
+ scanline[y++] = (data >> 5) & 1;
+ scanline[y++] = (data >> 4) & 1;
+ scanline[y++] = (data >> 3) & 1;
+ scanline[y++] = (data >> 2) & 1;
+ scanline[y++] = (data >> 1) & 1;
+ scanline[y++] = (data >> 0) & 1;
+ state->m_charline[state->m_charline_ptr] = 0;
+ }
+
+ if (creg == 1) state->m_offs1 = offs0;
+ }
+}
+
+VIDEO_START( zx )
+{
+ zx_state *state = machine.driver_data<zx_state>();
+ state->m_ula_nmi = machine.scheduler().timer_alloc(FUNC(zx_ula_nmi));
+ state->m_ula_irq_active = 0;
+ machine.primary_screen->register_screen_bitmap(state->m_bitmap);
+}
+
+SCREEN_VBLANK( zx )
+{
+ // rising edge
+ if (vblank_on)
+ {
+ zx_state *state = screen.machine().driver_data<zx_state>();
+ /* decrement video synchronization counter */
+ if (state->m_ula_frame_vsync)
+ --state->m_ula_frame_vsync;
+ }
+}
+
+UINT32 zx_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
diff --git a/src/mess/video/zx8301.c b/src/mess/video/zx8301.c
new file mode 100644
index 00000000000..0223080b802
--- /dev/null
+++ b/src/mess/video/zx8301.c
@@ -0,0 +1,346 @@
+/**********************************************************************
+
+ Sinclair ZX8301 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - wait state on memory access during video update
+ - proper video timing
+ - get rid of flash timer
+
+*/
+
+#include "emu.h"
+#include "zx8301.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+// low resolution palette
+static const int ZX8301_COLOR_MODE4[] = { 0, 2, 4, 7 };
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type ZX8301 = &device_creator<zx8301_device>;
+
+
+// default address map
+static ADDRESS_MAP_START( zx8301, AS_0, 8, zx8301_device )
+ AM_RANGE(0x00000, 0x1ffff) AM_RAM
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *zx8301_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void zx8301_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const zx8301_interface *intf = reinterpret_cast<const zx8301_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<zx8301_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&out_vsync_cb, 0, sizeof(out_vsync_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 zx8301_device::readbyte(offs_t address)
+{
+ return space()->read_byte(address);
+}
+
+
+//-------------------------------------------------
+// writebyte - write a byte at the given address
+//-------------------------------------------------
+
+inline void zx8301_device::writebyte(offs_t address, UINT8 data)
+{
+ space()->write_byte(address, data);
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// zx8301_device - constructor
+//-------------------------------------------------
+
+zx8301_device::zx8301_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ZX8301, "Sinclair ZX8301", tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(zx8301)),
+ m_dispoff(1),
+ m_mode8(0),
+ m_base(0),
+ m_flash(1),
+ m_vsync(1),
+ m_vda(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void zx8301_device::device_start()
+{
+ // get the CPU
+ m_cpu = machine().device<cpu_device>(cpu_tag);
+ assert(m_cpu != NULL);
+
+ // get the screen device
+ m_screen = machine().device<screen_device>(screen_tag);
+ assert(m_screen != NULL);
+
+ // resolve callbacks
+ m_out_vsync_func.resolve(out_vsync_cb, *this);
+
+ // allocate timers
+ m_vsync_timer = timer_alloc(TIMER_VSYNC);
+ m_flash_timer = timer_alloc(TIMER_FLASH);
+
+ // adjust timer periods
+ m_vsync_timer->adjust(attotime::zero, 0, attotime::from_hz(50));
+ m_flash_timer->adjust(attotime::from_hz(2), 0, attotime::from_hz(2));
+
+ // register for state saving
+ save_item(NAME(m_dispoff));
+ save_item(NAME(m_mode8));
+ save_item(NAME(m_base));
+ save_item(NAME(m_flash));
+ save_item(NAME(m_vsync));
+ save_item(NAME(m_vda));
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void zx8301_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_VSYNC:
+ //m_vsync = !m_vsync;
+ m_out_vsync_func(m_vsync);
+ break;
+
+ case TIMER_FLASH:
+ m_flash = !m_flash;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// control_w - display control register
+//-------------------------------------------------
+
+WRITE8_MEMBER( zx8301_device::control_w )
+{
+ /*
+
+ bit description
+
+ 0
+ 1 display off
+ 2
+ 3 graphics mode
+ 4
+ 5
+ 6
+ 7 display base address
+
+ */
+
+ if (LOG) logerror("ZX8301 Control: %02x\n", data);
+
+ // display off
+ m_dispoff = BIT(data, 1);
+
+ // graphics mode
+ m_mode8 = BIT(data, 3);
+
+ // display base address
+ m_base = BIT(data, 7);
+}
+
+
+//-------------------------------------------------
+// data_r - RAM read
+//-------------------------------------------------
+
+READ8_MEMBER( zx8301_device::data_r )
+{
+ if (LOG) logerror("ZX8301 RAM Read: %06x\n", offset);
+
+ if (m_vda)
+ {
+ device_spin_until_time(m_cpu, m_screen->time_until_pos(256, 0));
+ }
+
+ return readbyte(offset);
+}
+
+
+//-------------------------------------------------
+// data_w - RAM write
+//-------------------------------------------------
+
+WRITE8_MEMBER( zx8301_device::data_w )
+{
+ if (LOG) logerror("ZX8301 RAM Write: %06x = %02x\n", offset, data);
+
+ if (m_vda)
+ {
+ device_spin_until_time(m_cpu, m_screen->time_until_pos(256, 0));
+ }
+
+ writebyte(offset, data);
+}
+
+
+//-------------------------------------------------
+// draw_line_mode4 - draw mode 4 line
+//-------------------------------------------------
+
+void zx8301_device::draw_line_mode4(bitmap_ind16 &bitmap, int y, UINT16 da)
+{
+ int x = 0;
+
+ for (int word = 0; word < 64; word++)
+ {
+ UINT8 byte_high = readbyte(da++);
+ UINT8 byte_low = readbyte(da++);
+
+ for (int pixel = 0; pixel < 8; pixel++)
+ {
+ int red = BIT(byte_low, 7);
+ int green = BIT(byte_high, 7);
+ int color = (green << 1) | red;
+
+ bitmap.pix16(y, x++) = ZX8301_COLOR_MODE4[color];
+
+ byte_high <<= 1;
+ byte_low <<= 1;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// draw_line_mode8 - draw mode 8 line
+//-------------------------------------------------
+
+void zx8301_device::draw_line_mode8(bitmap_ind16 &bitmap, int y, UINT16 da)
+{
+ int x = 0;
+
+ for (int word = 0; word < 64; word++)
+ {
+ UINT8 byte_high = readbyte(da++);
+ UINT8 byte_low = readbyte(da++);
+
+ for (int pixel = 0; pixel < 4; pixel++)
+ {
+ int red = BIT(byte_low, 7);
+ int green = BIT(byte_high, 7);
+ int blue = BIT(byte_low, 6);
+ int flash = BIT(byte_high, 6);
+
+ int color = (green << 2) | (red << 1) | blue;
+
+ if (flash && m_flash)
+ {
+ color = 0;
+ }
+
+ bitmap.pix16(y, x++) = color;
+ bitmap.pix16(y, x++) = color;
+
+ byte_high <<= 2;
+ byte_low <<= 2;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// update_screen -
+//-------------------------------------------------
+
+void zx8301_device::update_screen(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ if (!m_dispoff)
+ {
+ UINT32 da = m_base << 15;
+
+ for (int y = 0; y < 256; y++)
+ {
+ if (m_mode8)
+ {
+ draw_line_mode8(bitmap, y, da);
+ }
+ else
+ {
+ draw_line_mode4(bitmap, y, da);
+ }
+
+ da += 128;
+ }
+ }
+ else
+ {
+ bitmap.fill(get_black_pen(machine()), cliprect);
+ }
+}
diff --git a/src/mess/video/zx8301.h b/src/mess/video/zx8301.h
new file mode 100644
index 00000000000..52be5bf8730
--- /dev/null
+++ b/src/mess/video/zx8301.h
@@ -0,0 +1,138 @@
+/**********************************************************************
+
+ Sinclair ZX8301 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ DTACKL 1 |* \_/ | 40 WEL
+ A17 2 | | 39 PCENL
+ A16 3 | | 38 VDA
+ RDWL 4 | | 37 ROWL
+ DSMCL 5 | | 36 TX0EL
+ VCC 6 | | 35 XTAL2
+ CLKCPU 7 | | 34 XTAL1
+ RASL 8 | | 33 ROM0EH
+ CAS0L 9 | | 32 BLUE
+ CAS1L 10 | ZX8301 | 31 GREEN
+ VSYNCH 11 | ULA | 30 RED
+ CSYNCL 12 | | 29 DB7
+ DA0 13 | | 28 DA7
+ DB0 14 | | 27 DA6
+ VDD 15 | | 26 DB6
+ DB1 16 | | 25 DB5
+ DA1 17 | | 24 DA5
+ DA2 18 | | 23 DB4
+ DB2 19 | | 22 DA4
+ DA3 20 |_____________| 21 DB3
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ZX8301__
+#define __ZX8301__
+
+#include "emu.h"
+
+
+
+///*************************************************************************
+// MACROS / CONSTANTS
+///*************************************************************************
+
+
+
+
+///*************************************************************************
+// INTERFACE CONFIGURATION MACROS
+///*************************************************************************
+
+#define MCFG_ZX8301_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, ZX8301, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define ZX8301_INTERFACE(name) \
+ const zx8301_interface(name) =
+
+
+
+///*************************************************************************
+// TYPE DEFINITIONS
+///*************************************************************************
+
+// ======================> zx8301_interface
+
+struct zx8301_interface
+{
+ const char *cpu_tag;
+ const char *screen_tag;
+
+ devcb_write_line out_vsync_cb;
+};
+
+
+// ======================> zx8301_device
+
+class zx8301_device : public device_t,
+ public device_memory_interface,
+ public zx8301_interface
+{
+public:
+ // construction/destruction
+ zx8301_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_WRITE8_MEMBER( control_w );
+ DECLARE_READ8_MEMBER( data_r );
+ DECLARE_WRITE8_MEMBER( data_w );
+
+ void update_screen(bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_config_complete();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+
+ inline UINT8 readbyte(offs_t address);
+ inline void writebyte(offs_t address, UINT8 data);
+
+ void draw_line_mode4(bitmap_ind16 &bitmap, int y, UINT16 da);
+ void draw_line_mode8(bitmap_ind16 &bitmap, int y, UINT16 da);
+
+private:
+ static const device_timer_id TIMER_VSYNC = 0;
+ static const device_timer_id TIMER_FLASH = 1;
+
+ devcb_resolved_write_line m_out_vsync_func;
+
+ cpu_device *m_cpu;
+ screen_device *m_screen;
+ address_space *m_data;
+
+ int m_dispoff; // display off
+ int m_mode8; // mode8 active
+ int m_base; // video ram base address
+ int m_flash; // flash
+ int m_vsync; // vertical sync
+ int m_vda; // valid data address
+
+ emu_timer *m_vsync_timer; // vertical sync timer
+ emu_timer *m_flash_timer; // flash timer
+};
+
+
+// device type definition
+extern const device_type ZX8301;
+
+
+
+#endif