1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /*
4 
5     TODO:
6 
7     - GR is always 0
8 
9 */
10 
11 #include "emu.h"
12 #include "includes/newbrain.h"
13 #include "rendlay.h"
14 #include "screen.h"
15 
16 #define VERBOSE 0
17 #include "logmacro.h"
18 
19 #define NEWBRAIN_VIDEO_RV               0x01
20 #define NEWBRAIN_VIDEO_FS               0x02
21 #define NEWBRAIN_VIDEO_32_40            0x04
22 #define NEWBRAIN_VIDEO_UCR              0x08
23 #define NEWBRAIN_VIDEO_80L              0x40
24 
tvl(uint8_t data,int a6)25 void newbrain_state::tvl(uint8_t data, int a6)
26 {
27 	/* latch video address counter bits A5-A0 */
28 	m_tvl = m_80l ? 0x04 : 0x02;
29 
30 	/* latch video address counter bit A6 */
31 	m_tvl |= a6 << 6;
32 
33 	/* latch data to video address counter bits A14-A7 */
34 	m_tvl |= (data << 7);
35 
36 	LOG("%s %s TVL %04x\n", machine().time().as_string(), machine().describe_context(), m_tvl);
37 }
38 
tvtl_w(uint8_t data)39 void newbrain_state::tvtl_w(uint8_t data)
40 {
41 	/*
42 
43 	    bit     signal      description
44 
45 	    0       RV          1 reverses video over entire field, ie. black on white
46 	    1       FS          0 generates 128 characters and 128 reverse field characters from 8 bit character code. 1 generates 256 characters from 8 bit character code
47 	    2       32/_40      0 generates 320 or 640 horizontal dots in pixel graphics mode. 1 generates 256 or 512 horizontal dots in pixel graphics mode
48 	    3       UCR         0 selects 256 characters expressed in an 8x10 matrix, and 25 lines (max) displayed. 1 selects 256 characters in an 8x8 matrix, and 31 lines (max) displayed
49 	    4
50 	    5
51 	    6       80L         0 selects 40 character line length. 1 selects 80 character line length
52 	    7
53 
54 	*/
55 
56 	LOG("%s %s TVTL %02x\n", machine().time().as_string(), machine().describe_context(), data);
57 
58 	m_rv = BIT(data, 0);
59 	m_fs = BIT(data, 1);
60 	m_32_40 = BIT(data, 2);
61 	m_ucr = BIT(data, 3);
62 	m_80l = BIT(data, 6);
63 }
64 
video_start()65 void newbrain_state::video_start()
66 {
67 	// set timer
68 	m_clkint_timer = timer_alloc(TIMER_ID_CLKINT);
69 	m_clkint_timer->adjust(attotime::zero, 0, attotime::from_hz(50));
70 
71 	// state saving
72 	save_item(NAME(m_rv));
73 	save_item(NAME(m_fs));
74 	save_item(NAME(m_32_40));
75 	save_item(NAME(m_ucr));
76 	save_item(NAME(m_80l));
77 	save_item(NAME(m_tvl));
78 }
79 
do_screen_update(bitmap_rgb32 & bitmap,const rectangle & cliprect)80 void newbrain_state::do_screen_update(bitmap_rgb32 &bitmap, const rectangle &cliprect)
81 {
82 	int columns = m_80l ? 80 : 40;
83 	int excess = m_32_40 ? 4 : 24;
84 	int gr = 0;
85 
86 	uint16_t videoram_addr = m_tvl;
87 	int rc = 0;
88 	uint8_t vsr = 0;
89 	uint8_t grsr = 0;
90 
91 	for (int y = 0; y < 240; y++) {
92 		int x = 0;
93 
94 		for (int sx = 0; sx < columns; sx++) {
95 			uint8_t rd = m_ram->pointer()[(videoram_addr + sx) & 0x7fff];
96 
97 			bool rc3 = BIT(rc, 3);
98 			bool txt = !(BIT(rd, 6) || BIT(rd, 5));
99 			bool txtq = m_ucr || txt;
100 
101 			int rc_ = rc & 0x07;
102 			if (rc3 && txt) {
103 				rc_ = 7;
104 			}
105 
106 			uint16_t charrom_addr = (m_ucr << 11) | (rc_ << 8) | ((BIT(rd, 7) && m_fs) << 7) | (rd & 0x7f);
107 			uint8_t crd = m_char_rom->base()[charrom_addr & 0xfff];
108 			bool crd0 = BIT(crd, 0);
109 
110 			bool ldvsr = !(((!rc3 ^ crd0) || gr) || txtq);
111 
112 			if (!ldvsr && !gr) {
113 				vsr = (crd & 0xfe) | (crd0 && txtq);
114 			}
115 
116 			if (!ldvsr && gr) {
117 				grsr = rd;
118 			}
119 
120 			for (int i = 0; i < 8; i++) {
121 				uint8_t sr = gr ? grsr : vsr;
122 				int color = BIT(sr, 7) ^ m_rv;
123 
124 				bitmap.pix(y, x++) = m_palette->pen(color);
125 
126 				if (columns == 40) {
127 					bitmap.pix(y, x++) = m_palette->pen(color);
128 				}
129 
130 				grsr <<= 1;
131 				vsr <<= 1;
132 			}
133 		}
134 
135 		if (gr)
136 		{
137 			// get new data for each line
138 			videoram_addr += columns;
139 			videoram_addr += excess;
140 		}
141 		else
142 		{
143 			rc++;
144 
145 			if (rc == (m_ucr ? 8 : 10)) {
146 				rc = 0;
147 
148 				// get new data after each character row
149 				videoram_addr += columns;
150 				videoram_addr += excess;
151 			}
152 		}
153 	}
154 }
155 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)156 uint32_t newbrain_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
157 {
158 	if (m_tvp)
159 		do_screen_update(bitmap, cliprect);
160 	else
161 		bitmap.fill(rgb_t::black(), cliprect);
162 
163 	return 0;
164 }
165 
166 /* F4 Character Displayer */
167 static const gfx_layout newbrain_charlayout =
168 {
169 	8, 10,                  /* 8 x 10 characters */
170 	256,                    /* 256 characters */
171 	1,                  /* 1 bits per pixel */
172 	{ 0 },                  /* no bitplanes */
173 	/* x offsets */
174 	{ 0, 1, 2, 3, 4, 5, 6, 7 },
175 	/* y offsets */
176 	{ 0*256*8, 1*256*8, 2*256*8, 3*256*8, 4*256*8, 5*256*8, 6*256*8, 7*256*8, 8*256*8, 9*256*8, 10*256*8, 11*256*8, 12*256*8, 13*256*8, 14*256*8, 15*256*8 },
177 	8                   /* every char takes 16 x 1 bytes */
178 };
179 
180 static GFXDECODE_START( gfx_newbrain )
181 	GFXDECODE_ENTRY( "chargen", 0x0000, newbrain_charlayout, 0, 1 )
182 GFXDECODE_END
183 
184 /* Machine Drivers */
185 
newbrain_video(machine_config & config)186 void newbrain_state::newbrain_video(machine_config &config)
187 {
188 	screen_device &screen(SCREEN(config, SCREEN_TAG, SCREEN_TYPE_RASTER, rgb_t::green()));
189 	screen.set_screen_update(FUNC(newbrain_state::screen_update));
190 	screen.set_refresh_hz(50);
191 	screen.set_size(640, 250);
192 	screen.set_visarea(0, 639, 0, 249);
193 
194 	PALETTE(config, m_palette, palette_device::MONOCHROME);
195 
196 	GFXDECODE(config, "gfxdecode", m_palette, gfx_newbrain);
197 }
198