abc80: Emulate the TKN 80 80-column expansion kit. [Curt Coder]

abc80: Add system ROMs with checksum 10042. [PC/M]
This commit is contained in:
Curt Coder 2023-04-02 13:06:35 +03:00
parent 41cd0bf725
commit 0315a8b918
3 changed files with 576 additions and 108 deletions

View File

@ -24,15 +24,15 @@ PCB Layout
| | Z80A PIO | | Z80A | |
| |--------------| |------------| LS04 LS74A LS86 LS161 LS166 74393 |
| |
| ROM3 LS107 4116 4116 LS10 LS257 LS74A LS08 LS107 PROM2 |
| ROM0 LS107 4116 4116 LS10 LS257 LS74A LS08 LS107 PROM2 |
| |
| ROM2 LS257 4116 4116 LS139 74393 LS107 LS32 LS175 74393 |
| |
| ROM1 LS257 4116 4116 LS08 LS283 LS10 LS32 PROM1 74393 |
| |
| ROM0 LS257 4116 4116 LS257 74393 LS375 74S263 LS145 PROM4 |
| ROM3 LS257 4116 4116 LS257 74393 LS375 74S263 LS145 PROM4 |
| |
| DIPSW1 DIPSW2 4045 4045 LS257 LS245 LS375 LS273 LS166 PROM3 |
| SB1 SB2 4045 4045 LS257 LS245 LS375 LS273 LS166 PROM3 |
|--------------------------------------------------------------------------------------|
Notes:
@ -56,14 +56,74 @@ Notes:
CN5 - cassette connector
CN6 - keyboard connector
SW1 - reset switch
DIPSW1 -
DIPSW2 -
SB1 - solder bridge for A11/CS1 to ROM1/ROM3
SB2 - solder bridge for A11/CS1 to ROM0/ROM2
Calculate ROM checksum:
10 FOR I%=0% TO 16383%
20 A%=A%+PEEK(I%)
30 NEXT I%
40 ;A%
RUN
*/
/*
Luxor ABC 80 with TKN 80
PCB Layout
----------
55 10470-02
CN1 CN2 CN5
SW1 |-----| |------------------------| |-----|
|-------| |--| |----------------------------------| |---|
| CN3 CN4 |
| 7912 |
| MC1488 |
| MC1489 7812 |
| LS245 LS138 |
| |-------| |
| |-----CN6-----| LS241 LS241 LS138 LS32 |SN76477| LS04 LM339 |
| |-------| |
| |--------------| |------------| PROM0 LS132 LS273 7406 LS08 |
| | Z80A PIO | | Z80A | |
| |--------------| |------------| LS04 LS74A LS86 LS161 LS166 74393 |
| |
| ROM0 LS107 4116 4116 LS10 LS257 LS74A LS08 LS107 PROM2 |
| |
| ROM2 LS257 4116 4116 LS139 74393 LS107 LS32 LS175 74393 |
| |
| ROM1 LS257 4116 4116 LS08 LS283 LS10 LS32 PROM1 74393 |
|-----------| |
| ROM3 | |------------------------------------------------|LS145 PROM4 |
| |-------| | |
| LS32 LS00 LS257 LS257 LS257 LS00 LS04 LS02 LS51 LS374 |LS166 PROM3 |
| |-----------------|
| ROM4 LS373 LS244 6116 LS74A LS74A LS163 LS163 LS374 |
| LS374 |
|--------------------------------------------------------------------|
Notes:
All IC's shown.
PROM0 - MMI 63S141N 512x4 TTL Bipolar PROM
ROM4 - 4Kx8 EPROM "TKN80-III"
6116 - Hitachi HM6116P-4 2Kx8 Static RAM
Switch to 40 column mode:
;INP(3);CHR$(12)
Switch to 80 column mode:
;INP(4);CHR$(12)
ROM checksum program:
10 FOR I%=0% TO 16383%
20 A%=A%+PEEK(I%)
30 NEXT I%
40 ;A%; I%
*/
/*
@ -72,11 +132,11 @@ ROM checksum program:
- PWM sound in ABC-klubben/abc80/grafik/flagga.bac
- proper keyboard controller emulation
- MyAB TKN80 80-column card
- GeJo 80-column card
- Mikrodatorn 64K expansion
- 64K RAM expansions
- Mikrodatorn
- MYAB UNI-80
- Metric ABC CAD 1000
- ROMs with checksum 10042
*/
@ -128,6 +188,62 @@ u8 abc80_state::read(offs_t offset)
return data;
}
u8 tkn80_state::read(offs_t offset)
{
/*
TKN 000-3ff -> ZA3506 000-3ff (9913/10042)
TKN 400-7ff -> ZA3507 000-3ff (9913/10042)
TKN 800-cff -> ZA3506 000-3ff (11273)
TKN c00-FFF -> ZA3507 000-3ff (11273)
*/
u8 data = 0xff;
u8 mmu = m_mmu_rom->base()[0x40 | (offset >> 10)];
if (offset < 0x400)
{
if (m_80)
data = m_rom_e->base()[m_rom_offset | (offset & 0x3ff)];
else
data = m_rom->base()[offset & 0x3fff];
}
else if (offset >= 0x400 && offset < 0x2000)
{
data = m_rom->base()[offset & 0x3fff];
}
else if (offset >= 0x2000 && offset < 0x2400)
{
if (m_80)
data = m_rom_e->base()[m_rom_offset | 0x400 | (offset & 0x3ff)];
else
data = m_rom->base()[offset & 0x3fff];
}
else if (offset >= 0x2400 && offset < 0x4000)
{
data = m_rom->base()[offset & 0x3fff];
}
else if (offset >= 0x5800 && offset < 0x6000)
{
data = m_char_ram[offset & 0x7ff];
}
else if (offset >= 0x7c00 && offset < 0x8000)
{
data = m_char_ram[offset & 0x7ff];
}
else if (!(mmu & MMU_XM))
{
data = m_bus->xmemfl_r(offset);
}
else if (!(mmu & MMU_RAM))
{
data = m_ram->pointer()[offset & 0x3fff];
}
return data;
}
//-------------------------------------------------
// write -
@ -151,6 +267,28 @@ void abc80_state::write(offs_t offset, u8 data)
}
}
void tkn80_state::write(offs_t offset, u8 data)
{
u8 mmu = m_mmu_rom->base()[0x40 | (offset >> 10)];
if (offset >= 0x5800 && offset < 0x6000)
{
m_char_ram[offset & 0x7ff] = data;
}
else if (offset >= 0x7c00 && offset < 0x8000)
{
m_char_ram[offset & 0x7ff] = data;
}
else if (!(mmu & MMU_XM))
{
m_bus->xmemw_w(offset, data);
}
else if (!(mmu & MMU_RAM))
{
m_ram->pointer()[offset & 0x3fff] = data;
}
}
//**************************************************************************
@ -210,6 +348,41 @@ void abc80_state::abc80_io(address_map &map)
}
//-------------------------------------------------
// ADDRESS_MAP( tkn80_io )
//-------------------------------------------------
void tkn80_state::tkn80_io(address_map &map)
{
abc80_io(map);
map(0x03, 0x03).r(FUNC(tkn80_state::in3_r));
map(0x04, 0x04).r(FUNC(tkn80_state::in4_r));
}
//**************************************************************************
// INPUT PORTS
//**************************************************************************
//-------------------------------------------------
// INPUT_PORTS( tkn80 )
//-------------------------------------------------
static INPUT_PORTS_START( tkn80 )
PORT_START("CONFIG")
PORT_CONFNAME( 0x01, 0x01, "Columns" )
PORT_CONFSETTING( 0x00, "40" )
PORT_CONFSETTING( 0x01, "80" )
PORT_CONFNAME( 0x02, 0x02, "Cursor" )
PORT_CONFSETTING( 0x00, "Static" )
PORT_CONFSETTING( 0x02, "Blinking" )
PORT_CONFNAME( 0x04, 0x00, "ROM Checksum" )
PORT_CONFSETTING( 0x00, "9913/10042" )
PORT_CONFSETTING( 0x04, "11273" )
INPUT_PORTS_END
//**************************************************************************
// DEVICE CONFIGURATION
@ -454,12 +627,39 @@ void abc80_state::machine_start()
save_item(NAME(m_tape_in));
save_item(NAME(m_tape_in_latch));
//zero-fill
// zero-fill
m_key_data = 0;
m_key_strobe = 0;
m_blink = 0;
}
void tkn80_state::machine_start()
{
abc80_state::machine_start();
// register for state saving
save_item(NAME(m_80));
save_item(NAME(m_rom_offset));
}
//-------------------------------------------------
// machine_reset
//-------------------------------------------------
void tkn80_state::machine_reset()
{
u8 config = m_config->read();
m_rom_offset = BIT(config, 2) << 11;
}
//-------------------------------------------------
// QUICKLOAD_LOAD_MEMBER( quickload_cb )
//-------------------------------------------------
QUICKLOAD_LOAD_MEMBER(abc80_state::quickload_cb)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
@ -493,10 +693,10 @@ QUICKLOAD_LOAD_MEMBER(abc80_state::quickload_cb)
//**************************************************************************
//-------------------------------------------------
// machine_config( abc80 )
// machine_config( abc80_common )
//-------------------------------------------------
void abc80_state::abc80(machine_config &config)
void abc80_state::abc80_common(machine_config &config)
{
// basic machine hardware
Z80(config, m_maincpu, XTAL(11'980'800)/2/2); // 2.9952 MHz
@ -504,9 +704,6 @@ void abc80_state::abc80(machine_config &config)
m_maincpu->set_addrmap(AS_IO, &abc80_state::abc80_io);
m_maincpu->set_daisy_config(abc80_daisy_chain);
// video hardware
abc80_video(config);
// sound hardware
SPEAKER(config, "mono").front_center();
SN76477(config, m_csg);
@ -553,6 +750,30 @@ void abc80_state::abc80(machine_config &config)
SOFTWARE_LIST(config, "rom_list").set_original("abc80_rom");
}
void abc80_state::abc80(machine_config &config)
{
abc80_state::abc80_common(config);
// video hardware
abc80_video(config);
}
//-------------------------------------------------
// machine_config( tkn80 )
//-------------------------------------------------
void tkn80_state::tkn80(machine_config &config)
{
abc80_state::abc80_common(config);
// basic machine hardware
m_maincpu->set_addrmap(AS_IO, &tkn80_state::tkn80_io);
// video hardware
tkn80_video(config);
}
//**************************************************************************
@ -567,15 +788,20 @@ ROM_START( abc80 )
ROM_REGION( 0x4000, Z80_TAG, 0 )
ROM_DEFAULT_BIOS("9913")
ROM_SYSTEM_BIOS( 0, "11273", "Checksum 11273" )
ROMX_LOAD( "3506_3.a5", 0x0000, 0x1000, CRC(7c004fb6) SHA1(9aee1d085122f4537c3e6ecdab9d799bd429ef52), ROM_BIOS(0) )
ROMX_LOAD( "3507_3.a3", 0x1000, 0x1000, CRC(d1850a84) SHA1(f7719f3af9173601a2aa23ae38ae00de1a387ad8), ROM_BIOS(0) )
ROMX_LOAD( "3508_3.a4", 0x2000, 0x1000, CRC(b55528e9) SHA1(3e5017e8cacad1f13215242f1bbd89d1d3eee131), ROM_BIOS(0) )
ROMX_LOAD( "3509_3.a2", 0x3000, 0x1000, CRC(659cab1e) SHA1(181db748cef22cdcccd311a60aa6189c85343db7), ROM_BIOS(0) )
ROM_SYSTEM_BIOS( 1, "9913", "Checksum 9913" )
ROMX_LOAD( "3506_3_v2.a5", 0x0000, 0x1000, CRC(e2afbf48) SHA1(9883396edd334835a844dcaa792d29599a8c67b9), ROM_BIOS(1) )
ROMX_LOAD( "3507_3_v2.a3", 0x1000, 0x1000, CRC(d224412a) SHA1(30968054bba7c2aecb4d54864b75a446c1b8fdb1), ROM_BIOS(1) )
ROMX_LOAD( "3508_3_v2.a4", 0x2000, 0x1000, CRC(1502ba5b) SHA1(5df45909c2c4296e5701c6c99dfaa9b10b3a729b), ROM_BIOS(1) )
ROMX_LOAD( "3509_3_v2.a2", 0x3000, 0x1000, CRC(bc8860b7) SHA1(28b6cf7f5a4f81e017c2af091c3719657f981710), ROM_BIOS(1) )
ROMX_LOAD( "za3506_11273.a5", 0x0000, 0x1000, CRC(7c004fb6) SHA1(9aee1d085122f4537c3e6ecdab9d799bd429ef52), ROM_BIOS(0) )
ROMX_LOAD( "za3507_11273.a3", 0x1000, 0x1000, CRC(d1850a84) SHA1(f7719f3af9173601a2aa23ae38ae00de1a387ad8), ROM_BIOS(0) )
ROMX_LOAD( "za3508_11273.a4", 0x2000, 0x1000, CRC(b55528e9) SHA1(3e5017e8cacad1f13215242f1bbd89d1d3eee131), ROM_BIOS(0) )
ROMX_LOAD( "za3509_11273.a2", 0x3000, 0x1000, CRC(659cab1e) SHA1(181db748cef22cdcccd311a60aa6189c85343db7), ROM_BIOS(0) )
ROM_SYSTEM_BIOS( 1, "10042", "Checksum 10042" )
ROMX_LOAD( "za3506_9913.a5", 0x0000, 0x1000, CRC(e2afbf48) SHA1(9883396edd334835a844dcaa792d29599a8c67b9), ROM_BIOS(1) )
ROMX_LOAD( "za3507_9913.a3", 0x1000, 0x1000, CRC(d224412a) SHA1(30968054bba7c2aecb4d54864b75a446c1b8fdb1), ROM_BIOS(1) )
ROMX_LOAD( "za3508_9913.a4", 0x2000, 0x1000, CRC(1502ba5b) SHA1(5df45909c2c4296e5701c6c99dfaa9b10b3a729b), ROM_BIOS(1) )
ROMX_LOAD( "za3509_10042.a2", 0x3000, 0x1000, CRC(346f0cdb) SHA1(4262137cff9dfc82c5bd5727994ed5f9b7d22395), ROM_BIOS(1) )
ROM_SYSTEM_BIOS( 2, "9913", "Checksum 9913" )
ROMX_LOAD( "za3506_9913.a5", 0x0000, 0x1000, CRC(e2afbf48) SHA1(9883396edd334835a844dcaa792d29599a8c67b9), ROM_BIOS(2) )
ROMX_LOAD( "za3507_9913.a3", 0x1000, 0x1000, CRC(d224412a) SHA1(30968054bba7c2aecb4d54864b75a446c1b8fdb1), ROM_BIOS(2) )
ROMX_LOAD( "za3508_9913.a4", 0x2000, 0x1000, CRC(1502ba5b) SHA1(5df45909c2c4296e5701c6c99dfaa9b10b3a729b), ROM_BIOS(2) )
ROMX_LOAD( "za3509_9913.a2", 0x3000, 0x1000, CRC(bc8860b7) SHA1(28b6cf7f5a4f81e017c2af091c3719657f981710), ROM_BIOS(2) )
ROM_REGION( 0x100, "hsync", 0 )
ROM_LOAD( "abc80_11.k5", 0x0000, 0x0100, CRC(e4f7e018) SHA1(63e718a39537f37286ea183e6469808c271dbfa5) ) // "64 40029-01" 82S129 256x4 horizontal sync
@ -599,12 +825,26 @@ ROM_END
//-------------------------------------------------
ROM_START( tkn80 )
ROM_REGION( 0x5000, Z80_TAG, 0 )
ROM_LOAD( "3506_3_v2.a5", 0x0000, 0x1000, CRC(e2afbf48) SHA1(9883396edd334835a844dcaa792d29599a8c67b9) )
ROM_LOAD( "3507_3_v2.a3", 0x1000, 0x1000, CRC(d224412a) SHA1(30968054bba7c2aecb4d54864b75a446c1b8fdb1) )
ROM_LOAD( "3508_3_v2.a4", 0x2000, 0x1000, CRC(1502ba5b) SHA1(5df45909c2c4296e5701c6c99dfaa9b10b3a729b) )
ROM_LOAD( "3509_3_v2.a2", 0x3000, 0x1000, CRC(bc8860b7) SHA1(28b6cf7f5a4f81e017c2af091c3719657f981710) )
ROM_LOAD( "tkn80-iii", 0x4000, 0x1000, CRC(f0d2e4fa) SHA1(b0263c65db39667a6fe62e61f73fe591ea10f14b) )
ROM_REGION( 0x4000, Z80_TAG, 0 )
ROM_DEFAULT_BIOS("9913")
ROM_SYSTEM_BIOS( 0, "11273", "Checksum 11273" )
ROMX_LOAD( "za3506_11273.a5", 0x0000, 0x1000, CRC(7c004fb6) SHA1(9aee1d085122f4537c3e6ecdab9d799bd429ef52), ROM_BIOS(0) )
ROMX_LOAD( "za3507_11273.a3", 0x1000, 0x1000, CRC(d1850a84) SHA1(f7719f3af9173601a2aa23ae38ae00de1a387ad8), ROM_BIOS(0) )
ROMX_LOAD( "za3508_11273.a4", 0x2000, 0x1000, CRC(b55528e9) SHA1(3e5017e8cacad1f13215242f1bbd89d1d3eee131), ROM_BIOS(0) )
ROMX_LOAD( "za3509_11273.a2", 0x3000, 0x1000, CRC(659cab1e) SHA1(181db748cef22cdcccd311a60aa6189c85343db7), ROM_BIOS(0) )
ROM_SYSTEM_BIOS( 1, "10042", "Checksum 10042" )
ROMX_LOAD( "za3506_9913.a5", 0x0000, 0x1000, CRC(e2afbf48) SHA1(9883396edd334835a844dcaa792d29599a8c67b9), ROM_BIOS(1) )
ROMX_LOAD( "za3507_9913.a3", 0x1000, 0x1000, CRC(d224412a) SHA1(30968054bba7c2aecb4d54864b75a446c1b8fdb1), ROM_BIOS(1) )
ROMX_LOAD( "za3508_9913.a4", 0x2000, 0x1000, CRC(1502ba5b) SHA1(5df45909c2c4296e5701c6c99dfaa9b10b3a729b), ROM_BIOS(1) )
ROMX_LOAD( "za3509_10042.a2", 0x3000, 0x1000, CRC(346f0cdb) SHA1(4262137cff9dfc82c5bd5727994ed5f9b7d22395), ROM_BIOS(1) )
ROM_SYSTEM_BIOS( 2, "9913", "Checksum 9913" )
ROMX_LOAD( "za3506_9913.a5", 0x0000, 0x1000, CRC(e2afbf48) SHA1(9883396edd334835a844dcaa792d29599a8c67b9), ROM_BIOS(2) )
ROMX_LOAD( "za3507_9913.a3", 0x1000, 0x1000, CRC(d224412a) SHA1(30968054bba7c2aecb4d54864b75a446c1b8fdb1), ROM_BIOS(2) )
ROMX_LOAD( "za3508_9913.a4", 0x2000, 0x1000, CRC(1502ba5b) SHA1(5df45909c2c4296e5701c6c99dfaa9b10b3a729b), ROM_BIOS(2) )
ROMX_LOAD( "za3509_9913.a2", 0x3000, 0x1000, CRC(bc8860b7) SHA1(28b6cf7f5a4f81e017c2af091c3719657f981710), ROM_BIOS(2) )
ROM_REGION( 0x1000, "tkn80", 0 )
ROM_LOAD( "tkn80-iii.e", 0x0000, 0x1000, CRC(f0d2e4fa) SHA1(b0263c65db39667a6fe62e61f73fe591ea10f14b) )
ROM_REGION( 0x100, "hsync", 0 )
ROM_LOAD( "abc80_11.k5", 0x0000, 0x0100, CRC(e4f7e018) SHA1(63e718a39537f37286ea183e6469808c271dbfa5) ) // "64 40029-01" 82S129 256x4 horizontal sync
@ -630,4 +870,4 @@ ROM_END
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP( 1978, abc80, 0, 0, abc80, 0, abc80_state, empty_init, "Luxor Datorer AB", "ABC 80", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND )
COMP( 198?, tkn80, abc80, 0, abc80, 0, abc80_state, empty_init, "MYAB", "ABC 80 with TKN80", MACHINE_NOT_WORKING )
COMP( 198?, tkn80, abc80, 0, tkn80, tkn80, tkn80_state, empty_init, "MYAB", "ABC 80 with TKN80", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND )

