sbrain: Driver overhaul

- Support cursor and scrolling through CRTC registers
- Correct number of interrupts per frame
- Actually show the "insert diskette" message with -bios 0
- Add RAM size option
- Add option for two more floppy drives
- Add RS232 ports and DIP switch for selecting baud clocks
- Redo memory banking without configured banks or bankdev to be hardware-accurate (nw)
- Rename all "portXX" handlers (nw)
- Acknowledge interrupt on reads as well as writes (nw)
- Remove palette device (nw)
- Update manufacturer and system names (nw)
- Update notes (nw)
- Many small code refinements (nw)
This commit is contained in:
AJR 2018-10-04 09:08:27 -04:00
parent 4a7fdb0d9b
commit 6392ecb0fa
3 changed files with 306 additions and 143 deletions

View File

@ -44,6 +44,9 @@
#include "video/dp8350.h"
#include "screen.h"
//#define VERBOSE 1
#include "logmacro.h"
//**************************************************************************
// GLOBAL VARIABLES
@ -344,7 +347,7 @@ void dp835x_device::register_load(u8 rs, u16 addr)
case 1:
// A = 0, B = 1: Top-of-Page
logerror("Top-of-Page Register = %03X\n", addr);
LOG("Top-of-Page Register = %03X\n", addr);
m_topr = addr;
break;
@ -352,19 +355,19 @@ void dp835x_device::register_load(u8 rs, u16 addr)
// A = 1, B = 0: Row Start (also Top-of-Page during vertical blanking)
if (m_line >= m_video_scan_lines)
{
logerror("Row Start Register = %03X (redirected to Top-of-Page)\n", addr);
LOG("Row Start Register = %03X (redirected to Top-of-Page)\n", addr);
m_topr = addr;
}
else
{
logerror("Row Start Register = %03X\n", addr);
LOG("Row Start Register = %03X\n", addr);
m_rsr = addr;
}
break;
case 3:
// A = 1, B = 1: Cursor
logerror("Cursor Register = %03X\n", addr);
LOG("Cursor Register = %03X\n", addr);
m_cr = addr;
break;
}

View File

@ -66,6 +66,11 @@ public:
DECLARE_READ_LINE_MEMBER(vsync_r);
DECLARE_READ_LINE_MEMBER(vblank_r);
// address getters (TODO: accurate character-by-character emulation)
u16 top_of_page() const { return m_topr; }
u16 row_start() const { return m_row_start; }
u16 cursor_address() const { return m_cr; }
protected:
// base type constructor
dp835x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock,

View File

