1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /**********************************************************************
4 
5     MOS 7360/8360 Text Edit Device (TED) emulation
6 
7 **********************************************************************/
8 
9 #include "emu.h"
10 #include "mos7360.h"
11 
12 #include "screen.h"
13 
14 
15 
16 //**************************************************************************
17 //  MACROS / CONSTANTS
18 //**************************************************************************
19 
20 #define VERBOSE_LEVEL 0
21 #define DBG_LOG(N,M,A) \
22 	do { \
23 		if(VERBOSE_LEVEL >= N) \
24 		{ \
25 			if( M ) \
26 				logerror("%11.6f: %-24s", machine().time().as_double(), (char*) M ); \
27 			logerror A; \
28 		} \
29 	} while(0)
30 
31 
32 #define VREFRESHINLINES 28
33 
34 #define TIMER1HELPER (m_reg[0] | (m_reg[1] << 8))
35 #define TIMER2HELPER (m_reg[2] | (m_reg[3] << 8))
36 #define TIMER3HELPER (m_reg[4] | (m_reg[5] << 8))
37 #define TIMER1 (TIMER1HELPER ? TIMER1HELPER : 0x10000)
38 #define TIMER2 (TIMER2HELPER ? TIMER2HELPER : 0x10000)
39 #define TIMER3 (TIMER3HELPER ? TIMER3HELPER : 0x10000)
40 
41 #define TED7360_YPOS            40
42 #define RASTERLINE_2_C16(a)    ((a + m_lines - TED7360_YPOS - 5) % m_lines)
43 #define C16_2_RASTERLINE(a)    ((a + TED7360_YPOS + 5) % m_lines)
44 #define XPOS 8
45 #define YPOS 8
46 
47 #define SCREENON               (m_reg[6] & 0x10)
48 #define TEST                   (m_reg[6] & 0x80)
49 #define VERTICALPOS            (m_reg[6] & 0x07)
50 #define HORICONTALPOS          (m_reg[7] & 0x07)
51 #define ECMON                  (m_reg[6] & 0x40)
52 #define HIRESON                (m_reg[6] & 0x20)
53 #define MULTICOLORON           (m_reg[7] & 0x10)
54 #define REVERSEON              (!(m_reg[7] & 0x80))
55 
56 /* hardware inverts character when bit 7 set (character taken &0x7f) */
57 /* instead of fetching character with higher number! */
58 #define LINES25     (m_reg[6] & 0x08)     /* else 24 Lines */
59 #define LINES       (LINES25 ? 25 : 24)
60 #define YSIZE       (LINES * 8)
61 #define COLUMNS40   (m_reg[7] & 0x08)     /* else 38 Columns */
62 #define COLUMNS     (COLUMNS40 ? 40 : 38)
63 #define XSIZE       (COLUMNS * 8)
64 
65 #define INROM       (m_reg[0x12] & 0x04)
66 #define CHARGENADDR (REVERSEON && !HIRESON && !MULTICOLORON ? ((m_reg[0x13] & 0xfc) << 8) : ((m_reg[0x13] & 0xf8) << 8))
67 #define BITMAPADDR  ((m_reg[0x12] & 0x38) << 10)
68 #define VIDEOADDR   ((m_reg[0x14] & 0xf8) << 8)
69 
70 #define RASTERLINE  (((m_reg[0xa] & 0x01) << 8) | m_reg[0xb])
71 #define CURSOR1POS  (m_reg[0xd] | ((m_reg[0xc] & 0x03) << 8))
72 #define CURSOR2POS  (m_reg[0x1b] | ((m_reg[0x1a] & 0x03) << 8))
73 #define CURSORRATE  ((m_reg[0x1f] & 0x7c) >> 2)
74 
75 #define BACKGROUNDCOLOR (m_reg[0x15] & 0x7f)
76 #define FOREGROUNDCOLOR (m_reg[0x16] & 0x7f)
77 #define MULTICOLOR1     (m_reg[0x17] & 0x7f)
78 #define MULTICOLOR2     (m_reg[0x18] & 0x7f)
79 #define FRAMECOLOR      (m_reg[0x19] & 0x7f)
80 
81 #define TED7360_CLOCK        (m_clock / 4)
82 #define TED7360_VRETRACERATE ((m_clock == TED7360PAL_CLOCK) ? PAL_VRETRACERATE : NTSC_VRETRACERATE)
83 #define TED7360_LINES        ((m_clock == TED7360PAL_CLOCK) ? PAL_LINES : NTSC_LINES)
84 
85 static const rgb_t PALETTE_MOS[] =
86 {
87 /* black, white, red, cyan */
88 /* purple, green, blue, yellow */
89 /* orange, light orange, pink, light cyan, */
90 /* light violett, light green, light blue, light yellow */
91 /* these 16 colors are 8 times here in different luminance (dark..light) */
92 /* taken from digitized tv screenshot */
93 	rgb_t(0x06, 0x01, 0x03), rgb_t(0x2b, 0x2b, 0x2b), rgb_t(0x67, 0x0e, 0x0f), rgb_t(0x00, 0x3f, 0x42),
94 	rgb_t(0x57, 0x00, 0x6d), rgb_t(0x00, 0x4e, 0x00), rgb_t(0x19, 0x1c, 0x94), rgb_t(0x38, 0x38, 0x00),
95 	rgb_t(0x56, 0x20, 0x00), rgb_t(0x4b, 0x28, 0x00), rgb_t(0x16, 0x48, 0x00), rgb_t(0x69, 0x07, 0x2f),
96 	rgb_t(0x00, 0x46, 0x26), rgb_t(0x06, 0x2a, 0x80), rgb_t(0x2a, 0x14, 0x9b), rgb_t(0x0b, 0x49, 0x00),
97 
98 	rgb_t(0x00, 0x03, 0x02), rgb_t(0x3d, 0x3d, 0x3d), rgb_t(0x75, 0x1e, 0x20), rgb_t(0x00, 0x50, 0x4f),
99 	rgb_t(0x6a, 0x10, 0x78), rgb_t(0x04, 0x5c, 0x00), rgb_t(0x2a, 0x2a, 0xa3), rgb_t(0x4c, 0x47, 0x00),
100 	rgb_t(0x69, 0x2f, 0x00), rgb_t(0x59, 0x38, 0x00), rgb_t(0x26, 0x56, 0x00), rgb_t(0x75, 0x15, 0x41),
101 	rgb_t(0x00, 0x58, 0x3d), rgb_t(0x15, 0x3d, 0x8f), rgb_t(0x39, 0x22, 0xae), rgb_t(0x19, 0x59, 0x00),
102 
103 	rgb_t(0x00, 0x03, 0x04), rgb_t(0x42, 0x42, 0x42), rgb_t(0x7b, 0x28, 0x20), rgb_t(0x02, 0x56, 0x59),
104 	rgb_t(0x6f, 0x1a, 0x82), rgb_t(0x0a, 0x65, 0x09), rgb_t(0x30, 0x34, 0xa7), rgb_t(0x50, 0x51, 0x00),
105 	rgb_t(0x6e, 0x36, 0x00), rgb_t(0x65, 0x40, 0x00), rgb_t(0x2c, 0x5c, 0x00), rgb_t(0x7d, 0x1e, 0x45),
106 	rgb_t(0x01, 0x61, 0x45), rgb_t(0x1c, 0x45, 0x99), rgb_t(0x42, 0x2d, 0xad), rgb_t(0x1d, 0x62, 0x00),
107 
108 	rgb_t(0x05, 0x00, 0x02), rgb_t(0x56, 0x55, 0x5a), rgb_t(0x90, 0x3c, 0x3b), rgb_t(0x17, 0x6d, 0x72),
109 	rgb_t(0x87, 0x2d, 0x99), rgb_t(0x1f, 0x7b, 0x15), rgb_t(0x46, 0x49, 0xc1), rgb_t(0x66, 0x63, 0x00),
110 	rgb_t(0x84, 0x4c, 0x0d), rgb_t(0x73, 0x55, 0x00), rgb_t(0x40, 0x72, 0x00), rgb_t(0x91, 0x33, 0x5e),
111 	rgb_t(0x19, 0x74, 0x5c), rgb_t(0x32, 0x59, 0xae), rgb_t(0x59, 0x3f, 0xc3), rgb_t(0x32, 0x76, 0x00),
112 
113 	rgb_t(0x02, 0x01, 0x06), rgb_t(0x84, 0x7e, 0x85), rgb_t(0xbb, 0x67, 0x68), rgb_t(0x45, 0x96, 0x96),
114 	rgb_t(0xaf, 0x58, 0xc3), rgb_t(0x4a, 0xa7, 0x3e), rgb_t(0x73, 0x73, 0xec), rgb_t(0x92, 0x8d, 0x11),
115 	rgb_t(0xaf, 0x78, 0x32), rgb_t(0xa1, 0x80, 0x20), rgb_t(0x6c, 0x9e, 0x12), rgb_t(0xba, 0x5f, 0x89),
116 	rgb_t(0x46, 0x9f, 0x83), rgb_t(0x61, 0x85, 0xdd), rgb_t(0x84, 0x6c, 0xef), rgb_t(0x5d, 0xa3, 0x29),
117 
118 	rgb_t(0x02, 0x00, 0x0a), rgb_t(0xb2, 0xac, 0xb3), rgb_t(0xe9, 0x92, 0x92), rgb_t(0x6c, 0xc3, 0xc1),
119 	rgb_t(0xd9, 0x86, 0xf0), rgb_t(0x79, 0xd1, 0x76), rgb_t(0x9d, 0xa1, 0xff), rgb_t(0xbd, 0xbe, 0x40),
120 	rgb_t(0xdc, 0xa2, 0x61), rgb_t(0xd1, 0xa9, 0x4c), rgb_t(0x93, 0xc8, 0x3d), rgb_t(0xe9, 0x8a, 0xb1),
121 	rgb_t(0x6f, 0xcd, 0xab), rgb_t(0x8a, 0xb4, 0xff), rgb_t(0xb2, 0x9a, 0xff), rgb_t(0x88, 0xcb, 0x59),
122 
123 	rgb_t(0x02, 0x00, 0x0a), rgb_t(0xc7, 0xca, 0xc9), rgb_t(0xff, 0xac, 0xac), rgb_t(0x85, 0xd8, 0xe0),
124 	rgb_t(0xf3, 0x9c, 0xff), rgb_t(0x92, 0xea, 0x8a), rgb_t(0xb7, 0xba, 0xff), rgb_t(0xd6, 0xd3, 0x5b),
125 	rgb_t(0xf3, 0xbe, 0x79), rgb_t(0xe6, 0xc5, 0x65), rgb_t(0xb0, 0xe0, 0x57), rgb_t(0xff, 0xa4, 0xcf),
126 	rgb_t(0x89, 0xe5, 0xc8), rgb_t(0xa4, 0xca, 0xff), rgb_t(0xca, 0xb3, 0xff), rgb_t(0xa2, 0xe5, 0x7a),
127 
128 	rgb_t(0x01, 0x01, 0x01), rgb_t(0xff, 0xff, 0xff), rgb_t(0xff, 0xf6, 0xf2), rgb_t(0xd1, 0xff, 0xff),
129 	rgb_t(0xff, 0xe9, 0xff), rgb_t(0xdb, 0xff, 0xd3), rgb_t(0xfd, 0xff, 0xff), rgb_t(0xff, 0xff, 0xa3),
130 	rgb_t(0xff, 0xff, 0xc1), rgb_t(0xff, 0xff, 0xb2), rgb_t(0xfc, 0xff, 0xa2), rgb_t(0xff, 0xee, 0xff),
131 	rgb_t(0xd1, 0xff, 0xff), rgb_t(0xeb, 0xff, 0xff), rgb_t(0xff, 0xf8, 0xff), rgb_t(0xed, 0xff, 0xbc)
132 };
133 
134 
135 #define NOISE_BUFFER_SIZE_SEC 5
136 
137 #define TONE_ON         (!(m_reg[0x11] & 0x80))     /* or tone update!? */
138 #define TONE1_ON        ((m_reg[0x11] & 0x10))
139 #define TONE1_VALUE     (m_reg[0x0e] | ((m_reg[0x12] & 3) << 8))
140 #define TONE2_ON        ((m_reg[0x11] & 0x20))
141 #define TONE2_VALUE     (m_reg[0x0f] | ((m_reg[0x10] & 3) << 8))
142 #define VOLUME          (m_reg[0x11] & 0x0f)
143 #define NOISE_ON        (m_reg[0x11] & 0x40)
144 
145 /*
146  * pal 111860.781
147  * ntsc 111840.45
148  */
149 #define TONE_FREQUENCY(reg)         ((TED7360_CLOCK >> 3) / (1024 - reg))
150 #define TONE_FREQUENCY_MIN          (TONE_FREQUENCY(0))
151 #define NOISE_FREQUENCY             (TED7360_CLOCK / 8 / (1024 - TONE2_VALUE))
152 #define NOISE_FREQUENCY_MAX         (TED7360_CLOCK / 8)
153 
154 
155 //**************************************************************************
156 //  GLOBAL VARIABLES
157 //**************************************************************************
158 
159 constexpr unsigned mos7360_device::NTSC_VRETRACERATE;
160 constexpr unsigned mos7360_device::PAL_VRETRACERATE;
161 constexpr unsigned mos7360_device::HRETRACERATE;
162 constexpr unsigned mos7360_device::HSIZE;
163 constexpr unsigned mos7360_device::VSIZE;
164 constexpr unsigned mos7360_device::NTSC_LINES;
165 constexpr unsigned mos7360_device::PAL_LINES;
166 
167 
168 // device type definition
169 DEFINE_DEVICE_TYPE(MOS7360, mos7360_device, "mos7360", "MOS 7360 TED")
170 
171 
172 // default address maps
mos7360_videoram_map(address_map & map)173 void mos7360_device::mos7360_videoram_map(address_map &map)
174 {
175 	if (!has_configured_map(0))
176 		map(0x0000, 0xffff).ram();
177 }
178 
179 
180 //-------------------------------------------------
181 //  memory_space_config - return a description of
182 //  any address spaces owned by this device
183 //-------------------------------------------------
184 
memory_space_config() const185 device_memory_interface::space_config_vector mos7360_device::memory_space_config() const
186 {
187 	return space_config_vector {
188 		std::make_pair(0, &m_videoram_space_config)
189 	};
190 }
191 
192 
193 
194 //**************************************************************************
195 //  INLINE HELPERS
196 //**************************************************************************
197 
set_interrupt(int mask)198 inline void mos7360_device::set_interrupt(int mask)
199 {
200 	/* kernel itself polls for timer 2 shot (interrupt disabled!) when cassette loading */
201 	m_reg[9] |= mask;
202 	if ((m_reg[0xa] & m_reg[9] & 0x5e))
203 	{
204 		if (!(m_reg[9] & 0x80))
205 		{
206 			//DBG_LOG(1, "ted7360", ("irq start %.2x\n", mask));
207 			m_reg[9] |= 0x80;
208 			m_write_irq(ASSERT_LINE);
209 		}
210 	}
211 	m_reg[9] |= mask;
212 }
213 
clear_interrupt(int mask)214 inline void mos7360_device::clear_interrupt(int mask)
215 {
216 	m_reg[9] &= ~mask;
217 	if ((m_reg[9] & 0x80) && !(m_reg[9] & m_reg[0xa] & 0x5e))
218 	{
219 		DBG_LOG(1, "ted7360", ("irq end %.2x\n", mask));
220 		m_reg[9] &= ~0x80;
221 		m_write_irq(CLEAR_LINE);
222 	}
223 }
224 
rastercolumn()225 inline int mos7360_device::rastercolumn()
226 {
227 	return (int) ((machine().time().as_double() - m_rastertime) * TED7360_VRETRACERATE * m_lines * 57 * 8 + 0.5);
228 }
229 
read_ram(offs_t offset)230 inline uint8_t mos7360_device::read_ram(offs_t offset)
231 {
232 	int rom = m_rom;
233 	m_rom = 0;
234 
235 	m_last_data = space(0).read_byte(offset);
236 
237 	m_rom = rom;
238 
239 	return m_last_data;
240 }
241 
read_rom(offs_t offset)242 inline uint8_t mos7360_device::read_rom(offs_t offset)
243 {
244 	int rom = m_rom;
245 	m_rom = 1;
246 
247 	m_last_data = space(0).read_byte(offset);
248 
249 	m_rom = rom;
250 
251 	return m_last_data;
252 }
253 
254 
255 
256 //**************************************************************************
257 //  LIVE DEVICE
258 //**************************************************************************
259 
260 //-------------------------------------------------
261 //  mos7360_device - constructor
262 //-------------------------------------------------
263 
mos7360_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)264 mos7360_device::mos7360_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
265 	: device_t(mconfig, MOS7360, tag, owner, clock),
266 		device_memory_interface(mconfig, *this),
267 		device_sound_interface(mconfig, *this),
268 		device_video_interface(mconfig, *this),
269 		m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, address_map_constructor(FUNC(mos7360_device::mos7360_videoram_map), this)),
270 		m_write_irq(*this),
271 		m_read_k(*this),
272 		m_stream(nullptr)
273 {
274 }
275 
276 
277 //-------------------------------------------------
278 //  device_start - device-specific startup
279 //-------------------------------------------------
280 
device_start()281 void mos7360_device::device_start()
282 {
283 	// resolve callbacks
284 	m_write_irq.resolve_safe();
285 	m_read_k.resolve_safe(0xff);
286 
287 	// allocate timers
288 	m_timer1 = timer_alloc(TIMER_ID_1);
289 	m_timer2 = timer_alloc(TIMER_ID_2);
290 	m_timer3 = timer_alloc(TIMER_ID_3);
291 	m_line_timer = timer_alloc(TIMER_LINE);
292 	m_line_timer->adjust(screen().scan_period(), 0, screen().scan_period());
293 	m_frame_timer = timer_alloc(TIMER_FRAME);
294 	m_frame_timer->adjust(screen().frame_period(), 0, screen().frame_period());
295 
296 	// allocate screen bitmap
297 	screen().register_screen_bitmap(m_bitmap);
298 
299 	// create sound stream
300 	m_stream = stream_alloc(0, 1, machine().sample_rate());
301 
302 	// buffer for fastest played sample for 5 second so we have enough data for min 5 second
303 	m_noisesize = NOISE_FREQUENCY_MAX * NOISE_BUFFER_SIZE_SEC;
304 	m_noise = std::make_unique<uint8_t[]>(m_noisesize);
305 
306 	{
307 		int noiseshift = 0x7ffff8;
308 		uint8_t data;
309 
310 		for (int i = 0; i < m_noisesize; i++)
311 		{
312 			data = 0;
313 			if (noiseshift & 0x400000)
314 				data |= 0x80;
315 			if (noiseshift & 0x100000)
316 				data |= 0x40;
317 			if (noiseshift & 0x010000)
318 				data |= 0x20;
319 			if (noiseshift & 0x002000)
320 				data |= 0x10;
321 			if (noiseshift & 0x000800)
322 				data |= 0x08;
323 			if (noiseshift & 0x000080)
324 				data |= 0x04;
325 			if (noiseshift & 0x000010)
326 				data |= 0x02;
327 			if (noiseshift & 0x000004)
328 				data |= 0x01;
329 			m_noise[i] = data;
330 			if (((noiseshift & 0x400000) == 0) != ((noiseshift & 0x002000) == 0))
331 				noiseshift = (noiseshift << 1) | 1;
332 			else
333 				noiseshift <<= 1;
334 		}
335 	}
336 
337 	// register for state saving
338 	save_item(NAME(m_reg));
339 	save_item(NAME(m_last_data));
340 	save_item(NAME(m_rom));
341 	save_item(NAME(m_frame_count));
342 	save_item(NAME(m_lines));
343 	save_item(NAME(m_timer1_active));
344 	save_item(NAME(m_timer2_active));
345 	save_item(NAME(m_timer3_active));
346 	save_item(NAME(m_cursor1));
347 	save_item(NAME(m_chargenaddr));
348 	save_item(NAME(m_bitmapaddr));
349 	save_item(NAME(m_videoaddr));
350 	save_item(NAME(m_x_begin));
351 	save_item(NAME(m_x_end));
352 	save_item(NAME(m_y_begin));
353 	save_item(NAME(m_y_end));
354 	save_item(NAME(m_c16_bitmap));
355 	save_item(NAME(m_bitmapmulti));
356 	save_item(NAME(m_mono));
357 	save_item(NAME(m_monoinversed));
358 	save_item(NAME(m_multi));
359 	save_item(NAME(m_ecmcolor));
360 	save_item(NAME(m_colors));
361 	save_item(NAME(m_rasterline));
362 	save_item(NAME(m_lastline));
363 	save_item(NAME(m_rastertime));
364 	save_item(NAME(m_tone1pos));
365 	save_item(NAME(m_tone2pos));
366 	save_item(NAME(m_tone1samples));
367 	save_item(NAME(m_tone2samples));
368 	save_item(NAME(m_noisepos));
369 	save_item(NAME(m_noisesamples));
370 }
371 
372 
373 //-------------------------------------------------
374 //  device_reset - device-specific reset
375 //-------------------------------------------------
376 
device_reset()377 void mos7360_device::device_reset()
378 {
379 	memset(m_reg, 0, sizeof(m_reg));
380 	m_last_data = 0;
381 
382 	m_rom = 1;  // FIXME: at start should be RAM or ROM? old c16 code set it to ROM at init: is it correct?
383 
384 	m_lines = TED7360_LINES;
385 	m_chargenaddr = m_bitmapaddr = m_videoaddr = 0;
386 	m_timer1_active = m_timer2_active = m_timer3_active = 0;
387 	m_cursor1 = 0;
388 
389 	m_rasterline = 0;
390 	m_lastline = 0;
391 
392 	m_rastertime = 0.0;
393 
394 	m_frame_count = 0;
395 
396 	m_x_begin = 0;
397 	m_x_end = 0;
398 	m_y_begin = 0;
399 	m_y_end = 0;
400 
401 	memset(m_c16_bitmap, 0, sizeof(m_c16_bitmap));
402 	memset(m_bitmapmulti, 0, sizeof(m_bitmapmulti));
403 	memset(m_mono, 0, sizeof(m_mono));
404 	memset(m_monoinversed, 0, sizeof(m_monoinversed));
405 	memset(m_multi, 0, sizeof(m_multi));
406 	memset(m_ecmcolor, 0, sizeof(m_ecmcolor));
407 	memset(m_colors, 0, sizeof(m_colors));
408 
409 	m_tone1pos = 0;
410 	m_tone2pos = 0;
411 	m_tone1samples = 1;
412 	m_tone2samples = 1;
413 	m_noisepos = 0;
414 	m_noisesamples = 1;
415 }
416 
417 
418 //-------------------------------------------------
419 //  device_timer - handler timer events
420 //-------------------------------------------------
421 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)422 void mos7360_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
423 {
424 	switch (id)
425 	{
426 	case TIMER_ID_1:
427 		// proved by digisound of several intros like eoroidpro
428 		m_timer1->adjust(clocks_to_attotime(TIMER1), 1);
429 		m_timer1_active = 1;
430 		set_interrupt(0x08);
431 		break;
432 
433 	case TIMER_ID_2:
434 		m_timer2->adjust(clocks_to_attotime(0x10000), 2);
435 		m_timer2_active = 1;
436 		set_interrupt(0x10);
437 		break;
438 
439 	case TIMER_ID_3:
440 		m_timer3->adjust(clocks_to_attotime(0x10000), 3);
441 		m_timer3_active = 1;
442 		set_interrupt(0x40);
443 		break;
444 
445 	case TIMER_LINE:
446 		raster_interrupt_gen();
447 		break;
448 
449 	case TIMER_FRAME:
450 		frame_interrupt_gen();
451 		break;
452 	}
453 }
454 
455 
456 //-------------------------------------------------
457 //  sound_stream_update - handle update requests for
458 //  our sound stream
459 //-------------------------------------------------
460 
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)461 void mos7360_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
462 {
463 	int i, v, a;
464 	auto &buffer = outputs[0];
465 
466 	for (i = 0; i < buffer.samples(); i++)
467 	{
468 		v = 0;
469 
470 		if (TONE1_ON)
471 		{
472 			if (m_tone1pos <= m_tone1samples / 2 || !TONE_ON)
473 				v += 0x2ff; // depends on the volume between sound and noise
474 
475 			m_tone1pos++;
476 
477 			if (m_tone1pos > m_tone1samples)
478 				m_tone1pos = 0;
479 		}
480 
481 		if (TONE2_ON || NOISE_ON )
482 		{
483 			if (TONE2_ON)
484 			{                          /*higher priority ?! */
485 				if (m_tone2pos <= m_tone2samples / 2 || !TONE_ON)
486 					v += 0x2ff;
487 
488 				m_tone2pos++;
489 
490 				if (m_tone2pos > m_tone2samples)
491 					m_tone2pos = 0;
492 			}
493 			else
494 			{
495 				v += m_noise[(int) ((double) m_noisepos * m_noisesize / m_noisesamples)];
496 				m_noisepos++;
497 
498 				if ((double) m_noisepos / m_noisesamples >= 1.0)
499 					m_noisepos = 0;
500 			}
501 		}
502 
503 		a = VOLUME;
504 		if (a > 8)
505 			a = 8;
506 
507 		v = v * a;
508 
509 		buffer.put_int(i, v, 32768);
510 	}
511 }
512 
513 
draw_character(int ybegin,int yend,int ch,int yoff,int xoff,uint16_t * color)514 void mos7360_device::draw_character(int ybegin, int yend, int ch, int yoff, int xoff, uint16_t *color)
515 {
516 	for (int y = ybegin; y <= yend; y++)
517 	{
518 		int code;
519 		if (INROM)
520 			code = read_rom(m_chargenaddr + ch * 8 + y);
521 		else
522 			code = read_ram(m_chargenaddr + ch * 8 + y);
523 
524 		m_bitmap.pix(y + yoff, 0 + xoff) = PALETTE_MOS[color[BIT(code, 7)]];
525 		m_bitmap.pix(y + yoff, 1 + xoff) = PALETTE_MOS[color[BIT(code, 6)]];
526 		m_bitmap.pix(y + yoff, 2 + xoff) = PALETTE_MOS[color[BIT(code, 5)]];
527 		m_bitmap.pix(y + yoff, 3 + xoff) = PALETTE_MOS[color[BIT(code, 4)]];
528 		m_bitmap.pix(y + yoff, 4 + xoff) = PALETTE_MOS[color[BIT(code, 3)]];
529 		m_bitmap.pix(y + yoff, 5 + xoff) = PALETTE_MOS[color[BIT(code, 2)]];
530 		m_bitmap.pix(y + yoff, 6 + xoff) = PALETTE_MOS[color[BIT(code, 1)]];
531 		m_bitmap.pix(y + yoff, 7 + xoff) = PALETTE_MOS[color[BIT(code, 0)]];
532 	}
533 }
534 
draw_character_multi(int ybegin,int yend,int ch,int yoff,int xoff)535 void mos7360_device::draw_character_multi(int ybegin, int yend, int ch, int yoff, int xoff)
536 {
537 	for (int y = ybegin; y <= yend; y++)
538 	{
539 		int code;
540 		if (INROM)
541 			code = read_rom(m_chargenaddr + ch * 8 + y);
542 		else
543 			code = read_ram(m_chargenaddr + ch * 8 + y);
544 
545 		m_bitmap.pix(y + yoff, 0 + xoff) = m_bitmap.pix(y + yoff, 1 + xoff) =
546 				PALETTE_MOS[m_multi[code >> 6]];
547 		m_bitmap.pix(y + yoff, 2 + xoff) = m_bitmap.pix(y + yoff, 3 + xoff) =
548 				PALETTE_MOS[m_multi[(code >> 4) & 3]];
549 		m_bitmap.pix(y + yoff, 4 + xoff) = m_bitmap.pix(y + yoff, 5 + xoff) =
550 				PALETTE_MOS[m_multi[(code >> 2) & 3]];
551 		m_bitmap.pix(y + yoff, 6 + xoff) = m_bitmap.pix(y + yoff, 7 + xoff) =
552 				PALETTE_MOS[m_multi[code & 3]];
553 	}
554 }
555 
draw_bitmap(int ybegin,int yend,int ch,int yoff,int xoff)556 void mos7360_device::draw_bitmap(int ybegin, int yend, int ch, int yoff, int xoff)
557 {
558 	for (int y = ybegin; y <= yend; y++)
559 	{
560 		int code = read_ram(m_bitmapaddr + ch * 8 + y);
561 
562 		m_bitmap.pix(y + yoff, 0 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 7)]];
563 		m_bitmap.pix(y + yoff, 1 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 6)]];
564 		m_bitmap.pix(y + yoff, 2 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 5)]];
565 		m_bitmap.pix(y + yoff, 3 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 4)]];
566 		m_bitmap.pix(y + yoff, 4 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 3)]];
567 		m_bitmap.pix(y + yoff, 5 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 2)]];
568 		m_bitmap.pix(y + yoff, 6 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 1)]];
569 		m_bitmap.pix(y + yoff, 7 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 0)]];
570 	}
571 }
572 
draw_bitmap_multi(int ybegin,int yend,int ch,int yoff,int xoff)573 void mos7360_device::draw_bitmap_multi(int ybegin, int yend, int ch, int yoff, int xoff)
574 {
575 	for (int y = ybegin; y <= yend; y++)
576 	{
577 		int code = read_ram(m_bitmapaddr + ch * 8 + y);
578 
579 		m_bitmap.pix(y + yoff, 0 + xoff) = m_bitmap.pix(y + yoff, 1 + xoff) =
580 				PALETTE_MOS[m_bitmapmulti[code >> 6]];
581 		m_bitmap.pix(y + yoff, 2 + xoff) = m_bitmap.pix(y + yoff, 3 + xoff) =
582 				PALETTE_MOS[m_bitmapmulti[(code >> 4) & 3]];
583 		m_bitmap.pix(y + yoff, 4 + xoff) = m_bitmap.pix(y + yoff, 5 + xoff) =
584 				PALETTE_MOS[m_bitmapmulti[(code >> 2) & 3]];
585 		m_bitmap.pix(y + yoff, 6 + xoff) = m_bitmap.pix(y + yoff, 7 + xoff) =
586 				PALETTE_MOS[m_bitmapmulti[code & 3]];
587 	}
588 }
589 
draw_cursor(int ybegin,int yend,int yoff,int xoff,int color)590 void mos7360_device::draw_cursor(int ybegin, int yend, int yoff, int xoff, int color)
591 {
592 	for (int y = ybegin; y <= yend; y++)
593 	{
594 		for (int x = 0; x < 8; x++)
595 		{
596 			m_bitmap.pix(y + yoff, x + xoff) = PALETTE_MOS[color];
597 		}
598 	}
599 }
600 
drawlines(int first,int last)601 void mos7360_device::drawlines(int first, int last)
602 {
603 	m_lastline = last;
604 
605 	/* top part of display not rastered */
606 	first -= TED7360_YPOS;
607 	last -= TED7360_YPOS;
608 	if ((first >= last) || (last <= 0))
609 		return;
610 	if (first < 0)
611 		first = 0;
612 
613 	if (!SCREENON)
614 	{
615 		for (int line = first; (line < last) && (line < m_bitmap.height()); line++)
616 		{
617 			for (int x = 0; x < m_bitmap.width(); x++)
618 			{
619 				m_bitmap.pix(line, x) = PALETTE_MOS[FRAMECOLOR];
620 			}
621 		}
622 		return;
623 	}
624 
625 	int xbegin, xend;
626 	if (COLUMNS40)
627 	{
628 		xbegin = XPOS;
629 		xend = xbegin + 320;
630 	}
631 	else
632 	{
633 		xbegin = XPOS + 7;
634 		xend = xbegin + 304;
635 	}
636 
637 	int end;
638 	if (last < m_y_begin)
639 		end = last;
640 	else
641 		end = m_y_begin + YPOS;
642 
643 	int line;
644 	for (line = first; line < end; line++)
645 	{
646 		for (int x = 0; x < m_bitmap.width(); x++)
647 		{
648 			m_bitmap.pix(line, x) = PALETTE_MOS[FRAMECOLOR];
649 		}
650 	}
651 
652 	int vline;
653 	if (LINES25)
654 		vline = line - m_y_begin - YPOS;
655 	else
656 		vline = line - m_y_begin - YPOS + 8 - VERTICALPOS;
657 
658 	if (last < m_y_end + YPOS)
659 		end = last;
660 	else
661 		end = m_y_end + YPOS;
662 
663 	for (int ybegin, yend; line < end; vline = (vline + 8) & ~7, line = line + 1 + yend - ybegin)
664 	{
665 		int offs = (vline >> 3) * 40;
666 		ybegin = vline & 7;
667 		int yoff = line - ybegin;
668 		yend = (yoff + 7 < end) ? 7 : (end - yoff - 1);
669 		/* rendering 39 characters */
670 		/* left and right borders are overwritten later */
671 
672 		for (int xoff = m_x_begin + XPOS; xoff < m_x_end + XPOS; xoff += 8, offs++)
673 		{
674 			if (HIRESON)
675 			{
676 				int ch = read_ram((m_videoaddr | 0x400) + offs);
677 				int attr = read_ram(m_videoaddr + offs);
678 				int c1 = ((ch >> 4) & 0xf) | (attr << 4);
679 				int c2 = (ch & 0xf) | (attr & 0x70);
680 				m_bitmapmulti[1] = m_c16_bitmap[1] = c1 & 0x7f;
681 				m_bitmapmulti[2] = m_c16_bitmap[0] = c2 & 0x7f;
682 				if (MULTICOLORON)
683 				{
684 					draw_bitmap_multi(ybegin, yend, offs, yoff, xoff);
685 				}
686 				else
687 				{
688 					draw_bitmap(ybegin, yend, offs, yoff, xoff);
689 				}
690 			}
691 			else
692 			{
693 				int ch = read_ram((m_videoaddr | 0x400) + offs);
694 				int attr = read_ram(m_videoaddr + offs);
695 				// levente harsfalvi's docu says cursor off in ecm and multicolor
696 				if (ECMON)
697 				{
698 					// hardware reverse off
699 					int ecm = ch >> 6;
700 					m_ecmcolor[0] = m_colors[ecm];
701 					m_ecmcolor[1] = attr & 0x7f;
702 					draw_character(ybegin, yend, ch & ~0xc0, yoff, xoff, m_ecmcolor);
703 				}
704 				else if (MULTICOLORON)
705 				{
706 					// hardware reverse off
707 					if (attr & 8)
708 					{
709 						m_multi[3] = attr & 0x77;
710 						draw_character_multi(ybegin, yend, ch, yoff, xoff);
711 					}
712 					else
713 					{
714 						m_mono[1] = attr & 0x7f;
715 						draw_character(ybegin, yend, ch, yoff, xoff, m_mono);
716 					}
717 				}
718 				else if (m_cursor1 && (offs == CURSOR1POS))
719 				{
720 					draw_cursor(ybegin, yend, yoff, xoff, attr & 0x7f);
721 				}
722 				else if (REVERSEON && (ch & 0x80))
723 				{
724 					m_monoinversed[0] = attr & 0x7f;
725 					if (m_cursor1 && (attr & 0x80))
726 						draw_cursor(ybegin, yend, yoff, xoff, m_monoinversed[0]);
727 					else
728 						draw_character(ybegin, yend, ch & ~0x80, yoff, xoff, m_monoinversed);
729 				}
730 				else
731 				{
732 					m_mono[1] = attr & 0x7f;
733 					if (m_cursor1 && (attr & 0x80))
734 						draw_cursor(ybegin, yend, yoff, xoff, m_mono[0]);
735 					else
736 						draw_character(ybegin, yend, ch, yoff, xoff, m_mono);
737 				}
738 			}
739 		}
740 
741 		for (int i = ybegin; i <= yend; i++)
742 		{
743 			for (int x = 0; x < xbegin; x++)
744 			{
745 				m_bitmap.pix(yoff + i, x) = PALETTE_MOS[FRAMECOLOR];
746 			}
747 
748 			for (int x = xend; x < m_bitmap.width(); x++)
749 			{
750 				m_bitmap.pix(yoff + i, x) = PALETTE_MOS[FRAMECOLOR];
751 			}
752 		}
753 	}
754 
755 	if (last < m_bitmap.height())
756 		end = last;
757 	else
758 		end = m_bitmap.height();
759 
760 	for (; line < end; line++)
761 	{
762 		for (int x = 0; x < m_bitmap.width(); x++)
763 		{
764 			m_bitmap.pix(line, x) = PALETTE_MOS[FRAMECOLOR];
765 		}
766 	}
767 }
768 
soundport_w(int offset,int data)769 void mos7360_device::soundport_w(int offset, int data)
770 {
771 	// int old = m_reg[offset & 0x1f];
772 	m_stream->update();
773 
774 	switch (offset)
775 	{
776 	case 0x0e:
777 	case 0x12:
778 		if (offset == 0x12)
779 			m_reg[offset & 0x1f] = (m_reg[offset & 0x1f] & ~3) | (data & 3);
780 		else
781 			m_reg[offset & 0x1f] = data;
782 
783 		m_tone1samples = machine().sample_rate() / TONE_FREQUENCY (TONE1_VALUE);
784 		DBG_LOG(1, "ted7360", ("tone1 %d %d sample:%d\n", TONE1_VALUE, TONE_FREQUENCY(TONE1_VALUE), m_tone1samples));
785 		break;
786 
787 	case 0xf:
788 	case 0x10:
789 		m_reg[offset & 0x1f] = data;
790 
791 		m_tone2samples = machine().sample_rate() / TONE_FREQUENCY (TONE2_VALUE);
792 		DBG_LOG (1, "ted7360", ("tone2 %d %d sample:%d\n", TONE2_VALUE, TONE_FREQUENCY(TONE2_VALUE), m_tone2samples));
793 
794 		m_noisesamples = (int) ((double) NOISE_FREQUENCY_MAX * machine().sample_rate() * NOISE_BUFFER_SIZE_SEC / NOISE_FREQUENCY);
795 		DBG_LOG (1, "ted7360", ("noise %d sample:%d\n", NOISE_FREQUENCY, m_noisesamples));
796 
797 		if (!NOISE_ON || ((double) m_noisepos / m_noisesamples >= 1.0))
798 			m_noisepos = 0;
799 		break;
800 
801 	case 0x11:
802 		m_reg[offset & 0x1f] = data;
803 		DBG_LOG(1, "ted7360", ("%s volume %d, %s %s %s\n", TONE_ON?"on":"off",
804 						VOLUME, TONE1_ON?"tone1":"", TONE2_ON?"tone2":"", NOISE_ON?"noise":""));
805 
806 		if (!TONE_ON||!TONE1_ON) m_tone1pos = 0;
807 		if (!TONE_ON||!TONE2_ON) m_tone2pos = 0;
808 		if (!TONE_ON||!NOISE_ON) m_noisepos = 0;
809 		break;
810 	}
811 }
812 
813 
814 //-------------------------------------------------
815 //  read - register read
816 //-------------------------------------------------
817 
read(offs_t offset,int & cs0,int & cs1)818 uint8_t mos7360_device::read(offs_t offset, int &cs0, int &cs1)
819 {
820 	uint8_t val = m_last_data;
821 
822 	cs0 = cs0_r(offset);
823 	cs1 = cs1_r(offset);
824 
825 	switch (offset)
826 	{
827 	case 0xff00:
828 		val = attotime_to_clocks(m_timer1->remaining()) & 0xff;
829 		break;
830 	case 0xff01:
831 		val = attotime_to_clocks(m_timer1->remaining()) >> 8;
832 		break;
833 	case 0xff02:
834 		val = attotime_to_clocks(m_timer2->remaining()) & 0xff;
835 		break;
836 	case 0xff03:
837 		val = attotime_to_clocks(m_timer2->remaining()) >> 8;
838 		break;
839 	case 0xff04:
840 		val = attotime_to_clocks(m_timer3->remaining()) & 0xff;
841 		break;
842 	case 0xff05:
843 		val = attotime_to_clocks(m_timer3->remaining()) >> 8;
844 		break;
845 	case 0xff07:
846 		val = (m_reg[offset & 0x1f] & ~0x40);
847 		if (m_clock == TED7360NTSC_CLOCK)
848 			val |= 0x40;
849 		break;
850 	case 0xff13:
851 		val = m_reg[offset & 0x1f] & ~1;
852 		if (m_rom)
853 			val |= 1;
854 		break;
855 	case 0xff1c:                         /*rasterline */
856 		drawlines(m_lastline, m_rasterline);
857 		val = ((RASTERLINE_2_C16(m_rasterline) & 0x100) >> 8) | 0xfe;   /* expected by matrix */
858 		break;
859 	case 0xff1d:                         /*rasterline */
860 		drawlines(m_lastline, m_rasterline);
861 		val = RASTERLINE_2_C16(m_rasterline) & 0xff;
862 		break;
863 	case 0xff1e:                         /*rastercolumn */
864 		val = rastercolumn() / 2;   /* pengo >=0x99 */
865 		break;
866 	case 0xff1f:
867 		val = ((m_rasterline & 7) << 4) | (m_reg[offset & 0x1f] & 0x0f);
868 		DBG_LOG(1, "port_w", ("read from cursorblink %.2x\n", val));
869 		break;
870 	case 0xff06:
871 	case 0xff08:
872 	case 0xff09:
873 	case 0xff0a:
874 	case 0xff0b:
875 	case 0xff0c:
876 	case 0xff0d:
877 	case 0xff0e:
878 	case 0xff0f:
879 	case 0xff10:
880 	case 0xff11:
881 	case 0xff12:
882 	case 0xff14:
883 	case 0xff15:
884 	case 0xff16:
885 	case 0xff17:
886 	case 0xff18:
887 	case 0xff19:
888 	case 0xff1a:
889 	case 0xff1b:
890 		val = m_reg[offset & 0x1f];
891 		break;
892 	}
893 
894 	return val;
895 }
896 
897 
898 //-------------------------------------------------
899 //  write - register write
900 //-------------------------------------------------
901 
write(offs_t offset,uint8_t data,int & cs0,int & cs1)902 void mos7360_device::write(offs_t offset, uint8_t data, int &cs0, int &cs1)
903 {
904 	int old;
905 
906 	cs0 = cs0_r(offset);
907 	cs1 = cs1_r(offset);
908 
909 	switch (offset)
910 	{
911 	case 0xff0e:
912 	case 0xff0f:
913 	case 0xff10:
914 	case 0xff11:
915 	case 0xff12:
916 		soundport_w(offset & 0x1f, data);
917 		break;
918 	}
919 
920 	switch (offset)
921 	{
922 	case 0xff00:                        /* stop timer 1 */
923 		m_reg[offset & 0x1f] = data;
924 
925 		if (m_timer1_active)
926 		{
927 			m_reg[1] = attotime_to_clocks(m_timer1->remaining()) >> 8;
928 			m_timer1->reset();
929 			m_timer1_active = 0;
930 		}
931 		break;
932 	case 0xff01:                        /* start timer 1 */
933 		m_reg[offset & 0x1f] = data;
934 		m_timer1->adjust(clocks_to_attotime(TIMER1), 1);
935 		m_timer1_active = 1;
936 		break;
937 	case 0xff02:                        /* stop timer 2 */
938 		m_reg[offset & 0x1f] = data;
939 		if (m_timer2_active)
940 		{
941 			m_reg[3] = attotime_to_clocks(m_timer2->remaining()) >> 8;
942 			m_timer2->reset();
943 			m_timer2_active = 0;
944 		}
945 		break;
946 	case 0xff03:                        /* start timer 2 */
947 		m_reg[offset & 0x1f] = data;
948 		m_timer2->adjust(clocks_to_attotime(TIMER2), 2);
949 		m_timer2_active = 1;
950 		break;
951 	case 0xff04:                        /* stop timer 3 */
952 		m_reg[offset & 0x1f] = data;
953 		if (m_timer3_active)
954 		{
955 			m_reg[5] = attotime_to_clocks(m_timer3->remaining()) >> 8;
956 			m_timer3->reset();
957 			m_timer3_active = 0;
958 		}
959 		break;
960 	case 0xff05:                        /* start timer 3 */
961 		m_reg[offset & 0x1f] = data;
962 		m_timer3->adjust(clocks_to_attotime(TIMER3), 3);
963 		m_timer3_active = 1;
964 		break;
965 	case 0xff06:
966 		if (m_reg[offset & 0x1f] != data)
967 		{
968 			drawlines(m_lastline, m_rasterline);
969 			m_reg[offset & 0x1f] = data;
970 			if (LINES25)
971 			{
972 				m_y_begin = 0;
973 				m_y_end = m_y_begin + 200;
974 			}
975 			else
976 			{
977 				m_y_begin = 4;
978 				m_y_end = m_y_begin + 192;
979 			}
980 			m_chargenaddr = CHARGENADDR;
981 		}
982 		break;
983 	case 0xff07:
984 		if (m_reg[offset & 0x1f] != data)
985 		{
986 			drawlines(m_lastline, m_rasterline);
987 			m_reg[offset & 0x1f] = data;
988 			if (COLUMNS40)
989 			{
990 				m_x_begin = 0;
991 				m_x_end = m_x_begin + 320;
992 			}
993 			else
994 			{
995 				m_x_begin = HORICONTALPOS;
996 				m_x_end = m_x_begin + 320;
997 			}
998 			DBG_LOG(3, "port_w", ("%s %s\n", data & 0x40 ? "ntsc" : "pal", data & 0x20 ? "hori freeze" : ""));
999 			m_chargenaddr = CHARGENADDR;
1000 		}
1001 		break;
1002 	case 0xff08:
1003 		m_reg[offset & 0x1f] = m_read_k(data);
1004 		break;
1005 	case 0xff09:
1006 		if (data & 0x08)
1007 			clear_interrupt(8);
1008 		if (data & 0x10)
1009 			clear_interrupt(0x10);
1010 		if (data & 0x40)
1011 			clear_interrupt(0x40);
1012 		if (data & 0x02)
1013 			clear_interrupt(2);
1014 		break;
1015 	case 0xff0a:
1016 		old = data;
1017 		m_reg[offset & 0x1f] = data | 0xa0;
1018 #if 0
1019 		m_reg[9] = (m_reg[9] & 0xa1) | (m_reg[9] & data & 0x5e);
1020 		if (m_reg[9] & 0x80)
1021 			clear_interrupt(0);
1022 #endif
1023 		if ((data ^ old) & 1)
1024 		{
1025 			/* DBG_LOG(1,"set rasterline hi",("soll:%d\n",RASTERLINE)); */
1026 		}
1027 		break;
1028 	case 0xff0b:
1029 		if (data != m_reg[offset & 0x1f])
1030 		{
1031 			drawlines(m_lastline, m_rasterline);
1032 			m_reg[offset & 0x1f] = data;
1033 			/*  DBG_LOG(1,"set rasterline lo",("soll:%d\n",RASTERLINE)); */
1034 		}
1035 		break;
1036 	case 0xff0c:
1037 	case 0xff0d:
1038 		if (m_reg[offset & 0x1f] != data)
1039 		{
1040 			drawlines(m_lastline, m_rasterline);
1041 			m_reg[offset & 0x1f] = data;
1042 		}
1043 		break;
1044 	case 0xff12:
1045 		if (m_reg[offset & 0x1f] != data)
1046 		{
1047 			drawlines(m_lastline, m_rasterline);
1048 			m_reg[offset & 0x1f] = data;
1049 			m_bitmapaddr = BITMAPADDR;
1050 			m_chargenaddr = CHARGENADDR;
1051 			DBG_LOG(3, "port_w", ("bitmap %.4x %s\n",  BITMAPADDR, INROM ? "rom" : "ram"));
1052 		}
1053 		break;
1054 	case 0xff13:
1055 		if (m_reg[offset & 0x1f] != data)
1056 		{
1057 			drawlines(m_lastline, m_rasterline);
1058 			m_reg[offset & 0x1f] = data;
1059 			m_chargenaddr = CHARGENADDR;
1060 			DBG_LOG(3, "port_w", ("chargen %.4x %s %d\n", CHARGENADDR, data & 2 ? "" : "doubleclock", data & 1));
1061 		}
1062 		break;
1063 	case 0xff14:
1064 		if (m_reg[offset & 0x1f] != data)
1065 		{
1066 			drawlines(m_lastline, m_rasterline);
1067 			m_reg[offset & 0x1f] = data;
1068 			m_videoaddr = VIDEOADDR;
1069 			DBG_LOG(3, "port_w", ("videoram %.4x\n", VIDEOADDR));
1070 		}
1071 		break;
1072 	case 0xff15:                         /* backgroundcolor */
1073 		if (m_reg[offset & 0x1f] != data)
1074 		{
1075 			drawlines(m_lastline, m_rasterline);
1076 			m_reg[offset & 0x1f] = data;
1077 			m_monoinversed[1] = m_mono[0] = m_bitmapmulti[0] = m_multi[0] = m_colors[0] = BACKGROUNDCOLOR;
1078 		}
1079 		break;
1080 	case 0xff16:                         /* foregroundcolor */
1081 		if (m_reg[offset & 0x1f] != data)
1082 		{
1083 			drawlines(m_lastline, m_rasterline);
1084 			m_reg[offset & 0x1f] = data;
1085 			m_bitmapmulti[3] = m_multi[1] = m_colors[1] = FOREGROUNDCOLOR;
1086 		}
1087 		break;
1088 	case 0xff17:                         /* multicolor 1 */
1089 		if (m_reg[offset & 0x1f] != data)
1090 		{
1091 			drawlines(m_lastline, m_rasterline);
1092 			m_reg[offset & 0x1f] = data;
1093 			m_multi[2] = m_colors[2] = MULTICOLOR1;
1094 		}
1095 		break;
1096 	case 0xff18:                         /* multicolor 2 */
1097 		if (m_reg[offset & 0x1f] != data)
1098 		{
1099 			drawlines(m_lastline, m_rasterline);
1100 			m_reg[offset & 0x1f] = data;
1101 			m_colors[3] = MULTICOLOR2;
1102 		}
1103 		break;
1104 	case 0xff19:                         /* framecolor */
1105 		if (m_reg[offset & 0x1f] != data)
1106 		{
1107 			drawlines(m_lastline, m_rasterline);
1108 			m_reg[offset & 0x1f] = data;
1109 			m_colors[4] = FRAMECOLOR;
1110 		}
1111 		break;
1112 	case 0xff1c:
1113 		m_reg[offset & 0x1f] = data;          /*? */
1114 		DBG_LOG(1, "port_w", ("write to rasterline high %.2x\n",
1115 										data));
1116 		break;
1117 	case 0xff1f:
1118 		m_reg[offset & 0x1f] = data;
1119 		DBG_LOG(1, "port_w", ("write to cursorblink %.2x\n", data));
1120 		break;
1121 	case 0xff3e:
1122 		m_rom = 1;
1123 		break;
1124 	case 0xff3f:
1125 		m_rom = 0;
1126 		break;
1127 	case 0xff1a:
1128 	case 0xff1b:
1129 	case 0xff1d:
1130 	case 0xff1e:
1131 		m_reg[offset & 0x1f] = data;
1132 		break;
1133 	}
1134 }
1135 
1136 
1137 //-------------------------------------------------
1138 //  update_screen - update screen
1139 //-------------------------------------------------
1140 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)1141 uint32_t mos7360_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1142 {
1143 	copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
1144 
1145 	return 0;
1146 }
1147 
frame_interrupt_gen()1148 void mos7360_device::frame_interrupt_gen()
1149 {
1150 	if ((m_reg[0x1f] & 0xf) >= 0x0f)
1151 	{
1152 		/*  if (m_frame_count >= CURSORRATE) */
1153 		m_cursor1 ^= 1;
1154 		m_reg[0x1f] &= ~0xf;
1155 		m_frame_count = 0;
1156 	}
1157 	else
1158 		m_reg[0x1f]++;
1159 }
1160 
raster_interrupt_gen()1161 void mos7360_device::raster_interrupt_gen()
1162 {
1163 	m_rasterline++;
1164 	m_rastertime = machine().time().as_double();
1165 	if (m_rasterline >= m_lines)
1166 	{
1167 		m_rasterline = 0;
1168 		drawlines(m_lastline, TED7360_LINES);
1169 		m_lastline = 0;
1170 	}
1171 
1172 	if (m_rasterline == C16_2_RASTERLINE(RASTERLINE))
1173 	{
1174 		drawlines(m_lastline, m_rasterline);
1175 		set_interrupt(2);
1176 	}
1177 }
1178 
1179 
1180 //-------------------------------------------------
1181 //  cs0_r - chip select 0 read
1182 //-------------------------------------------------
1183 
cs0_r(offs_t offset)1184 int mos7360_device::cs0_r(offs_t offset)
1185 {
1186 	if (m_rom && offset >= 0x8000 && offset < 0xc000)
1187 	{
1188 		return 0;
1189 	}
1190 
1191 	return 1;
1192 }
1193 
1194 
1195 //-------------------------------------------------
1196 //  cs1_r - chip select 1 read
1197 //-------------------------------------------------
1198 
cs1_r(offs_t offset)1199 int mos7360_device::cs1_r(offs_t offset)
1200 {
1201 	if (m_rom && ((offset >= 0xc000 && offset < 0xfd00) || (offset >= 0xff20)))
1202 	{
1203 		return 0;
1204 	}
1205 
1206 	return 1;
1207 }
1208