vta2000: Convert video rendering to use 8275 CRTCs fed by 8257 DMAC; add various other peripherals and interrupts. (Display has become slightly glitchy, but there is a cursor now.)

This commit is contained in:
AJR 2024-01-28 20:09:32 -05:00
parent 0732db9d07
commit 332ae0e29a

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Robbbert
// copyright-holders:Robbbert, AJR
/***************************************************************************
VTA-2000 Terminal
@ -23,9 +23,12 @@ Note: port 0 bit 4 is NOT a speaker bit. See code at 027B.
#include "emu.h"
#include "cpu/i8085/i8085.h"
#include "machine/i8251.h"
#include "machine/i8255.h"
#include "machine/i8257.h"
#include "machine/pit8253.h"
#include "machine/pic8259.h"
#include "sound/spkrdev.h"
#include "video/i8275.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
@ -40,29 +43,59 @@ public:
, m_maincpu(*this, "maincpu")
, m_mainpit(*this, "mainpit")
, m_speaker(*this, "speaker")
, m_crtc(*this, "crtc%u", 0U)
, m_p_videoram(*this, "videoram")
, m_p_chargen(*this, "chargen")
{ }
void vta2000(machine_config &config);
private:
uint8_t memory_r(offs_t offset);
void crtc_dack_w(offs_t offset, uint8_t data);
uint8_t crtc_r(offs_t offset);
void crtc_w(offs_t offset, uint8_t data);
void output_00(uint8_t data);
void speaker_w(int state);
uint8_t m_framecnt = 0;
uint32_t screen_update_vta2000(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
I8275_DRAW_CHARACTER_MEMBER(draw_character);
void mem_map(address_map &map);
void io_map(address_map &map);
virtual void machine_reset() override;
required_device<i8085a_cpu_device> m_maincpu;
required_device<pit8253_device> m_mainpit;
required_device<speaker_sound_device> m_speaker;
required_device_array<i8275_device, 2> m_crtc;
required_shared_ptr<uint8_t> m_p_videoram;
required_region_ptr<u8> m_p_chargen;
};
uint8_t vta2000_state::memory_r(offs_t offset)
{
return m_maincpu->space(AS_PROGRAM).read_byte(offset ^ 1);
}
void vta2000_state::crtc_dack_w(offs_t offset, uint8_t data)
{
if (BIT(offset, 0))
m_crtc[0]->dack_w(data);
m_crtc[1]->dack_w(data | 0x80);
}
uint8_t vta2000_state::crtc_r(offs_t offset)
{
(void)m_crtc[1]->read(offset);
return m_crtc[0]->read(offset);
}
void vta2000_state::crtc_w(offs_t offset, uint8_t data)
{
m_crtc[0]->write(offset, data);
m_crtc[1]->write(offset, data);
}
void vta2000_state::output_00(uint8_t data)
{
m_mainpit->write_gate0(BIT(data, 4));
@ -78,7 +111,7 @@ void vta2000_state::mem_map(address_map &map)
map.unmap_value_high();
map(0x0000, 0x5fff).rom().region("roms", 0);
map(0x8000, 0xc7ff).ram().share("videoram");
map(0xc800, 0xc8ff).rom().region("roms", 0x5000);
map(0xc800, 0xc8ff).rom().region("roms", 0x5000); // FIXME: KR1601RR1 EAROM should be mapped here instead
}
void vta2000_state::io_map(address_map &map)
@ -86,9 +119,12 @@ void vta2000_state::io_map(address_map &map)
map.unmap_value_high();
map(0x00, 0x00).w(FUNC(vta2000_state::output_00));
map(0x20, 0x21).rw("pic", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
map(0x80, 0x88).rw("dmac", FUNC(i8257_device::read), FUNC(i8257_device::write));
map(0xa0, 0xa1).rw(FUNC(vta2000_state::crtc_r), FUNC(vta2000_state::crtc_w));
map(0xc0, 0xc0).rw("usart", FUNC(i8251_device::data_r), FUNC(i8251_device::data_w));
map(0xc3, 0xc3).rw("usart", FUNC(i8251_device::status_r), FUNC(i8251_device::control_w));
map(0xc8, 0xcb).w("brgpit", FUNC(pit8253_device::write));
map(0xd0, 0xd3).rw("ppi", FUNC(i8255_device::read), FUNC(i8255_device::write));
map(0xe0, 0xe3).rw("mainpit", FUNC(pit8253_device::read), FUNC(pit8253_device::write));
}
@ -97,84 +133,35 @@ static INPUT_PORTS_START( vta2000 )
INPUT_PORTS_END
void vta2000_state::machine_reset()
I8275_DRAW_CHARACTER_MEMBER(vta2000_state::draw_character)
{
}
using namespace i8275_attributes;
uint32_t vta2000_state::screen_update_vta2000(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
/* Cursor is missing. */
{
uint16_t sy=0,ma=0;
uint8_t dots = 0;
if (BIT(attrcode, LTEN + 8))
dots = 0xff;
else if (!BIT(attrcode, VSP + 8))
dots = m_p_chargen[BIT(attrcode, HLGT + 8) << 12 | (charcode & 0x7f) << 4 | linecount];
if (BIT(attrcode, RVV + 8))
dots = ~dots;
m_framecnt++;
for (uint8_t y = 0; y < 25; y++)
{
for (uint8_t ra = 0; ra < 12; ra++)
{
uint16_t *p = &bitmap.pix(sy++);
uint16_t xx = ma << 1;
for (uint16_t x = ma; x < ma + 80; x++)
{
uint16_t chr = m_p_videoram[xx++];
uint8_t const attr = m_p_videoram[xx++];
if ((chr & 0x60)==0x60)
chr+=256;
uint8_t gfx = m_p_chargen[(chr<<4) | ra ];
uint8_t fg, bg = 0;
/* Process attributes */
if (BIT(attr, 4))
{
gfx ^= 0xff; // reverse video
bg = 2;
}
if (BIT(attr, 0))
fg = 2; // highlight
else
fg = 1;
if ((BIT(attr, 1)) && (BIT(m_framecnt, 5)))
gfx = 0; // blink
if ((BIT(attr, 5)) && (ra == 10))
{
gfx = 0xff; // underline
fg = 2;
}
/* 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;
}
}
if (y)
ma+=132;
else
ma+=80;
}
return 0;
uint32_t *p = &bitmap.pix(y, x);
for (int i = 0; i < 8; i++)
p[i] = BIT(dots, 7 - i) ? rgb_t::white() : rgb_t::black();
}
/* F4 Character Displayer */
static const gfx_layout vta2000_charlayout =
{
8, 16, /* 8 x 16 characters */
512, /* 128 characters */
8, 12, /* 8 x 12 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, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 },
{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8, 10*8, 11*8 },
8*16 /* every char takes 16 bytes */
};
@ -184,22 +171,31 @@ GFXDECODE_END
void vta2000_state::vta2000(machine_config &config)
{
//constexpr auto CPU_CLOCK = XTAL(4'000'000) / 4; // too slow for CRTC DMA
constexpr auto CPU_CLOCK = 2'000'000;
constexpr auto DOT_CLOCK = 12'500'000; // guessed
/* basic machine hardware */
I8080(config, m_maincpu, XTAL(4'000'000) / 4);
I8080(config, m_maincpu, CPU_CLOCK);
m_maincpu->set_addrmap(AS_PROGRAM, &vta2000_state::mem_map);
m_maincpu->set_addrmap(AS_IO, &vta2000_state::io_map);
m_maincpu->in_inta_func().set("pic", FUNC(pic8259_device::acknowledge));
//KR1601RR1(config, "earom", 0);
PIT8253(config, m_mainpit, 0);
m_mainpit->set_clk<0>(500'000);
m_mainpit->out_handler<0>().set(FUNC(vta2000_state::speaker_w));
m_mainpit->set_clk<2>(500'000);
m_mainpit->out_handler<2>().set("pic", FUNC(pic8259_device::ir7_w));
pic8259_device &pic(PIC8259(config, "pic", 0));
pic.in_sp_callback().set_constant(0);
pic.out_int_callback().set_inputline(m_maincpu, 0);
i8251_device &usart(I8251(config, "usart", XTAL(4'000'000) / 4));
i8251_device &usart(I8251(config, "usart", CPU_CLOCK));
usart.rxrdy_handler().set("pic", FUNC(pic8259_device::ir4_w));
usart.syndet_handler().set("pic", FUNC(pic8259_device::ir1_w));
pit8253_device &brgpit(PIT8253(config, "brgpit", 0));
brgpit.set_clk<0>(1'228'800); // maybe
@ -207,14 +203,32 @@ void vta2000_state::vta2000(machine_config &config)
brgpit.out_handler<0>().set("usart", FUNC(i8251_device::write_rxc));
brgpit.out_handler<1>().set("usart", FUNC(i8251_device::write_txc)); // or vice versa?
i8255_device &ppi(I8255(config, "ppi"));
ppi.in_pc_callback().set_constant(0xe0);
i8257_device &dmac(I8257(config, "dmac", CPU_CLOCK));
dmac.out_hrq_cb().set_inputline(m_maincpu, INPUT_LINE_HALT);
dmac.out_hrq_cb().append("dmac", FUNC(i8257_device::hlda_w));
dmac.out_tc_cb().set("pic", FUNC(pic8259_device::ir2_w)).invert();
dmac.in_memr_cb().set(FUNC(vta2000_state::memory_r));
dmac.out_iow_cb<2>().set(FUNC(vta2000_state::crtc_dack_w));
/* video hardware */
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER, rgb_t::green()));
screen.set_refresh_hz(50);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
screen.set_size(80*8, 25*12);
screen.set_visarea(0, 80*8-1, 0, 25*12-1);
screen.set_screen_update(FUNC(vta2000_state::screen_update_vta2000));
screen.set_palette("palette");
screen.set_raw(DOT_CLOCK, 800, 0, 640, 312, 0, 300);
screen.set_screen_update(m_crtc[0], FUNC(i8275_device::screen_update));
//screen.set_palette("palette");
for (auto &crtc : m_crtc)
{
I8275(config, crtc, DOT_CLOCK / 8);
crtc->set_character_width(8);
crtc->set_screen("screen");
}
m_crtc[0]->set_display_callback(FUNC(vta2000_state::draw_character));
m_crtc[0]->drq_wr_callback().set("dmac", FUNC(i8257_device::dreq2_w));
m_crtc[0]->irq_wr_callback().set("pic", FUNC(pic8259_device::ir6_w));
m_crtc[0]->set_next_crtc(m_crtc[1]);
PALETTE(config, "palette", palette_device::MONOCHROME_HIGHLIGHT);
GFXDECODE(config, "gfxdecode", "palette", gfx_vta2000);