@ -8,10 +8,12 @@ Intertec SuperBrain
Intertec Compustar terminal appears to have identical hardware. Need roms for it.
Chips: 2x Z80; FD1791; 2x 8251; 8255; BR1941; CRT8002; KR3600; DP8350
Chips: 2x Z80; FD1791; 2x 8251; 8255; BR1941; CRT8002-003; KR3600-056; DP8350; MM5035
Xtals: 16.0, 10.92, 5.0688
RAM: 32K or 64K dynamic (TMS4116-20NL); 1K static disk buffer (MM2114)
Disk parameters: 512 bytes x 10 sectors x 35 tracks. 1 and 2-sided disks supported.
Sound: Beeper
Expansion bus: 40 pins, nearly identical to TRS-80
The boot prom is shared between both cpus. This feat is accomplished by holding the sub cpu
in reset, until the main cpu has prepared a few memory locations. The first thing in the rom
@ -26,30 +28,31 @@ When booted, the time (corrupted) is displayed at top right. You need to run TIM
The schematic in parts is difficult to read. Some assumptions have been made.
To Do:
- Without a disk in, it should display a message to insert a disk. Doesn't happen. May
attempt to execute empty memory instead. (-bios 1, -bios 2)
- Without a disk in, it should display a message to insert a disk. This happens, but only with
-bios 0. May attempt to execute empty memory instead. (-bios 1, -bios 2)
- Improve keyboard.
- Video chips need to be emulated (CRT8002 and DP8350), attributes etc.
- Row buffering DMA (DP8350, MM5035) and line-by-line rendering.
- Proper character generator emulation (CRT8002).
- Add expansion bus slot.
- Probably lots of other stuff.
- PC0 when high will swap out lower 16k of RAM for the DP8350 device. The value of HL (the
"memory" address) is the data (cursor location, top of screen, etc). The byte "written"
to this address (d0,d1) is the command for the CRTC.
*************************************************************************************************************/
#include "emu.h"
#include "cpu/z80/z80.h"
#include "bus/rs232/rs232.h"
#include "machine/com8116.h"
#include "machine/i8251.h"
#include "machine/i8255.h"
#include "machine/wd_fdc.h"
#include "machine/ram.h"
#include "machine/timer.h"
#include "sound/beep.h"
#include "video/dp8350.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include <algorithm>
class sbrain_state : public driver_device
@ -59,43 +62,56 @@ public:
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_subcpu(*this, "subcpu")
, m_p_videoram(*this, "videoram")
, m_p_chargen(*this, "chargen")
, m_beep(*this, "beeper")
, m_crtc(*this, "crtc")
, m_u0(*this, "uart0")
, m_u1(*this, "uart1")
, m_usart(*this, "usart%u", 0U)
, m_mainport(*this, "mainport")
, m_ppi(*this, "ppi")
, m_fdc (*this, "fdc")
, m_floppy0(*this, "fdc:0")
, m_floppy1(*this, "fdc:1")
, m_vs(*this, "VS")
, m_bankr0(*this, "bankr0")
, m_bankw0(*this, "bankw0")
, m_bank2(*this, "bank2")
, m_fdc(*this, "fdc")
, m_floppy(*this, "fdc:%u", 0U)
, m_ram(*this, RAM_TAG)
, m_boot_prom(*this, "subcpu")
, m_disk_buffer(*this, "buffer")
, m_keyboard(*this, "X%u", 0)
, m_modifiers(*this, "MODIFIERS")
, m_serial_sw(*this, "BAUDCLOCK")
{
}
void sbrain(machine_config &config);
void init_sbrain();
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
private:
DECLARE_MACHINE_RESET(sbrain);
DECLARE_READ8_MEMBER(ppi_pa_r);
DECLARE_WRITE8_MEMBER(ppi_pa_w);
DECLARE_READ8_MEMBER(ppi_pb_r);
DECLARE_WRITE8_MEMBER(ppi_pb_w);
DECLARE_READ8_MEMBER(ppi_pc_r);
DECLARE_WRITE8_MEMBER(ppi_pc_w);
DECLARE_READ8_MEMBER(port48_r);
DECLARE_READ8_MEMBER(port50_r);
DECLARE_READ8_MEMBER(port10_r);
DECLARE_WRITE8_MEMBER(port10_w);
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
u8 mem_r(offs_t offset);
void mem_w(offs_t offset, u8 data);
u8 ppi_pa_r();
void ppi_pa_w(u8 data);
u8 ppi_pb_r();
void ppi_pb_w(u8 data);
u8 ppi_pc_r();
void ppi_pc_w(u8 data);
u8 char_int_ack_r();
void char_int_ack_w(u8 data);
u8 keyboard_r();
void disk_select_w(u8 data);
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
TIMER_DEVICE_CALLBACK_MEMBER(kbd_scan);
DECLARE_WRITE_LINE_MEMBER(crtc_lrc_w);
DECLARE_WRITE_LINE_MEMBER(crtc_vblank_w);
DECLARE_WRITE_LINE_MEMBER(crtc_vsync_w);
DECLARE_WRITE_LINE_MEMBER(external_txc_w);
DECLARE_WRITE_LINE_MEMBER(external_rxc_w);
DECLARE_WRITE_LINE_MEMBER(internal_txc_rxc_w);
void sbrain_io(address_map &map);
void sbrain_mem(address_map &map);
void sbrain_subio(address_map &map);
@ -107,79 +123,135 @@ private:
u8 m_portb;
u8 m_portc;
u8 m_port10;
u8 m_term_data;
u8 m_key_data;
u8 m_framecnt;
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_subcpu;
required_shared_ptr<u8> m_p_videoram;
required_region_ptr<u8> m_p_chargen;
required_device<beep_device> m_beep;
required_device<dp8350_device> m_crtc;
required_device<i8251_device> m_u0;
required_device<i8251_device> m_u1;
required_device_array<i8251_device, 2> m_usart;
required_device<rs232_port_device> m_mainport;
required_device<i8255_device> m_ppi;
required_device<fd1791_device> m_fdc;
required_device<floppy_connector> m_floppy0;
required_device<floppy_connector> m_floppy1;
required_ioport m_vs;
required_memory_bank m_bankr0;
required_memory_bank m_bankw0;
required_memory_bank m_bank2;
required_device_array<floppy_connector, 4> m_floppy;
required_device<ram_device> m_ram;
required_region_ptr<u8> m_boot_prom;
required_shared_ptr<u8> m_disk_buffer;
required_ioport_array<10> m_keyboard;
required_ioport m_modifiers;
required_ioport m_serial_sw;
};
void sbrain_state::sbrain_mem(address_map &map)
{
map(0x0000, 0x3fff).bankr("bankr0").bankw("bankw0");
map(0x4000, 0x7fff).ram();
map(0x8000, 0xbfff).bankrw("bank2");
map(0xc000, 0xf7ff).ram();
map(0xf800, 0xffff).ram().share("videoram");
map(0x0000, 0xffff).rw(FUNC(sbrain_state::mem_r), FUNC(sbrain_state::mem_w));
}
void sbrain_state::sbrain_io(address_map &map)
{
map.global_mask(0xff);
map(0x40, 0x41).mirror(6).rw(m_u0, FUNC(i8251_device::read), FUNC(i8251_device::write));
map(0x48, 0x4f).r(FUNC(sbrain_state::port48_r)); //chr_int_latch
map(0x50, 0x57).r(FUNC(sbrain_state::port50_r));
map(0x58, 0x59).mirror(6).rw(m_u1, FUNC(i8251_device::read), FUNC(i8251_device::write));
map(0x40, 0x41).mirror(6).rw(m_usart[0], FUNC(i8251_device::read), FUNC(i8251_device::write));
map(0x48, 0x48).mirror(7).rw(FUNC(sbrain_state::char_int_ack_r), FUNC(sbrain_state::char_int_ack_w)); //chr_int_latch
map(0x50, 0x50).mirror(7).r(FUNC(sbrain_state::keyboard_r));
map(0x58, 0x59).mirror(6).rw(m_usart[1], FUNC(i8251_device::read), FUNC(i8251_device::write));
map(0x60, 0x60).mirror(7).w("brg", FUNC(com8116_device::stt_str_w));
map(0x68, 0x6b).mirror(4).rw(m_ppi, FUNC(i8255_device::read), FUNC(i8255_device::write));
}
void sbrain_state::sbrain_submem(address_map &map)
{
map(0x0000, 0x07ff).rom();
map(0x8800, 0x8bff).ram().region("subcpu", 0x8800);
map(0x0000, 0x07ff).mirror(0xf000).rom().region("subcpu", 0);
map(0x8800, 0x8bff).mirror(0x7400).ram().share("buffer");
}
void sbrain_state::sbrain_subio(address_map &map)
{
map.global_mask(0xff);
map(0x08, 0x0b).rw(m_fdc, FUNC(fd1791_device::read), FUNC(fd1791_device::write));
map(0x10, 0x10).rw(FUNC(sbrain_state::port10_r), FUNC(sbrain_state::port10_w));
map.global_mask(0x1f);
map(0x08, 0x0b).mirror(4).rw(m_fdc, FUNC(fd1791_device::read), FUNC(fd1791_device::write));
map(0x10, 0x10).mirror(7).w(FUNC(sbrain_state::disk_select_w));
}
READ8_MEMBER( sbrain_state::port48_r )
u8 sbrain_state::mem_r(offs_t offset)
{
m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
switch (offset & 0xc000)
{
case 0x0000:
// PPIC-2 set selects boot PROM
if (BIT(m_portc, 2))
return m_boot_prom[offset & 0x7ff];
// lowest 16K of RAM is disabled when PPIC-0 is set
if (BIT(m_portc, 0))
return 0xff;
break;
case 0x8000:
// resetting PPIC-4 selects disk buffer RAM
if (!BIT(m_portc, 4))
return m_disk_buffer[offset & 0x3ff];
break;
}
return m_ram->read(offset);
}
void sbrain_state::mem_w(offs_t offset, u8 data)
{
// any memory write affects CRTC when PPIC-0 is set
if (BIT(m_portc, 0))
m_crtc->register_load(bitswap<2>(data, 0, 1), offset & 0xfff);
switch (offset & 0xc000)
{
case 0x0000:
// can't write to boot PROM
if (BIT(m_portc, 2))
return;
// RAS is disabled for bank 0 when PPIC-0 is set
if (BIT(m_portc, 0))
return;
break;
case 0x8000:
// resetting PPIC-4 selects disk buffer RAM
if (!BIT(m_portc, 4))
{
m_disk_buffer[offset & 0x3ff] = data;
break;
}
break;
}
m_ram->write(offset, data);
}
u8 sbrain_state::char_int_ack_r()
{
if (!machine().side_effects_disabled())
m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
return 0xff;
}
READ8_MEMBER( sbrain_state::port50_r )
void sbrain_state::char_int_ack_w(u8 data)
{
return m_term_data;
m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
}
READ8_MEMBER( sbrain_state::port10_r )
u8 sbrain_state::keyboard_r()
{
return m_port10;
return m_key_data;
}
/* Misc disk functions
d0 : ?
d0 : busy signal to master CPU
d1 : SEL A (drive 0?)
d2 : SEL B (drive 1?)
d3 : SEL C
@ -187,24 +259,27 @@ d4 : SEL D
d5 : side select
d6,7 : not used
*/
WRITE8_MEMBER( sbrain_state::port10_w )
void sbrain_state::disk_select_w(u8 data)
{
m_port10 = data | 0xc0;
floppy_image_device *floppy = nullptr;
if (BIT(m_port10, 1)) floppy = m_floppy0->get_device();
if (BIT(m_port10, 2)) floppy = m_floppy1->get_device();
m_fdc->set_floppy(floppy);
if (floppy)
floppy->ss_w(BIT(m_port10, 5));
m_floppy0->get_device()->mon_w(0); // motors run all the time
m_floppy1->get_device()->mon_w(0);
m_fdc->set_floppy(nullptr);
for (int d = 0; d < 4; d++)
{
if (BIT(m_port10, d + 1))
{
floppy_image_device *floppy = m_floppy[d]->get_device();
if (floppy && floppy->exists())
{
m_fdc->set_floppy(floppy);
floppy->ss_w(BIT(m_port10, 5));
break;
}
}
}
}
READ8_MEMBER( sbrain_state::ppi_pa_r )
u8 sbrain_state::ppi_pa_r()
{
return m_porta;
}
@ -217,7 +292,7 @@ d5 : strike through
d6 : 1=60hz 0=50hz
d7 : reverse video
*/
WRITE8_MEMBER( sbrain_state::ppi_pa_w )
void sbrain_state::ppi_pa_w(u8 data)
{
m_crtc->refresh_control(BIT(data, 6));
@ -230,25 +305,26 @@ d1 : key held down
d2 : Vert Blank
d3 : not used
d4 : /capslock
d5 : ?
d5 : disk status: 1 = busy, 0 = ready
d6 : Ring Indicator line from main rs232 port, 1=normal, 0=set
d7 : cpu2 /busak line
*/
READ8_MEMBER( sbrain_state::ppi_pb_r )
u8 sbrain_state::ppi_pb_r()
{
u8 vertsync = m_vs->read(); // bit 2
u8 capslock = BIT(ioport("MODIFIERS")->read(), 0) << 4; // bit 4, capslock
u8 vertsync = m_crtc->vblank_r() << 2;
u8 capslock = BIT(m_modifiers->read(), 0) << 4; // bit 4, capslock
u8 p10d0 = BIT(m_port10, 0) << 5; // bit 5
u8 ri = m_mainport->ri_r() << 6;
u8 busak = m_busak ? 128 : 0; // bit 7
return busak | p10d0 | capslock | vertsync | m_keydown;
return busak | ri | p10d0 | capslock | vertsync | m_keydown;
}
WRITE8_MEMBER( sbrain_state::ppi_pb_w )
void sbrain_state::ppi_pb_w(u8 data)
{
m_portb = data & 8;
}
READ8_MEMBER( sbrain_state::ppi_pc_r )
u8 sbrain_state::ppi_pc_r()
{
return m_portc;
}
@ -263,20 +339,45 @@ d5 : cpu2 /busreq line
d6 : beeper
d7 : keyboard, 1=enable comms, 0=reset
*/
WRITE8_MEMBER( sbrain_state::ppi_pc_w )
void sbrain_state::ppi_pc_w(u8 data)
{
m_portc = data;
m_beep->set_state(BIT(data, 6));
m_bankr0->set_entry(BIT(data, 2));
m_bank2->set_entry(BIT(data, 4));
if (!BIT(data, 7))
m_keydown &= 2; // ack DR
m_subcpu->set_input_line(INPUT_LINE_RESET, BIT(data, 3) ? ASSERT_LINE : CLEAR_LINE);
if (BIT(data, 3))
{
m_fdc->reset();
disk_select_w(0);
}
m_subcpu->set_input_line(Z80_INPUT_LINE_BUSRQ, BIT(data, 5) ? ASSERT_LINE : CLEAR_LINE); // ignored in z80.cpp
m_busak = BIT(data, 5);
}
WRITE_LINE_MEMBER(sbrain_state::external_txc_w)
{
if (!BIT(m_serial_sw->read(), 0))
m_usart[1]->write_txc(state);
}
WRITE_LINE_MEMBER(sbrain_state::external_rxc_w)
{
if (!BIT(m_serial_sw->read(), 2))
m_usart[1]->write_rxc(state);
}
WRITE_LINE_MEMBER(sbrain_state::internal_txc_rxc_w)
{
if (!BIT(m_serial_sw->read(), 1))
m_usart[1]->write_txc(state);
if (!BIT(m_serial_sw->read(), 3))
m_usart[1]->write_rxc(state);
if (!BIT(m_serial_sw->read(), 4))
m_mainport->write_etc(state);
}
u8 translate_table[3][10][8] = {
// unshifted
{
@ -419,16 +520,23 @@ static INPUT_PORTS_START( sbrain )
PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
/* vblank */
PORT_START("VS")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_CUSTOM) PORT_VBLANK("screen")
PORT_START("BAUDCLOCK")
PORT_DIPNAME(0x03, 0x01, "Main TX Clock") PORT_DIPLOCATION("SW:1,3")
PORT_DIPSETTING(0x01, "Internal")
PORT_DIPSETTING(0x02, "External")
PORT_DIPNAME(0x0c, 0x04, "Main RX Clock") PORT_DIPLOCATION("SW:2,4")
PORT_DIPSETTING(0x04, "Internal")
PORT_DIPSETTING(0x08, "External")
PORT_DIPNAME(0x10, 0x10, "Internal Baud Clock to Main Port") PORT_DIPLOCATION("SW:5")
PORT_DIPSETTING(0x10, DEF_STR(Off))
PORT_DIPSETTING(0x00, DEF_STR(On))
INPUT_PORTS_END
TIMER_DEVICE_CALLBACK_MEMBER(sbrain_state::kbd_scan)
{
// m_keydown: d0 = 1 after key pressed, and is reset by pc7; d1 = 1 while a key is down.
m_keydown &= 1;
u8 i, j, keyin, mods = ioport("MODIFIERS")->read() & 6;
u8 i, j, keyin, mods = m_modifiers->read() & 6;
u8 translate_set = 0;
if (BIT(mods, 1))
translate_set = 1;
@ -446,26 +554,41 @@ TIMER_DEVICE_CALLBACK_MEMBER(sbrain_state::kbd_scan)
if (BIT(keyin, j))
{
u8 pressed = translate_table[translate_set][i][j];
m_keydown = (m_term_data == pressed) ? (m_keydown | 2) : 3;
m_term_data = pressed;
m_keydown = (m_key_data == pressed) ? (m_keydown | 2) : 3;
m_key_data = pressed;
return;
}
}
}
}
m_term_data = 0xff;
m_key_data = 0xff;
}
void sbrain_state::init_sbrain()
WRITE_LINE_MEMBER(sbrain_state::crtc_lrc_w)
{
u8 *main = memregion("maincpu")->base();
u8 *sub = memregion("subcpu")->base();
// TODO: actually triggered by BUSACK and taken after DMA burst finishes
if (state && !m_crtc->lbre_r() && !m_crtc->vblank_r())
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
}
m_bankr0->configure_entry(0, &main[0x0000]);
m_bankr0->configure_entry(1, &sub[0x0000]);
m_bankw0->configure_entry(0, &main[0x0000]);
m_bank2->configure_entry(0, &sub[0x8000]);
m_bank2->configure_entry(1, &main[0x8000]);
WRITE_LINE_MEMBER(sbrain_state::crtc_vblank_w)
{
if (state)
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
}
WRITE_LINE_MEMBER(sbrain_state::crtc_vsync_w)
{
// TODO: internal to the CRT8002
if (!state)
m_framecnt++;
}
void sbrain_state::machine_start()
{
std::fill_n(m_ram->pointer(), m_ram->size(), 0x00);
m_usart[0]->write_cts(0);
}
static void sbrain_floppies(device_slot_interface &device)
@ -473,20 +596,31 @@ static void sbrain_floppies(device_slot_interface &device)
device.option_add("525dd", FLOPPY_525_DD);
}
MACHINE_RESET_MEMBER( sbrain_state, sbrain )
void sbrain_state::machine_reset()
{
m_keydown = 0;
m_bankr0->set_entry(1); // point at rom
m_bankw0->set_entry(0); // always write to ram
m_bank2->set_entry(1); // point at maincpu bank
m_subcpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); // hold subcpu in reset
for (auto &floppy : m_floppy)
{
floppy_image_device *device = floppy->get_device();
if (device != nullptr)
device->mon_w(0); // motors run all the time
}
// PPI resets to input mode, which causes PPIC-3 to be pulled up to +5V, resetting disk CPU
}
u32 sbrain_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
u32 sbrain_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
// PPIC-3 blanks entire display
if (BIT(m_portc, 3))
{
bitmap.fill(rgb_t::black(), cliprect);
return 0;
}
u8 y,ra,chr,gfx;
uint16_t sy=0,ma=0,x;
m_framecnt++;
uint16_t sy=0,x;
// Where attributes come from:
// - Most systems use ram for character-based attributes, but this one uses strictly hardware which would seem cumbersome
@ -497,39 +631,45 @@ u32 sbrain_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con
// - d5 blank from PC1 (scan-line based)
// - d6 flash from bit 7 of each character
uint16_t ma = m_crtc->top_of_page();
uint16_t cr = m_crtc->cursor_address();
uint8_t *videoram = &m_ram->pointer()[m_ram->size() - 0x800];
for (y = 0; y < 24; y++)
{
for (ra = 0; ra < 10; ra++)
{
uint16_t *p = &bitmap.pix16(sy++);
uint32_t *p = &bitmap.pix32(sy++);
for (x = 0; x < 80; x++)
{
gfx = 0;
if (ra < 9)
if (ra > 0)
{
chr = m_p_videoram[x+ma];
chr = videoram[(x + ma) & 0x7ff];
if (!BIT(chr, 7) || BIT(m_framecnt, 5))
{
chr &= 0x7f;
if (chr)
gfx = m_p_chargen[(chr<<4) | ra ];
gfx = m_p_chargen[(chr<<4) | (ra - 1)]; // ra hacked for incorrect character generator
}
}
if (((x + ma) & 0xfff) == cr)
gfx ^= 0x7f;
/* Display a scanline of a character */
*p++ = BIT(gfx, 6);
*p++ = BIT(gfx, 5);
*p++ = BIT(gfx, 4);
*p++ = BIT(gfx, 3);
*p++ = BIT(gfx, 2);
*p++ = BIT(gfx, 1);
*p++ = BIT(gfx, 0);
*p++ = BIT(gfx, 6) ? rgb_t::white() : rgb_t::black();
*p++ = BIT(gfx, 5) ? rgb_t::white() : rgb_t::black();
*p++ = BIT(gfx, 4) ? rgb_t::white() : rgb_t::black();
*p++ = BIT(gfx, 3) ? rgb_t::white() : rgb_t::black();
*p++ = BIT(gfx, 2) ? rgb_t::white() : rgb_t::black();
*p++ = BIT(gfx, 1) ? rgb_t::white() : rgb_t::black();
*p++ = BIT(gfx, 0) ? rgb_t::white() : rgb_t::black();
}
}
ma+=80;
ma = (ma + 80) & 0xfff;
}
return 0;
}
@ -539,27 +679,26 @@ MACHINE_CONFIG_START(sbrain_state::sbrain)
MCFG_DEVICE_ADD("maincpu", Z80, 16_MHz_XTAL / 4)
MCFG_DEVICE_PROGRAM_MAP(sbrain_mem)
MCFG_DEVICE_IO_MAP(sbrain_io)
MCFG_DEVICE_VBLANK_INT_DRIVER("screen", sbrain_state, irq0_line_hold)
MCFG_DEVICE_ADD("subcpu", Z80, 16_MHz_XTAL / 4)
MCFG_DEVICE_PROGRAM_MAP(sbrain_submem)
MCFG_DEVICE_IO_MAP(sbrain_subio)
MCFG_MACHINE_RESET_OVERRIDE(sbrain_state, sbrain)
RAM(config, m_ram).set_default_size("64K").set_extra_options("32K");
/* video hardware */
MCFG_SCREEN_ADD_MONOCHROME("screen", RASTER, rgb_t::amber())
MCFG_SCREEN_UPDATE_DRIVER(sbrain_state, screen_update)
MCFG_SCREEN_PALETTE("palette")
MCFG_PALETTE_ADD_MONOCHROME("palette")
DP8350(config, m_crtc, 10.92_MHz_XTAL).set_screen("screen");
DP8350(config, m_crtc, 10.92_MHz_XTAL).set_screen("screen"); // XTAL not directly connected
m_crtc->character_generator_program(1);
m_crtc->lrc_callback().set(FUNC(sbrain_state::crtc_lrc_w));
m_crtc->vblank_callback().set(FUNC(sbrain_state::crtc_vblank_w));
m_crtc->vsync_callback().set(FUNC(sbrain_state::crtc_vsync_w));
/* sound hardware */
SPEAKER(config, "mono").front_center();
MCFG_DEVICE_ADD("beeper", BEEP, 800)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
BEEP(config, m_beep, 800).add_route(ALL_OUTPUTS, "mono", 1.00);
/* Devices */
I8255(config, m_ppi);
@ -570,29 +709,45 @@ MACHINE_CONFIG_START(sbrain_state::sbrain)
m_ppi->in_pc_callback().set(FUNC(sbrain_state::ppi_pc_r));
m_ppi->out_pc_callback().set(FUNC(sbrain_state::ppi_pc_w));
I8251(config, m_u0, 0);
I8251(config, m_usart[0], 16_MHz_XTAL / 8);
m_usart[0]->txd_handler().set("auxport", FUNC(rs232_port_device::write_txd));
I8251(config, m_u1, 0);
I8251(config, m_usart[1], 16_MHz_XTAL / 8);
m_usart[1]->txd_handler().set(m_mainport, FUNC(rs232_port_device::write_txd));
m_usart[1]->rts_handler().set(m_mainport, FUNC(rs232_port_device::write_rts));
m_usart[1]->dtr_handler().set(m_mainport, FUNC(rs232_port_device::write_dtr));
RS232_PORT(config, m_mainport, default_rs232_devices, nullptr);
m_mainport->rxd_handler().set(m_usart[1], FUNC(i8251_device::write_rxd));
m_mainport->cts_handler().set(m_usart[1], FUNC(i8251_device::write_cts));
m_mainport->dsr_handler().set(m_usart[1], FUNC(i8251_device::write_dsr));
m_mainport->txc_handler().set(FUNC(sbrain_state::external_txc_w));
m_mainport->rxc_handler().set(FUNC(sbrain_state::external_rxc_w));
rs232_port_device &auxport(RS232_PORT(config, "auxport", default_rs232_devices, nullptr));
auxport.rxd_handler().set(m_usart[0], FUNC(i8251_device::write_rxd));
auxport.dsr_handler().set(m_usart[0], FUNC(i8251_device::write_dsr));
com8116_device &brg(COM8116(config, "brg", 5.0688_MHz_XTAL)); // BR1941L
brg.fr_handler().set(m_u0, FUNC(i8251_device::write_txc));
brg.fr_handler().append(m_u0, FUNC(i8251_device::write_rxc));
brg.ft_handler().set(m_u1, FUNC(i8251_device::write_txc));
brg.ft_handler().append(m_u1, FUNC(i8251_device::write_rxc));
brg.fr_handler().set(m_usart[0], FUNC(i8251_device::write_txc));
brg.fr_handler().append(m_usart[0], FUNC(i8251_device::write_rxc));
brg.ft_handler().set(FUNC(sbrain_state::internal_txc_rxc_w));
FD1791(config, m_fdc, 16_MHz_XTAL / 16);
MCFG_FLOPPY_DRIVE_ADD("fdc:0", sbrain_floppies, "525dd", floppy_image_device::default_floppy_formats)
MCFG_FLOPPY_DRIVE_SOUND(true)
MCFG_FLOPPY_DRIVE_ADD("fdc:1", sbrain_floppies, "525dd", floppy_image_device::default_floppy_formats)
MCFG_FLOPPY_DRIVE_SOUND(true)
MCFG_FLOPPY_DRIVE_ADD("fdc:2", sbrain_floppies, nullptr, floppy_image_device::default_floppy_formats)
MCFG_FLOPPY_DRIVE_SOUND(true)
MCFG_FLOPPY_DRIVE_ADD("fdc:3", sbrain_floppies, nullptr, floppy_image_device::default_floppy_formats)
MCFG_FLOPPY_DRIVE_SOUND(true)
MCFG_TIMER_DRIVER_ADD_PERIODIC("timer_a", sbrain_state, kbd_scan, attotime::from_hz(15))
MACHINE_CONFIG_END
ROM_START( sbrain )
ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF )
ROM_REGION( 0x10000, "subcpu", ROMREGION_ERASEFF )
ROM_REGION( 0x0800, "subcpu", ROMREGION_ERASEFF ) // only the second CPU has its own ROM
ROM_SYSTEM_BIOS( 0, "4_003", "4.003" )
ROMX_LOAD("4_003_vc8001.z69", 0x0000, 0x0800, CRC(3ce3cd53) SHA1(fb6ade6bd67de3d9f911a1a48481ca619bda65ae), ROM_BIOS(0))
ROM_SYSTEM_BIOS( 1, "3_1", "3.1" )
@ -604,4 +759,4 @@ ROM_START( sbrain )
ROM_LOAD("c10_char.bin", 0x0000, 0x2000, BAD_DUMP CRC(cb530b6f) SHA1(95590bbb433db9c4317f535723b29516b9b9fcbf))
ROM_END
COMP( 1981, sbrain, 0, 0, sbrain, sbrain, sbrain_state, init_sbrain, "Intertec", "Superbrain", MACHINE_NOT_WORKING )
COMP( 1981, sbrain, 0, 0, sbrain, sbrain, sbrain_state, empty_init, "Intertec Data Systems", "SuperBrain Video Computer System", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )