summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/hp1ll3.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/hp1ll3.cpp')
-rw-r--r--src/devices/video/hp1ll3.cpp228
1 files changed, 156 insertions, 72 deletions
diff --git a/src/devices/video/hp1ll3.cpp b/src/devices/video/hp1ll3.cpp
index a8a9309e142..f71d9bdb855 100644
--- a/src/devices/video/hp1ll3.cpp
+++ b/src/devices/video/hp1ll3.cpp
@@ -19,13 +19,6 @@
- windows with blitter (copy, fill and scroll) and clipping
To do:
- . proper cursor and mouse pointers [cursor can be offset from the pen location]
- + variable width fonts [?? placed relative to current window]
- + basic lines
- - patterned lines
- . bit blits & scroll
- . meaning of WRRR bits
- . meaning of CONF data [+ autoconfiguration]
- interrupt generation
- realistic timing?
- &c.
@@ -145,9 +138,6 @@ constexpr uint16_t MSB_MASK = 0x8000; // Mask of MSB
} \
} while (0)
-// This is the size for 9807. To be made configurable.
-#define HPGPU_VRAM_SIZE 16384
-
// Index of words in configuration vector
enum : unsigned
{
@@ -161,18 +151,18 @@ enum : unsigned
CONF_VER_3 = 7, // Vertical timing, 4th word
CONF_WPL = 8, // Words per line
CONF_LINES = 9, // Lines
- CONF_RAM_SIZE = 10 // RAM size (?)
+ CONF_OPTS = 10 // RAM size or option bits (more likely)
};
// Fields of hor/ver timing words
enum : uint16_t
{
HV_CNT_MASK = 0x3ff, // Mask of counter part
- HV_ZONE_MASK = 0xc000, // Mask of zone part
- HV_ZONE_0 = 0x0000, // Value for zone 0
- HV_ZONE_1 = 0x4000, // Value for zone 1
- HV_ZONE_2 = 0x8000, // Value for zone 2
- HV_ZONE_3 = 0xc000 // Value for zone 3
+ HV_ZONE_MASK = 0xc00, // Mask of zone part
+ HV_ZONE_0 = 0x000, // Value for zone 0
+ HV_ZONE_1 = 0x400, // Value for zone 1
+ HV_ZONE_2 = 0x800, // Value for zone 2
+ HV_ZONE_3 = 0xc00 // Value for zone 3
};
//**************************************************************************
@@ -194,10 +184,10 @@ DEFINE_DEVICE_TYPE(HP1LL3, hp1ll3_device, "hp1ll3", "Hewlett-Packard 1LL3-0005 G
hp1ll3_device::hp1ll3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, HP1LL3, tag, owner, clock)
, device_video_interface(mconfig, *this)
+ , m_vram_size(16)
{
}
-
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -211,17 +201,17 @@ void hp1ll3_device::device_start()
screen().register_screen_bitmap(m_bitmap);
- m_videoram = std::make_unique<uint16_t[]>(HPGPU_VRAM_SIZE);
+ m_videoram = std::make_unique<uint16_t[]>(m_vram_size);
- save_pointer(NAME(m_videoram), HPGPU_VRAM_SIZE);
- m_ram_addr_mask = 0x3fff;
+ save_pointer(NAME(m_videoram) , m_vram_size);
+ m_ram_addr_mask = uint16_t(m_vram_size - 1);
m_horiz_pix_total = visarea.max_x + 1;
m_vert_pix_total = visarea.max_y + 1;
}
void hp1ll3_device::device_reset()
{
- m_io_ptr = m_command = 0;
+ m_rd_ptr = m_wr_ptr = m_command = 0;
m_sad = m_fad = m_dad = m_org = m_rr = m_udl = 0;
m_enable_video = m_enable_cursor = m_enable_sprite = m_busy = false;
}
@@ -357,13 +347,23 @@ void hp1ll3_device::line(int x1, int y1, int x2, int y2)
}
}
+void hp1ll3_device::get_font(uint16_t& font_data, uint16_t& font_height) const
+{
+ font_data = m_fad + rd_video(m_fad + 1) + 2;
+ font_height = rd_video(m_fad);
+}
+
void hp1ll3_device::label(uint8_t chr, int width)
{
draw_cursor_sprite();
+ uint16_t font_data;
+ uint16_t font_height;
+ get_font(font_data, font_height);
+
Rectangle clip = get_window();
- Rectangle dst{{ m_cursor_x, m_cursor_y }, { uint16_t(width), m_fontheight }};
- bitblt(m_fontdata + chr * 16, 16, 16, Point { 0, 0 }, clip, dst, m_rr);
+ Rectangle dst{{ m_cursor_x, m_cursor_y }, { uint16_t(width), font_height }};
+ bitblt(font_data + chr * 16, 16, 16, Point { 0, 0 }, clip, dst, m_rr);
m_cursor_x += width;
draw_cursor_sprite();
}
@@ -639,6 +639,18 @@ void hp1ll3_device::set_sprite_pos(Point p)
}
}
+void hp1ll3_device::disable_cursor()
+{
+ draw_cursor();
+ m_enable_cursor = false;
+}
+
+void hp1ll3_device::disable_sprite()
+{
+ draw_sprite();
+ m_enable_sprite = false;
+}
+
hp1ll3_device::Rectangle hp1ll3_device::get_window() const
{
return Rectangle{{ m_window.org_x, m_window.org_y }, { m_window.width, m_window.height }};
@@ -649,9 +661,49 @@ hp1ll3_device::Rectangle hp1ll3_device::get_screen() const
return Rectangle{{ 0, 0 }, { uint16_t(m_horiz_pix_total), uint16_t(m_vert_pix_total) }};
}
+void hp1ll3_device::get_hv_timing(bool vertical, unsigned& total, unsigned& active) const
+{
+ unsigned idx = vertical ? CONF_VER_0 : CONF_HOR_0;
+ // Look for active part (zone 1) & compute total time
+ total = 0;
+ active = 0;
+ for (unsigned i = 0; i < 4; ++i) {
+ unsigned cnt = (m_conf[idx + i] & HV_CNT_MASK) + 1;
+ total += cnt;
+ if ((m_conf[idx + i] & HV_ZONE_MASK) == HV_ZONE_1) {
+ active = cnt;
+ // It seems that if a zone 2 comes immediately before a zone 1, it's
+ // counted in the active part
+ unsigned idx_1 = (i + 3) % 4 + idx;
+ if ((m_conf[idx_1] & HV_ZONE_MASK) == HV_ZONE_2) {
+ active += (m_conf[idx_1] & HV_CNT_MASK) + 1;
+ }
+ }
+ }
+ DBG_LOG(2, 0, ("H/V=%d total=%u active=%u\n", vertical, total, active));
+}
+
void hp1ll3_device::apply_conf()
{
- // TODO:
+ unsigned h_total;
+ unsigned h_active;
+ unsigned v_total;
+ unsigned v_active;
+
+ get_hv_timing(false, h_total, h_active);
+ get_hv_timing(true, v_total, v_active);
+
+ // Dot clock is 4 times the GPU clock, H timings are in units of half the GPU clock
+ // I suspect that the GPU has a kind of "double clock" mode that is enabled by option bits in the last conf word.
+ // Without clock doubling, the HP-9808A video has a strange frame rate (~32Hz).
+ h_total *= 8;
+ h_active *= 8;
+
+ attotime frame_rate{clocks_to_attotime(h_total * v_total)};
+ screen().configure(h_total, v_total, rectangle{0, int32_t(h_active - 1), 0, int32_t(v_active - 1)}, frame_rate.attoseconds() / 4);
+
+ m_horiz_pix_total = h_active;
+ m_vert_pix_total = v_active;
}
uint32_t hp1ll3_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
@@ -662,10 +714,9 @@ uint32_t hp1ll3_device::screen_update(screen_device &screen, bitmap_ind16 &bitma
return 0;
}
- // XXX last line is not actually drawn on real hw
for (int y = 0; y < m_vert_pix_total; y++)
{
- int const offset = m_sad + y * (m_horiz_pix_total / 16);
+ int const offset = m_sad + y*m_conf[CONF_WPL];
uint16_t *p = &m_bitmap.pix16(y);
for (int x = offset; x < offset + m_horiz_pix_total / 16; x++)
@@ -723,7 +774,7 @@ READ8_MEMBER( hp1ll3_device::read )
}
else
{
- if (!(m_io_ptr & 1))
+ if (!(m_rd_ptr & 1))
{
switch (m_command)
{
@@ -762,19 +813,39 @@ READ8_MEMBER( hp1ll3_device::read )
break;
case RDP:
- if (m_io_ptr == 0)
+ if (m_rd_ptr == 0)
m_io_word = m_cursor_x;
- else if (m_io_ptr == 2)
+ else if (m_rd_ptr == 2)
m_io_word = m_cursor_y;
break;
case RDSP:
- if (m_io_ptr == 0)
+ if (m_rd_ptr == 0)
m_io_word = m_sprite_x;
- else if (m_io_ptr == 2)
+ else if (m_rd_ptr == 2)
m_io_word = m_sprite_y;
break;
+ case RDWINPARM:
+ switch (m_rd_ptr)
+ {
+ case 0:
+ m_io_word = m_window.org_x;
+ break;
+ case 2:
+ m_io_word = m_window.org_y;
+ break;
+ case 4:
+ m_io_word = m_window.width;
+ break;
+ case 6:
+ m_io_word = m_window.height;
+ break;
+ default:
+ break;
+ }
+ break;
+
case ID:
/*
* 'diagb' ROM accepts either of these ID values
@@ -788,7 +859,7 @@ READ8_MEMBER( hp1ll3_device::read )
{
data = m_io_word & 0xff;
}
- m_io_ptr++;
+ m_rd_ptr++;
}
DBG_LOG(1,"HPGPU", ("R @ %d == %02x\n", offset, data));
@@ -811,7 +882,7 @@ WRITE8_MEMBER( hp1ll3_device::write )
}
else
{
- if (!(m_io_ptr & 1))
+ if (!(m_wr_ptr & 1))
{
m_io_word = uint16_t(data) << 8;
}
@@ -821,11 +892,11 @@ WRITE8_MEMBER( hp1ll3_device::write )
switch (m_command)
{
case CONF:
- m_conf[m_io_ptr >> 1] = m_io_word;
- DBG_LOG(1,"HPGPU",("CONF data word %d received: %04X\n", m_io_ptr >> 1, m_io_word));
- if ((m_io_ptr >> 1) == 10) {
+ m_conf[m_wr_ptr >> 1] = m_io_word;
+ DBG_LOG(1,"HPGPU",("CONF data word %d received: %04X\n", m_wr_ptr >> 1, m_io_word));
+ if ((m_wr_ptr >> 1) == 10) {
apply_conf();
- m_io_ptr = -1;
+ m_wr_ptr = -1;
m_command = NOP;
}
break;
@@ -844,10 +915,7 @@ WRITE8_MEMBER( hp1ll3_device::write )
unsigned bit = m_rw_win_x % WS;
int width = m_window.width + m_window.org_x - m_rw_win_x;
if (width <= 0)
- {
m_command = NOP;
- draw_cursor_sprite();
- }
else
{
unsigned w = std::min(WS, unsigned(width));
@@ -871,22 +939,19 @@ WRITE8_MEMBER( hp1ll3_device::write )
m_rw_win_x = m_window.org_x;
m_rw_win_y++;
if (m_rw_win_y >= (m_window.height + m_window.org_y))
- {
m_command = NOP;
- draw_cursor_sprite();
- }
}
}
}
break;
default:
- if (m_io_ptr <= 4)
- m_input[m_io_ptr / 2] = m_io_word;
- DBG_LOG(2,"HPGPU",("wrote %02x at %d, input buffer is %04X %04X\n", data, m_io_ptr, m_input[0], m_input[1]));
+ if (m_wr_ptr <= 4)
+ m_input[m_wr_ptr / 2] = m_io_word;
+ DBG_LOG(2,"HPGPU",("wrote %02x at %d, input buffer is %04X %04X\n", data, m_wr_ptr, m_input[0], m_input[1]));
}
}
- m_io_ptr++;
+ m_wr_ptr++;
}
}
@@ -909,10 +974,6 @@ void hp1ll3_device::command(int command)
case WRMEM:
DBG_LOG(1,"HPGPU",("WRMEM of %d words to %04X complete\n", m_memory_ptr - m_input[0], m_input[0]));
break;
-
- case WRWIN:
- draw_cursor_sprite();
- break;
}
break;
@@ -930,8 +991,7 @@ void hp1ll3_device::command(int command)
case DISSP:
DBG_LOG(2,"HPGPU",("command: DISSP [%d, 0x%x]\n", command, command));
- draw_sprite();
- m_enable_sprite = false;
+ disable_sprite();
break;
case ENSP:
@@ -945,8 +1005,7 @@ void hp1ll3_device::command(int command)
case DISCURS:
DBG_LOG(2,"HPGPU",("command: DISCURS [%d, 0x%x]\n", command, command));
- draw_cursor();
- m_enable_cursor = false;
+ disable_cursor();
break;
// type 1 commands -- 1 word of data expected in the buffer
@@ -961,13 +1020,11 @@ void hp1ll3_device::command(int command)
case WRFAD:
DBG_LOG(2,"HPGPU",("command: WRFAD [%d, 0x%x] (0x%04x)\n", command, command, m_input[0]));
m_fad = m_input[0];
+ break;
// ?? used by diagnostic ROM
case 6:
- m_fontheight = rd_video(m_fad);
- m_fontdata = m_fad + rd_video(m_fad + 1) + 2;
- DBG_LOG(1,"HPGPU",("font data set: FAD %04X header %d bitmaps %04X height %d\n",
- m_fad, rd_video(m_fad + 1), m_fontdata, m_fontheight));
+ DBG_LOG(1,"HPGPU",("command: 6\n"));
break;
// start of data area
@@ -1018,19 +1075,15 @@ void hp1ll3_device::command(int command)
// Write window
case WRWIN:
- DBG_LOG(2,"HPGPU",("command: WRWIN [%d, 0x%x] offset=%u size(%d,%d)\n",command, command, m_input[0], m_window.width, m_window.height));
- // m_input[0] is offset (to be implemented)
- m_rw_win_x = m_window.org_x;
- m_rw_win_y = m_window.org_y;
- draw_cursor_sprite();
- break;
-
// Read window
case RDWIN:
- DBG_LOG(2,"HPGPU",("command: RDWIN [%d, 0x%x] offset=%u\n",command, command, m_input[0]));
+ DBG_LOG(2,"HPGPU",("command: %s [%d, 0x%x] offset=%u size(%d,%d)\n",
+ command == RDWIN ? "RDWIN":"WRWIN", command, command, m_input[0], m_window.width, m_window.height));
// m_input[0] is offset (to be implemented)
m_rw_win_x = m_window.org_x;
m_rw_win_y = m_window.org_y;
+ disable_cursor();
+ disable_sprite();
break;
// type 2 commands -- 2 words of data expected in the buffer
@@ -1079,6 +1132,13 @@ void hp1ll3_device::command(int command)
m_saved_x = m_cursor_x;
break;
+ // move pointer incremental
+ case IMOVEP:
+ DBG_LOG(2,"HPGPU",("command: IMOVEP [%d, 0x%x] (%d, %d)\n", command, command, m_input[0], m_input[1]));
+ set_pen_pos(Point{ uint16_t(m_cursor_x + m_input[0]), uint16_t(m_cursor_y + m_input[1]) });
+ m_saved_x = m_cursor_x;
+ break;
+
// Scroll UP
case SCROLUP:
{
@@ -1087,7 +1147,8 @@ void hp1ll3_device::command(int command)
Point src_p{ m_window.org_x, uint16_t(m_window.org_y + m_input[1]) };
Rectangle dst_rect = get_window();
dst_rect.size.y -= m_input[1];
- bitblt(m_org, m_horiz_pix_total, m_vert_pix_total, src_p, get_window(), dst_rect, m_rr);
+ unsigned rounded_width = m_conf[CONF_WPL] * WS;
+ bitblt(m_org, rounded_width, m_vert_pix_total, src_p, get_window(), dst_rect, m_rr);
dst_rect.origin.y += dst_rect.size.y;
dst_rect.size.y = m_input[1];
fill(dst_rect, m_input[0]);
@@ -1104,7 +1165,8 @@ void hp1ll3_device::command(int command)
Rectangle dst_rect = get_window();
dst_rect.origin.y += m_input[1];
dst_rect.size.y -= m_input[1];
- bitblt(m_org, m_horiz_pix_total, m_vert_pix_total, src_p, get_window(), dst_rect, m_rr);
+ unsigned rounded_width = m_conf[CONF_WPL] * WS;
+ bitblt(m_org, rounded_width, m_vert_pix_total, src_p, get_window(), dst_rect, m_rr);
dst_rect.origin.y = m_window.org_y;
dst_rect.size.y = m_input[1];
fill(dst_rect, m_input[0]);
@@ -1124,8 +1186,15 @@ void hp1ll3_device::command(int command)
// carriage return, line feed
case CRLFx:
- DBG_LOG(2,"HPGPU",("command: CRLF [%d, 0x%x] (%d, %d)\n", command, command, m_input[0], m_input[1]));
- set_pen_pos(Point{ m_saved_x, uint16_t(m_cursor_y + m_fontheight) });
+ {
+ DBG_LOG(2,"HPGPU",("command: CRLF [%d, 0x%x]\n", command, command));
+
+ uint16_t font_data;
+ uint16_t font_height;
+ get_font(font_data, font_height);
+
+ set_pen_pos(Point{ m_saved_x, uint16_t(m_cursor_y + font_height) });
+ }
break;
// move sprite absolute
@@ -1154,11 +1223,25 @@ void hp1ll3_device::command(int command)
DBG_LOG(2,"HPGPU",("command: %s [%d, 0x%x] (0x%04x)\n",
command == RDMEM?"RDMEM":"WRMEM", command, command, m_input[0]));
m_memory_ptr = m_input[0]; // memory is word-addressable
+ disable_cursor();
+ disable_sprite();
break;
// type 3 read commands
case RDP:
+ DBG_LOG(2,"HPGPU",("command: RDP [%d, 0x%x]\n", command, command));
+ break;
+
case RDSP:
+ DBG_LOG(2,"HPGPU",("command: RDSP [%d, 0x%x]\n", command, command));
+ break;
+
+ case RDWINPARM:
+ DBG_LOG(2,"HPGPU",("command: RDWINPARM [%d, 0x%x]\n", command, command));
+ break;
+
+ case ID:
+ DBG_LOG(2,"HPGPU",("command: ID [%d, 0x%x]\n", command, command));
break;
default:
@@ -1166,6 +1249,7 @@ void hp1ll3_device::command(int command)
break;
}
- m_io_ptr = 0;
+ m_rd_ptr = 0;
+ m_wr_ptr = 0;
m_command = command;
}