summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/mc68328lcd.cpp
blob: 1864fcab22cde5d14356b9f0e56d97c088b4bf69 (plain) (blame)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/******************************************************************************

    Generic LCD emulation for use with MC68328/MC68EZ328 devices

******************************************************************************/

#include "emu.h"

#include "mc68328lcd.h"

#include "screen.h"

DEFINE_DEVICE_TYPE(MC68328_LCD, mc68328_lcd_device, "mc68328_lcd", "MC68328-compatible LCD Controller")

mc68328_lcd_device::mc68328_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
	: device_t(mconfig, MC68328_LCD, tag, owner, clock)
	, device_palette_interface(mconfig, *this)
	, device_video_interface(mconfig, *this)
{
}

void mc68328_lcd_device::device_start()
{
	save_item(NAME(m_lcd_first_line));
	save_item(NAME(m_lcd_line_pulse));
	save_item(NAME(m_lcd_shift_clk));
	save_item(NAME(m_lcd_data));
	save_item(NAME(m_lcd_scan_x));
	save_item(NAME(m_lcd_scan_y));
	save_item(NAME(m_bus_width));
	save_item(NAME(m_bpp));

	palette_init();
}

void mc68328_lcd_device::device_reset()
{
	m_lcd_first_line = true;
	m_lcd_line_pulse = false;
	m_lcd_shift_clk = false;
	m_lcd_data = 0;
	m_lcd_scan_x = 0;
	m_lcd_scan_y = 0;
	m_bus_width = 4;
	m_bpp = 1;
}

void mc68328_lcd_device::palette_init()
{
	constexpr u8 LCD_OFF_R = 0xbd;
	constexpr u8 LCD_OFF_G = 0xbd;
	constexpr u8 LCD_OFF_B = 0xaa;
	constexpr u8 LCD_ON_R = 0x40;
	constexpr u8 LCD_ON_G = 0x40;
	constexpr u8 LCD_ON_B = 0x40;
	for (int i = 0; i < 16; i++)
	{
		const float lerp_factor = i / 15.f;
		const u8 blend_r = (u8)(LCD_OFF_R * (1.f - lerp_factor) + LCD_ON_R * lerp_factor);
		const u8 blend_g = (u8)(LCD_OFF_G * (1.f - lerp_factor) + LCD_ON_G * lerp_factor);
		const u8 blend_b = (u8)(LCD_OFF_B * (1.f - lerp_factor) + LCD_ON_B * lerp_factor);
		set_pen_color(i, blend_r, blend_g, blend_b);
	}
}

DECLARE_WRITE_LINE_MEMBER(mc68328_lcd_device::flm_w)
{
	m_lcd_first_line = state;
}

DECLARE_WRITE_LINE_MEMBER(mc68328_lcd_device::llp_w)
{
	const int old = m_lcd_line_pulse;
	m_lcd_line_pulse = state;
	if (!state && old)
	{
		if (m_lcd_first_line)
		{
			m_lcd_scan_y = 0;
		}
		else
		{
			m_lcd_scan_y++;
		}
		m_lcd_scan_x = 0;
	}
}

DECLARE_WRITE_LINE_MEMBER(mc68328_lcd_device::lsclk_w)
{
	const int old = m_lcd_shift_clk;
	m_lcd_shift_clk = state;
	if (state && !old)
	{
		for (u8 i = 0; i < m_bus_width && m_lcd_scan_x < m_lcd_bitmap.width() && m_lcd_scan_y < m_lcd_bitmap.height(); i += m_bpp)
		{
			u8 value = 0;
			switch (m_bpp)
			{
				case 1:
					value = BIT(m_lcd_data, (m_bus_width - 1) - i) * 15;
					break;
				case 2:
					value = ((m_lcd_data >> ((m_bus_width - 2) - i)) & 3) * 5;
					break;
				case 4:
					value = m_lcd_data & 15;
					break;
			}
			if (m_lcd_scan_x < m_lcd_bitmap.width() && m_lcd_scan_y < m_lcd_bitmap.height())
			{
				m_lcd_bitmap.pix(m_lcd_scan_y, m_lcd_scan_x) = pen_color(value);
			}
			m_lcd_scan_x++;
		}
	}
}

void mc68328_lcd_device::ld_w(u8 data)
{
	m_lcd_data = data;
}

void mc68328_lcd_device::lcd_info_changed(double refresh_hz, int width, int height, u8 bus_width, u8 bpp)
{
	if (has_screen())
	{
		screen().set_refresh_hz(refresh_hz);
	}
	m_lcd_bitmap.resize(width, height);
	m_bus_width = bus_width;
	m_bpp = bpp;
	m_lcd_scan_x = 0;
	m_lcd_scan_y = 0;
}

void mc68328_lcd_device::video_update(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
	bitmap.fill(pen_color(0));
	if (m_lcd_bitmap.valid())
	{
		u32 *src = &m_lcd_bitmap.pix(0);
		u32 *dst = &bitmap.pix(0);
		const int word_count = std::min(bitmap.width() * bitmap.height(), m_lcd_bitmap.width() * m_lcd_bitmap.height());
		std::copy_n(src, word_count, dst);
	}
}