View File

@ -92,6 +92,7 @@ public:
m_tape_in_latch(1)
{ }
void abc80_common(machine_config &config);
void abc80(machine_config &config);
void abc80_video(machine_config &config);
@ -113,10 +114,13 @@ protected:
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
void draw_scanline(bitmap_rgb32 &bitmap, int y);
virtual void draw_scanline(bitmap_rgb32 &bitmap, int y);
void draw_character(bitmap_rgb32 &bitmap, int y, int sx, int hsync_data, int dv);
virtual offs_t get_videoram_addr();
virtual u8 read_videoram(offs_t offset);
u8 read(offs_t offset);
void write(offs_t offset, u8 data);
virtual u8 read(offs_t offset);
virtual void write(offs_t offset, u8 data);
DECLARE_WRITE_LINE_MEMBER( vco_voltage_w );
@ -191,4 +195,50 @@ protected:
emu_timer *m_keyboard_clear_timer = nullptr;
};
// ======================> tkn80_state
class tkn80_state : public abc80_state
{
public:
tkn80_state(const machine_config &mconfig, device_type type, const char *tag) :
abc80_state(mconfig, type, tag),
m_rom_e(*this, "tkn80"),
m_char_ram(*this, "char_ram", 0x800, ENDIANNESS_LITTLE),
m_config(*this, "CONFIG"),
m_80(true)
{ }
void tkn80(machine_config &config);
void tkn80_video(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_reset() override;
virtual void draw_scanline(bitmap_rgb32 &bitmap, int y) override;
virtual offs_t get_videoram_addr() override;
virtual u8 read_videoram(offs_t offset) override;
void set_screen_params(void);
virtual u8 read(offs_t offset) override;
virtual void write(offs_t offset, u8 data) override;
uint8_t in3_r();
uint8_t in4_r();
void tkn80_io(address_map &map);
required_memory_region m_rom_e;
memory_share_creator<uint8_t> m_char_ram;
required_ioport m_config;
bool m_80;
offs_t m_rom_offset;
};
#endif // MAME_LUXOR_ABC80_H

View File

@ -10,10 +10,47 @@
#include "abc80.h"
#include "screen.h"
void tkn80_state::set_screen_params(void)
{
if (m_80)
{
m_screen->set_raw(XTAL(11'980'800), ABC80_HTOTAL*2, ABC80_HBEND*2, ABC80_HBSTART*2, ABC80_VTOTAL, ABC80_VBEND, ABC80_VBSTART);
m_scanline_timer->adjust(m_screen->time_until_pos(0, ABC80_HBEND*2), 0, m_screen->scan_period());
}
else
{
m_screen->set_raw(XTAL(11'980'800)/2, ABC80_HTOTAL, ABC80_HBEND, ABC80_HBSTART, ABC80_VTOTAL, ABC80_VBEND, ABC80_VBSTART);
m_scanline_timer->adjust(m_screen->time_until_pos(0, ABC80_HBEND), 0, m_screen->scan_period());
}
}
uint8_t tkn80_state::in3_r()
{
if (!machine().side_effects_disabled() && m_80)
{
m_80 = false;
set_screen_params();
}
return 0xff;
};
uint8_t tkn80_state::in4_r()
{
if (!machine().side_effects_disabled() && !m_80)
{
m_80 = true;
set_screen_params();
}
return 0xff;
};
void abc80_state::draw_scanline(bitmap_rgb32 &bitmap, int y)
{
uint8_t vsync_data = m_vsync_prom->base()[y];
uint8_t l = m_line_prom->base()[y];
int dv = (vsync_data & ABC80_K2_DV) ? 1 : 0;
if (!(vsync_data & ABC80_K2_FRAME_RESET))
@ -25,8 +62,6 @@ void abc80_state::draw_scanline(bitmap_rgb32 &bitmap, int y)
for (int sx = 0; sx < 64; sx++)
{
uint8_t hsync_data = m_hsync_prom->base()[sx];
int dh = (hsync_data & ABC80_K5_DH) ? 1 : 0;
uint8_t data = 0;
if (hsync_data & ABC80_K5_LINE_END)
{
@ -37,73 +72,7 @@ void abc80_state::draw_scanline(bitmap_rgb32 &bitmap, int y)
m_mode = 0;
}
/*
Video RAM Addressing Scheme
A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
R2 R1 R0 xx xx xx xx C2 C1 C0
A6 A5 A4 A3 = 00 C5 C4 C3 + R4 R3 R4 R3
*/
int a = (m_c >> 3) & 0x07;
int b = ((m_r >> 1) & 0x0c) | ((m_r >> 3) & 0x03);
int s = (a + b) & 0x0f;
uint16_t videoram_addr = ((m_r & 0x07) << 7) | (s << 3) | (m_c & 0x07);
uint8_t videoram_data = m_latch;
uint8_t attr_addr = ((dh & dv) << 7) | (videoram_data & 0x7f);
uint8_t attr_data = m_attr_prom->base()[attr_addr];
int blank = (attr_data & ABC80_J3_BLANK) ? 1 : 0;
int j = (attr_data & ABC80_J3_TEXT) ? 1 : 0;
int k = (attr_data & ABC80_J3_GRAPHICS) ? 1 : 0;
int versal = (attr_data & ABC80_J3_VERSAL) ? 1 : 0;
int cursor = (videoram_data & ABC80_CHAR_CURSOR) ? 1 : 0;
if (!j && k) m_mode = 0;
if (j && !k) m_mode = 1;
if (j && k) m_mode = !m_mode;
if (m_mode & versal)
{
// graphics mode
int r0 = 1, r1 = 1, r2 = 1;
if (l < 3) r0 = 0; else if (l < 7) r1 = 0; else r2 = 0;
int c0 = BIT(videoram_data, 0) || r0;
int c1 = BIT(videoram_data, 1) || r0;
int c2 = BIT(videoram_data, 2) || r1;
int c3 = BIT(videoram_data, 3) || r1;
int c4 = BIT(videoram_data, 4) || r2;
int c5 = BIT(videoram_data, 6) || r2;
if (c0 && c2 && c4) data |= 0xe0;
if (c1 && c3 && c5) data |= 0x1c;
}
else
{
// text mode
data = m_rocg->read(videoram_data & 0x7f, l);
}
// shift out pixels
for (int bit = 0; bit < 6; bit++)
{
int color = BIT(data, 7);
int x = (sx * 6) + bit;
color ^= (cursor & m_blink);
color &= blank;
bitmap.pix(y, x) = m_palette->pen(color);
data <<= 1;
}
m_latch = m_video_ram[videoram_addr];
draw_character(bitmap, y, sx, dv, hsync_data);
if (hsync_data & ABC80_K5_ROW_START)
{
@ -119,6 +88,182 @@ void abc80_state::draw_scanline(bitmap_rgb32 &bitmap, int y)
}
}
void tkn80_state::draw_scanline(bitmap_rgb32 &bitmap, int y)
{
uint8_t vsync_data = m_vsync_prom->base()[y];
int dv = (vsync_data & ABC80_K2_DV) ? 1 : 0;
if (!(vsync_data & ABC80_K2_FRAME_RESET))
{
// reset F2
m_r = 0;
}
int cols = m_80 ? 128 : 64;
for (int sx = 0; sx < cols; sx++)
{
uint8_t hsync_data = m_hsync_prom->base()[m_80 ? (sx / 2) : sx];
if (hsync_data & ABC80_K5_LINE_END)
{
// reset F4
m_c = 0;
// reset J5
m_mode = 0;
}
draw_character(bitmap, y, sx, dv, hsync_data);
if (hsync_data & ABC80_K5_ROW_START)
{
if (!m_80 || sx > 30) {
// clock F4
m_c++;
}
}
}
if (vsync_data & ABC80_K2_FRAME_END)
{
// clock F2
m_r++;
}
}
void abc80_state::draw_character(bitmap_rgb32 &bitmap, int y, int sx, int dv, int hsync_data)
{
uint8_t l = m_line_prom->base()[y];
int dh = (hsync_data & ABC80_K5_DH) ? 1 : 0;
uint8_t data = 0;
uint16_t videoram_addr = get_videoram_addr();
uint8_t videoram_data = m_latch;
uint8_t attr_addr = ((dh & dv) << 7) | (videoram_data & 0x7f);
uint8_t attr_data = m_attr_prom->base()[attr_addr];
int blank = (attr_data & ABC80_J3_BLANK) ? 1 : 0;
int j = (attr_data & ABC80_J3_TEXT) ? 1 : 0;
int k = (attr_data & ABC80_J3_GRAPHICS) ? 1 : 0;
int versal = (attr_data & ABC80_J3_VERSAL) ? 1 : 0;
int cursor = (videoram_data & ABC80_CHAR_CURSOR) ? 1 : 0;
if (!j && k) m_mode = 0;
if (j && !k) m_mode = 1;
if (j && k) m_mode = !m_mode;
if (m_mode & versal)
{
// graphics mode
int r0 = 1, r1 = 1, r2 = 1;
if (l < 3) r0 = 0; else if (l < 7) r1 = 0; else r2 = 0;
int c0 = BIT(videoram_data, 0) || r0;
int c1 = BIT(videoram_data, 1) || r0;
int c2 = BIT(videoram_data, 2) || r1;
int c3 = BIT(videoram_data, 3) || r1;
int c4 = BIT(videoram_data, 4) || r2;
int c5 = BIT(videoram_data, 6) || r2;
if (c0 && c2 && c4) data |= 0xe0;
if (c1 && c3 && c5) data |= 0x1c;
}
else
{
// text mode
data = m_rocg->read(videoram_data & 0x7f, l);
}
// shift out pixels
for (int bit = 0; bit < 6; bit++)
{
int color = BIT(data, 7);
int x = (sx * 6) + bit;
color ^= (cursor & m_blink);
color &= blank;
bitmap.pix(y, x) = m_palette->pen(color);
data <<= 1;
}
m_latch = read_videoram(videoram_addr);
}
offs_t abc80_state::get_videoram_addr()
{
/*
Video RAM Addressing Scheme
A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
R2 R1 R0 xx xx xx xx C2 C1 C0
A6 A5 A4 A3 = 00 C5 C4 C3 + R4 R3 R4 R3
*/
int a = (m_c >> 3) & 0x07;
int b = ((m_r >> 1) & 0x0c) | ((m_r >> 3) & 0x03);
int s = (a + b) & 0x0f;
return ((m_r & 0x07) << 7) | (s << 3) | (m_c & 0x07);
}
offs_t tkn80_state::get_videoram_addr()
{
if (m_80)
{
/*
Video RAM Addressing Scheme
A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
R2 R1 R0 xx xx xx xx C3 C2 C1 C0
A7 A6 A5 A4 = 00 C6 C5 C4 + R4 R3 R4 R3
*/
int a = (m_c >> 4) & 0x07;
int b = ((m_r >> 1) & 0x0c) | ((m_r >> 3) & 0x03);
int s = (a + b) & 0x1f;
return ((m_r & 0x07) << 8) | (s << 4) | (m_c & 0x0f);
}
else
{
/*
Video RAM Addressing Scheme
A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
1 R2 R1 R0 xx xx xx xx C2 C1 C0
A6 A5 A4 A3 = 00 C5 C4 C3 + R4 R3 R4 R3
*/
int a = (m_c >> 3) & 0x07;
int b = ((m_r >> 1) & 0x0c) | ((m_r >> 3) & 0x03);
int s = (a + b) & 0x0f;
return 0x400 | ((m_r & 0x07) << 7) | (s << 3) | (m_c & 0x07);
}
}
u8 abc80_state::read_videoram(offs_t offset)
{
return m_video_ram[offset];
}
u8 tkn80_state::read_videoram(offs_t offset)
{
return m_char_ram[offset];
}
//-------------------------------------------------
// video_start -
@ -143,6 +288,22 @@ void abc80_state::video_start()
}
//-------------------------------------------------
// video_reset -
//-------------------------------------------------
void tkn80_state::video_reset()
{
u8 config = m_config->read();
m_80 = BIT(config, 0);
set_screen_params();
m_blink = 1;
m_blink_timer->enable(BIT(config, 1));
}
//-------------------------------------------------
// screen_update -
//-------------------------------------------------
@ -170,3 +331,20 @@ void abc80_state::abc80_video(machine_config &config)
SN74S263(config, m_rocg, 0);
m_rocg->set_palette(m_palette);
}
//-------------------------------------------------
// machine_config( tkn80_video )
//-------------------------------------------------
void tkn80_state::tkn80_video(machine_config &config)
{
PALETTE(config, m_palette, palette_device::MONOCHROME);
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_screen_update(FUNC(tkn80_state::screen_update));
m_screen->set_raw(XTAL(11'980'800), ABC80_HTOTAL*2, ABC80_HBEND*2, ABC80_HBSTART*2, ABC80_VTOTAL, ABC80_VBEND, ABC80_VBSTART);
SN74S263(config, m_rocg, 0);
m_rocg->set_palette(m_palette);
}