diff options
Diffstat (limited to 'src/mame/sun/sun2.cpp')
-rw-r--r-- | src/mame/sun/sun2.cpp | 837 |
1 files changed, 837 insertions, 0 deletions
diff --git a/src/mame/sun/sun2.cpp b/src/mame/sun/sun2.cpp new file mode 100644 index 00000000000..139b7193ad0 --- /dev/null +++ b/src/mame/sun/sun2.cpp @@ -0,0 +1,837 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic, R. Belmont +/*************************************************************************** + + Sun-2 Models + ------------ + + 2/120 + Processor(s): 68010 @ 10MHz + CPU: 501-1007/1051 + Chassis type: deskside + Bus: Multibus (9 slots) + Oscillator(s): 39.3216MHz + Memory: 7M physical + Notes: First machines in deskside chassis. Serial + microswitch keyboard (type 2), Mouse Systems + optical mouse (Sun-2). + + 2/100U + Processor(s): 68010 @ 10MHz + CPU: 501-1007 + Bus: Multibus + Notes: Upgraded Sun 100. Replaced CPU and memory boards + with first-generation Sun-2 CPU and memory + boards so original customers could run SunOS + 1.x. Still has parallel kb/mouse interface so + type 1 keyboards and Sun-1 mice could be + connected. + + 2/150U + Notes: Apparently also an upgraded Sun-1. + + 2/170 + Chassis type: rackmount + Bus: Multibus (15 slots) + Notes: Rackmount version of 2/120, with more slots. + + 2/50 + Processor(s): 68010 @ 10MHz + CPU: 501-1141/1142/1143/1426/1427/1428 + Chassis type: wide pizza box + Bus: VME (2 slots) + Oscillator(s): 19.6608MHz, 16MHz (Ethernet/VMEbus), 100MHz + (video), 24MHz ("for special applications") + Memory: 7M physical + Notes: The (type 2) keyboard and mouse attach via an + adapter that accepts two modular plugs and + attaches to a DB15 port; later on, units were + apparently shipped with type 3 keyboards. The + CPU boards have a double-width back panel but + are otherwise identical to those in the 2/130 + and 2/160. + + 2/130 + 2/160 + Processor(s): 68010 @ 10MHz + CPU: 501-1144/1145/1146/1429/1430/1431 + Chassis type: deskside + Bus: VME (12 slots) + Memory: 7M physical + Notes: First machine in 12-slot deskside VME chassis. + Has four-fan cooling tray instead of six as in + later machines, which led to cooling problems + with lots of cards. Backplane has only four P2 + memory connectors bussed instead of six as in + later 12-slot backplanes; SCSI passthrough is in + slot 6 instead of 7 as in later 12-slot + backplanes. Upgradeable to a 3/160 by replacing + the CPU board. No information on the differences + between the 2/130 and the 2/160. + + + 25/08/2009 Skeleton driver. + 31/05/2016 Main screen turn on. + +How the architecture works: + - There are 3 address sub-spaces: CPU layer, MMU layer, and device layer + - CPU layer uses MOVS instructions to output FC 3. + - CPU layer: the low-order address bits A4-A1 specify the device + 0100x = ID Prom + 0101x = Diagnostic register (8 bits, 8 LEDs, bit = 0 for ON, 1 for OFF) + 0110x = Bus error register + 0111x = System enable register + + Bits A5+ address the actual individual parts of these things. ID Prom bytes + are at 0x0008, 0x0808, 0x1008, 0x1808, 0x2008, 0x2808, 0x3008, etc. + + System enable bits: + b0 = enable parity generation + b1 = cause level 1 IRQ + b2 = cause level 2 IRQ + b3 = cause level 3 IRQ + b4 = enable parity error checking + b5 = enable DVMA + b6 = enable all interrupts + b7 = boot state (0 = boot, 1 = normal) + In boot state, all supervisor program reads go to the EPROM. + + - MMU layer: also accessed via FC 3 + PAGE MAP at 0 + V + SEGMENT MAP at 4 + V + CONTEXT REG at 6 + V + + There are 8 hardware contexts. Supervisor and User FCs can have different contexts. + + Segment map is 4096 entries, from bits 23-15 of the virtual address + 3 context bits. + Entries are 8 bits, which point to a page map entry group (PMEG), which is 16 consecutive + page table entries (32 KB of space). + + Page map is 4096 entries each mapping a 2K page. There are 256 groups of 16 entries; + the PMEG points to these 256 groups. The page map contains a 20-bit page number, + which combines with the 11 low bits of the original address to get a 31-bit physical address. + The entry from 0-15 is picked with bits 15-11 of the original address. + + Page map entries are written to the PMEG determined by their segment map entry; you must + set the segment map validly in order to write to the page map. This is how they get away + with having 16 MB of segment entries and only 8 MB of PMEGs. + + See http://sunstuff.org/Sun-Hardware-Ref/s2hr/part2 +****************************************************************************/ + +#include "emu.h" +#include "cpu/m68000/m68010.h" +#include "machine/ram.h" +#include "machine/am9513.h" +#include "machine/i82586.h" +#include "machine/mm58167.h" +#include "machine/z80scc.h" +#include "machine/bankdev.h" +#include "machine/input_merger.h" +#include "bus/rs232/rs232.h" +#include "screen.h" + + +namespace { + +#define SCC1_TAG "scc1" +#define SCC2_TAG "scc2" +#define RS232A_TAG "rs232a" +#define RS232B_TAG "rs232b" + +// page table entry constants +#define PM_VALID (0x80000000) // page is valid +#define PM_PROTMASK (0x7e000000) // protection mask +#define PM_TYPEMASK (0x01c00000) // type mask +#define PM_ACCESSED (0x00200000) // accessed flag +#define PM_MODIFIED (0x00100000) // modified flag + +class sun2_state : public driver_device +{ +public: + sun2_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_rom(*this, "bootprom") + , m_idprom(*this, "idprom") + , m_ram(*this, RAM_TAG) + , m_type0space(*this, "type0") + , m_type1space(*this, "type1") + , m_type2space(*this, "type2") + , m_type3space(*this, "type3") + , m_edlc(*this, "edlc") + , m_bw2_vram(*this, "bw2_vram") + { } + + void sun2mbus(machine_config &config); + void sun2vme(machine_config &config); + +private: + required_device<m68010_device> m_maincpu; + required_memory_region m_rom, m_idprom; + required_device<ram_device> m_ram; + required_device<address_map_bank_device> m_type0space, m_type1space, m_type2space, m_type3space; + optional_device<i82586_device> m_edlc; + required_shared_ptr<uint16_t> m_bw2_vram; + + virtual void machine_start() override ATTR_COLD; + virtual void machine_reset() override ATTR_COLD; + + uint16_t mmu_r(offs_t offset, uint16_t mem_mask = ~0); + void mmu_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t tl_mmu_r(uint8_t fc, offs_t offset, uint16_t mem_mask); + void tl_mmu_w(uint8_t fc, offs_t offset, uint16_t data, uint16_t mem_mask); + uint16_t video_ctrl_r(); + void video_ctrl_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t ram_r(offs_t offset); + void ram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint8_t ethernet_r(); + void ethernet_w(uint8_t data); + void ethernet_int_w(int state); + uint16_t edlc_mmu_r(offs_t offset, uint16_t mem_mask); + void edlc_mmu_w(offs_t offset, uint16_t data, uint16_t mem_mask); + + uint32_t bw2_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + void mbustype0space_map(address_map &map) ATTR_COLD; + void mbustype1space_map(address_map &map) ATTR_COLD; + void mbustype2space_map(address_map &map) ATTR_COLD; + void mbustype3space_map(address_map &map) ATTR_COLD; + void sun2_mem(address_map &map) ATTR_COLD; + void edlc_mem(address_map &map) ATTR_COLD; + void vmetype0space_map(address_map &map) ATTR_COLD; + void vmetype1space_map(address_map &map) ATTR_COLD; + void vmetype2space_map(address_map &map) ATTR_COLD; + void vmetype3space_map(address_map &map) ATTR_COLD; + + uint16_t *m_rom_ptr, *m_ram_ptr; + uint8_t *m_idprom_ptr; + uint16_t m_diagreg, m_sysenable, m_buserror; + uint16_t m_context; + uint8_t m_segmap[8][512]; + uint32_t m_pagemap[4097]; + uint32_t m_ram_size, m_ram_size_words; + uint16_t m_bw2_ctrl; + uint8_t m_ethernet_status; +}; + +uint16_t sun2_state::ram_r(offs_t offset) +{ + if (offset < m_ram_size_words) return m_ram_ptr[offset]; + return 0xffff; +} + +void sun2_state::ram_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (offset < m_ram_size_words) COMBINE_DATA(&m_ram_ptr[offset]); +} + +uint16_t sun2_state::mmu_r(offs_t offset, uint16_t mem_mask) +{ + return tl_mmu_r(m_maincpu->get_fc(), offset, mem_mask); +} + +uint16_t sun2_state::tl_mmu_r(uint8_t fc, offs_t offset, uint16_t mem_mask) +{ + if ((fc == 3) && !machine().side_effects_disabled()) + { + if (offset & 0x4) // set for CPU space + { + switch (offset & 7) + { + case 4: + //printf("sun2: Read IDPROM @ %x (PC=%x)\n", offset<<1, m_maincpu->pc()); + return m_idprom_ptr[(offset>>10) & 0x1f]<<8; + + case 5: + //printf("sun2: Read diag reg\n"); + return m_diagreg; + + case 6: + //printf("sun2: Read bus error @ PC %x\n", m_maincpu->pc()); + return m_buserror; + + case 7: + //printf("sun2: Read sysenable\n"); + return m_sysenable; + } + } + else // clear for MMU space + { + int page; + + switch (offset & 3) + { + case 0: // page map + case 1: + page = m_segmap[m_context & 7][offset >> 14] << 4; + page += ((offset >> 10) & 0xf); + + //printf("sun2: Read page map at %x (entry %d)\n", offset<<1, page); + if (offset & 1) // low-order 16 bits + { + return m_pagemap[page] & 0xffff; + } + return m_pagemap[page] >> 16; + + case 2: // segment map + //printf("sun2: Read segment map at %x (entry %d, user ctx %d)\n", offset<<1, offset>>14, m_context & 7); + return m_segmap[m_context & 7][offset >> 14]; + + case 3: // context reg + //printf("sun2: Read context reg\n"); + return m_context; + } + } + } + + // boot mode? + if ((fc == M68K_FC_SUPERVISOR_PROGRAM) && !(m_sysenable & 0x80)) + { + return m_rom_ptr[offset & 0x3fff]; + } + + // debugger hack + if (machine().side_effects_disabled() && (offset >= (0xef0000>>1)) && (offset <= (0xef8000>>1))) + { + return m_rom_ptr[offset & 0x3fff]; + } + + // it's translation time + uint8_t context = (fc & 4) ? ((m_context >> 8) & 7) : (m_context & 7); + uint8_t pmeg = m_segmap[context][offset >> 14]; + uint32_t entry = (pmeg << 4) + ((offset >> 10) & 0xf); + + // printf("sun2: Context = %d, pmeg = %d, offset >> 14 = %x, entry = %d, page = %d\n", context, pmeg, offset >> 14, entry, (offset >> 10) & 0xf); + + if (m_pagemap[entry] & PM_VALID) + { + m_pagemap[entry] |= PM_ACCESSED; + + // Sun2 implementations only use 12 bits from the page entry + uint32_t tmp = (m_pagemap[entry] & 0xfff) << 10; + tmp |= (offset & 0x3ff); + + // if (!machine().side_effects_disabled()) + // printf("sun2: Translated addr: %08x, type %d (page %d page entry %08x, orig virt %08x, FC %d)\n", tmp << 1, (m_pagemap[entry] >> 22) & 7, entry, m_pagemap[entry], offset<<1, fc); + + switch ((m_pagemap[entry] >> 22) & 7) + { + case 0: // type 0 space + return m_type0space->read16(tmp, mem_mask); + + case 1: // type 1 space + // EPROM space is special: the MMU has a trap door + // where the original bits of the virtual address are + // restored so that the entire 32K EPROM can be + // accessed via a 2K single page view. This isn't + // obvious in the sun2 manual, but the sun3 manual + // (sun3 has the same mechanism) explains it well. + // the 2/50 ROM tests this specifically at $EF0DF0. + if (m_idprom_ptr[1] == 0x02) // 2/50 VMEbus has EPROM at 0x7F0000 + { + if ((tmp >= (0x7f0000>>1)) && (tmp <= (0x7f07ff>>1))) + { + return m_rom_ptr[offset & 0x3fff]; // the mask here is probably &0x7fff, change it if any 8KW (1.x?) romset shows up for a VME machine + } + } + else // Multibus has EPROM at 0x000000 + { + if (tmp <= (0x7ff>>1)) + { + return m_rom_ptr[offset & 0x7fff]; + } + } + + //printf("read device space @ %x\n", tmp<<1); + return m_type1space->read16(tmp, mem_mask); + + case 2: // type 2 space + return m_type2space->read16(tmp, mem_mask); + + case 3: // type 3 space + return m_type3space->read16(tmp, mem_mask); + } + } + else + { + if (!machine().side_effects_disabled()) printf("sun2: pagemap entry not valid!\n"); + } + + if (!machine().side_effects_disabled()) printf("sun2: Unmapped read @ %08x (FC %d, mask %04x, PC=%x, seg %x)\n", offset<<1, fc, mem_mask, m_maincpu->pc(), offset>>15); + + return 0xffff; +} + +void sun2_state::mmu_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + tl_mmu_w(m_maincpu->get_fc(), offset, data, mem_mask); +} + +void sun2_state::tl_mmu_w(uint8_t fc, offs_t offset, uint16_t data, uint16_t mem_mask) +{ + //printf("sun2: Write %04x (FC %d, mask %04x, PC=%x) to %08x\n", data, fc, mem_mask, m_maincpu->pc(), offset<<1); + + if (fc == 3) + { + if (offset & 0x4) // set for CPU space + { + switch (offset & 7) + { + case 4: + //printf("sun2: Write? IDPROM @ %x\n", offset<<1); + return; + + case 5: + // XOR to match Table 2-1 in the 2/50 Field Service Manual + printf("sun2: CPU LEDs to %02x (PC=%x) => ", (data & 0xff) ^ 0xff, m_maincpu->pc()); + m_diagreg = data & 0xff; + for (int i = 0; i < 8; i++) + { + if (m_diagreg & (1<<(7-i))) + { + printf("*"); + } + else + { + printf("O"); + } + } + printf("\n"); + return; + + case 6: + //printf("sun2: Write %04x to bus error not allowed\n", data); + return; + + case 7: + //printf("sun2: Write %04x to system enable\n", data); + COMBINE_DATA(&m_sysenable); + return; + } + } + else // clear for MMU space + { + int page; + + switch (offset & 3) + { + case 0: // page map + case 1: + page = m_segmap[m_context & 7][offset >> 14] << 4; + page += ((offset >> 10) & 0xf); + + //printf("sun2: Write %04x to page map at %x (entry %d), ", data, offset<<1, page); + if (offset & 1) // low-order 16 bits + { + m_pagemap[page] &= 0xffff0000; + m_pagemap[page] |= data; + } + else + { + m_pagemap[page] &= 0x0000ffff; + m_pagemap[page] |= (data<<16); + } + //printf("entry now %08x (adr %08x PC=%x)\n", m_pagemap[page], (m_pagemap[page] & 0xfffff) << 11, m_maincpu->pc()); + return; + + case 2: // segment map + //printf("sun2: Write %02x to segment map at %x (entry %d, user ctx %d PC=%x)\n", data & 0xff, offset<<1, offset>>14, m_context & 7, m_maincpu->pc()); + m_segmap[m_context & 7][offset >> 14] = data & 0xff; + return; + + case 3: // context reg + //printf("sun2: Write %04x to context\n", data); + COMBINE_DATA(&m_context); + return; + } + } + } + + // it's translation time + uint8_t context = (fc & 4) ? ((m_context >> 8) & 7) : (m_context & 7); + uint8_t pmeg = m_segmap[context][offset >> 14]; + uint32_t entry = (pmeg << 4) + ((offset >> 10) & 0xf); + + if (m_pagemap[entry] & PM_VALID) + { + m_pagemap[entry] |= (PM_ACCESSED | PM_MODIFIED); + + // only 12 of the 20 bits in the page table entry are used on either Sun2 implementation + uint32_t tmp = (m_pagemap[entry] & 0xfff) << 10; + tmp |= (offset & 0x3ff); + + //if (!machine().side_effects_disabled()) printf("sun2: Translated addr: %08x, type %d (page entry %08x, orig virt %08x)\n", tmp << 1, (m_pagemap[entry] >> 22) & 7, m_pagemap[entry], offset<<1); + + switch ((m_pagemap[entry] >> 22) & 7) + { + case 0: // type 0 + m_type0space->write16(tmp, data, mem_mask); + return; + + case 1: // type 1 + //printf("write device space @ %x\n", tmp<<1); + m_type1space->write16(tmp, data, mem_mask); + return; + + case 2: // type 2 + m_type2space->write16(tmp, data, mem_mask); + return; + + case 3: // type 3 + m_type3space->write16(tmp, data, mem_mask); + return; + } + } + else + { + if (!machine().side_effects_disabled()) printf("sun2: pagemap entry not valid!\n"); + } + + printf("sun2: Unmapped write %04x (FC %d, mask %04x, PC=%x) to %08x\n", data, fc, mem_mask, m_maincpu->pc(), offset<<1); +} + +// BW2 video control +uint16_t sun2_state::video_ctrl_r() +{ + return m_bw2_ctrl; +} + +void sun2_state::video_ctrl_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + //printf("sun2: BW2: %x to video_ctrl\n", data); + COMBINE_DATA(&m_bw2_ctrl); +} + +// 82586 Ethernet Data Link Controller interface +uint8_t sun2_state::ethernet_r() +{ + return m_ethernet_status; +} + +void sun2_state::ethernet_w(uint8_t data) +{ + m_edlc->reset_w(!BIT(data, 7)); + m_edlc->set_loopback(!BIT(data, 6)); // LBC on MB502 + m_edlc->ca(BIT(data, 5)); + + m_ethernet_status = (data & 0xf0) | (m_ethernet_status & 0x0f); + m_maincpu->set_input_line(M68K_IRQ_3, BIT(m_ethernet_status, 0) && BIT(m_ethernet_status, 4) ? ASSERT_LINE : CLEAR_LINE); +} + +void sun2_state::ethernet_int_w(int state) +{ + if (state) + { + m_ethernet_status |= 0x01; + if (BIT(m_ethernet_status, 4)) + m_maincpu->set_input_line(M68K_IRQ_3, ASSERT_LINE); + } + else + { + m_ethernet_status &= 0xfe; + if (BIT(m_ethernet_status, 4)) + m_maincpu->set_input_line(M68K_IRQ_3, CLEAR_LINE); + } +} + +uint16_t sun2_state::edlc_mmu_r(offs_t offset, uint16_t mem_mask) +{ + return swapendian_int16(tl_mmu_r(M68K_FC_SUPERVISOR_DATA, offset, swapendian_int16(mem_mask))); +} + +void sun2_state::edlc_mmu_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + tl_mmu_w(M68K_FC_SUPERVISOR_DATA, offset, swapendian_int16(data), swapendian_int16(mem_mask)); +} + +void sun2_state::sun2_mem(address_map &map) +{ + map(0x000000, 0xffffff).rw(FUNC(sun2_state::mmu_r), FUNC(sun2_state::mmu_w)); +} + +void sun2_state::edlc_mem(address_map &map) +{ + map(0x000000, 0xffffff).rw(FUNC(sun2_state::edlc_mmu_r), FUNC(sun2_state::edlc_mmu_w)); +} + +// VME memory spaces +// type 0 device space +void sun2_state::vmetype0space_map(address_map &map) +{ + map(0x000000, 0x7fffff).rw(FUNC(sun2_state::ram_r), FUNC(sun2_state::ram_w)); +} + +// type 1 device space +void sun2_state::vmetype1space_map(address_map &map) +{ + map(0x000000, 0x01ffff).ram().share(m_bw2_vram); + map(0x020000, 0x020001).rw(FUNC(sun2_state::video_ctrl_r), FUNC(sun2_state::video_ctrl_w)); + map(0x7f0000, 0x7f07ff).rom().region("bootprom", 0); // uses MMU loophole to read 32k from a 2k window + map(0x7f0800, 0x7f0800).mirror(0x7fe).rw(FUNC(sun2_state::ethernet_r), FUNC(sun2_state::ethernet_w)).cswidth(16); + // 7f1000-7f17ff: AM9518 encryption processor + //map(0x7f1800, 0x7f1800).rw(SCC1_TAG, FUNC(z80scc_device::cb_r), FUNC(z80scc_device::cb_w)); + //map(0x7f1802, 0x7f1802).rw(SCC1_TAG, FUNC(z80scc_device::db_r), FUNC(z80scc_device::db_w)); + map(0x7f1804, 0x7f1805).nopr(); + //map(0x7f1804, 0x7f1804).rw(SCC1_TAG, FUNC(z80scc_device::ca_r), FUNC(z80scc_device::ca_w)); + //map(0x7f1806, 0x7f1806).rw(SCC1_TAG, FUNC(z80scc_device::da_r), FUNC(z80scc_device::da_w)); + map(0x7f2000, 0x7f2000).rw(SCC2_TAG, FUNC(z80scc_device::cb_r), FUNC(z80scc_device::cb_w)); + map(0x7f2002, 0x7f2002).rw(SCC2_TAG, FUNC(z80scc_device::db_r), FUNC(z80scc_device::db_w)); + map(0x7f2004, 0x7f2004).rw(SCC2_TAG, FUNC(z80scc_device::ca_r), FUNC(z80scc_device::ca_w)); + map(0x7f2006, 0x7f2006).rw(SCC2_TAG, FUNC(z80scc_device::da_r), FUNC(z80scc_device::da_w)); + map(0x7f2800, 0x7f2803).mirror(0x7fc).rw("timer", FUNC(am9513_device::read16), FUNC(am9513_device::write16)); +} + +// type 2 device space +void sun2_state::vmetype2space_map(address_map &map) +{ +} + +// type 3 device space +void sun2_state::vmetype3space_map(address_map &map) +{ +} + +// Multibus memory spaces +// type 0 device space +void sun2_state::mbustype0space_map(address_map &map) +{ + map(0x000000, 0x3fffff).rw(FUNC(sun2_state::ram_r), FUNC(sun2_state::ram_w)); + // 7f80000-7f807ff: Keyboard/mouse SCC8530 + //map(0x7f8000, 0x7f8007).rw(SCC1_TAG, FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask16(0xff00); + map(0x700000, 0x71ffff).ram().share("bw2_vram"); + map(0x781800, 0x781801).rw(FUNC(sun2_state::video_ctrl_r), FUNC(sun2_state::video_ctrl_w)); +} + +// type 1 device space +void sun2_state::mbustype1space_map(address_map &map) +{ + map(0x000000, 0x0007ff).rom().region("bootprom", 0); // uses MMU loophole to read 32k from a 2k window + // 001000-0017ff: AM9518 encryption processor + // 001800-001fff: Parallel port + map(0x002000, 0x0027ff).rw(SCC2_TAG, FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask16(0xff00); + map(0x002800, 0x002803).mirror(0x7fc).rw("timer", FUNC(am9513_device::read16), FUNC(am9513_device::write16)); + map(0x003800, 0x00383f).mirror(0x7c0).rw("rtc", FUNC(mm58167_device::read), FUNC(mm58167_device::write)).umask16(0xff00); // 12 wait states generated by PAL16R6 (U415) +} + +// type 2 device space (Multibus memory space) +void sun2_state::mbustype2space_map(address_map &map) +{ +} + +// type 3 device space (Multibus I/O space) +void sun2_state::mbustype3space_map(address_map &map) +{ +} + +uint32_t sun2_state::bw2_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + static const uint32_t palette[2] = { 0, 0xffffff }; + auto const vram = util::big_endian_cast<uint8_t const>(m_bw2_vram.target()); + + if (!(m_bw2_ctrl & 0x8000)) return 0; + + for (int y = 0; y < 900; y++) + { + uint32_t *scanline = &bitmap.pix(y); + for (int x = 0; x < 1152/8; x++) + { + uint8_t const pixels = vram[(y * (1152 / 8)) + x]; + + *scanline++ = palette[BIT(pixels, 7)]; + *scanline++ = palette[BIT(pixels, 6)]; + *scanline++ = palette[BIT(pixels, 5)]; + *scanline++ = palette[BIT(pixels, 4)]; + *scanline++ = palette[BIT(pixels, 3)]; + *scanline++ = palette[BIT(pixels, 2)]; + *scanline++ = palette[BIT(pixels, 1)]; + *scanline++ = palette[BIT(pixels, 0)]; + } + } + + return 0; +} + +/* Input ports */ +static INPUT_PORTS_START( sun2 ) +INPUT_PORTS_END + +void sun2_state::machine_start() +{ + m_rom_ptr = (uint16_t *)m_rom->base(); + m_idprom_ptr = (uint8_t *)m_idprom->base(); + m_ram_ptr = (uint16_t *)m_ram->pointer(); + m_ram_size = m_ram->size(); + m_ram_size_words = m_ram_size >> 1; + + m_bw2_ctrl = 0; + + m_ethernet_status = 0; +} + +void sun2_state::machine_reset() +{ + m_diagreg = 0; + m_sysenable = 0; + m_context = 0; + m_buserror = 0; + memset(m_segmap, 0, sizeof(m_segmap)); + memset(m_pagemap, 0, sizeof(m_pagemap)); + + if (m_edlc.found()) + ethernet_w(0); +} + +void sun2_state::sun2vme(machine_config &config) +{ + /* basic machine hardware */ + M68010(config, m_maincpu, 19.6608_MHz_XTAL / 2); // or 24_MHz_XTAL / 2 by jumper setting + m_maincpu->set_addrmap(AS_PROGRAM, &sun2_state::sun2_mem); + + RAM(config, RAM_TAG).set_default_size("2M").set_extra_options("4M,6M,8M").set_default_value(0x00); + + // MMU Type 0 device space + ADDRESS_MAP_BANK(config, "type0").set_map(&sun2_state::vmetype0space_map).set_options(ENDIANNESS_BIG, 16, 32, 0x1000000); + + // MMU Type 1 device space + ADDRESS_MAP_BANK(config, "type1").set_map(&sun2_state::vmetype1space_map).set_options(ENDIANNESS_BIG, 16, 32, 0x1000000); + + // MMU Type 2 device space + ADDRESS_MAP_BANK(config, "type2").set_map(&sun2_state::vmetype2space_map).set_options(ENDIANNESS_BIG, 16, 32, 0x1000000); + + // MMU Type 3 device space + ADDRESS_MAP_BANK(config, "type3").set_map(&sun2_state::vmetype3space_map).set_options(ENDIANNESS_BIG, 16, 32, 0x1000000); + + screen_device &bwtwo(SCREEN(config, "bwtwo", SCREEN_TYPE_RASTER)); + bwtwo.set_screen_update(FUNC(sun2_state::bw2_update)); + bwtwo.set_raw(100_MHz_XTAL, 1600, 0, 1152, 937, 0, 900); + + I82586(config, m_edlc, 16_MHz_XTAL / 2); + m_edlc->set_addrmap(0, &sun2_state::edlc_mem); + m_edlc->out_irq_cb().set(FUNC(sun2_state::ethernet_int_w)); + + am9513a_device &timer(AM9513A(config, "timer", 19.6608_MHz_XTAL / 4)); + timer.fout_cb().set("timer", FUNC(am9513_device::gate1_w)); + timer.out1_cb().set_inputline(m_maincpu, M68K_IRQ_7); + timer.out2_cb().set("irq5", FUNC(input_merger_device::in_w<0>)); + timer.out3_cb().set("irq5", FUNC(input_merger_device::in_w<1>)); + timer.out4_cb().set("irq5", FUNC(input_merger_device::in_w<2>)); + timer.out5_cb().set("irq5", FUNC(input_merger_device::in_w<3>)); + + INPUT_MERGER_ANY_HIGH(config, "irq5").output_handler().set_inputline(m_maincpu, M68K_IRQ_5); // 74LS05 open collectors + + SCC8530(config, SCC1_TAG, 19.6608_MHz_XTAL / 4); + scc8530_device& scc2(SCC8530(config, SCC2_TAG, 19.6608_MHz_XTAL / 4)); + scc2.out_txda_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_txd)); + scc2.out_txdb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_txd)); + scc2.out_int_callback().set_inputline(m_maincpu, M68K_IRQ_6); + + rs232_port_device &rs232a(RS232_PORT(config, RS232A_TAG, default_rs232_devices, nullptr)); + rs232a.rxd_handler().set(SCC2_TAG, FUNC(z80scc_device::rxa_w)); + rs232a.dcd_handler().set(SCC2_TAG, FUNC(z80scc_device::dcda_w)); + rs232a.cts_handler().set(SCC2_TAG, FUNC(z80scc_device::ctsa_w)); + + rs232_port_device &rs232b(RS232_PORT(config, RS232B_TAG, default_rs232_devices, nullptr)); + rs232b.rxd_handler().set(SCC2_TAG, FUNC(z80scc_device::rxb_w)); + rs232b.dcd_handler().set(SCC2_TAG, FUNC(z80scc_device::dcdb_w)); + rs232b.cts_handler().set(SCC2_TAG, FUNC(z80scc_device::ctsb_w)); +} + +void sun2_state::sun2mbus(machine_config &config) +{ + /* basic machine hardware */ + M68010(config, m_maincpu, 39.3216_MHz_XTAL / 4); + m_maincpu->set_addrmap(AS_PROGRAM, &sun2_state::sun2_mem); + + RAM(config, RAM_TAG).set_default_size("2M").set_extra_options("4M").set_default_value(0x00); + + // MMU Type 0 device space + ADDRESS_MAP_BANK(config, "type0").set_map(&sun2_state::mbustype0space_map).set_options(ENDIANNESS_BIG, 16, 32, 0x1000000); + + // MMU Type 1 device space + ADDRESS_MAP_BANK(config, "type1").set_map(&sun2_state::mbustype1space_map).set_options(ENDIANNESS_BIG, 16, 32, 0x1000000); + + // MMU Type 2 device space + ADDRESS_MAP_BANK(config, "type2").set_map(&sun2_state::mbustype2space_map).set_options(ENDIANNESS_BIG, 16, 32, 0x1000000); + + // MMU Type 3 device space + ADDRESS_MAP_BANK(config, "type3").set_map(&sun2_state::mbustype3space_map).set_options(ENDIANNESS_BIG, 16, 32, 0x1000000); + + screen_device &bwtwo(SCREEN(config, "bwtwo", SCREEN_TYPE_RASTER)); + bwtwo.set_screen_update(FUNC(sun2_state::bw2_update)); + bwtwo.set_raw(100_MHz_XTAL, 1600, 0, 1152, 937, 0, 900); + //bwtwo.set_raw(100_MHz_XTAL, 1600, 0, 1024, 1061, 0, 1024); + + am9513a_device &timer(AM9513A(config, "timer", 39.3216_MHz_XTAL / 8)); + timer.fout_cb().set("timer", FUNC(am9513_device::gate1_w)); + timer.out1_cb().set_inputline(m_maincpu, M68K_IRQ_7); + timer.out2_cb().set("irq5", FUNC(input_merger_device::in_w<0>)); + timer.out3_cb().set("irq5", FUNC(input_merger_device::in_w<1>)); + timer.out4_cb().set("irq5", FUNC(input_merger_device::in_w<2>)); + timer.out5_cb().set("irq5", FUNC(input_merger_device::in_w<3>)); + + INPUT_MERGER_ANY_HIGH(config, "irq5").output_handler().set_inputline(m_maincpu, M68K_IRQ_5); // 74LS05 open collectors + + SCC8530(config, SCC1_TAG, 39.3216_MHz_XTAL / 8); + scc8530_device& scc2(SCC8530(config, SCC2_TAG, 39.3216_MHz_XTAL / 8)); + scc2.out_txda_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_txd)); + scc2.out_txdb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_txd)); + scc2.out_int_callback().set_inputline(m_maincpu, M68K_IRQ_6); + + rs232_port_device &rs232a(RS232_PORT(config, RS232A_TAG, default_rs232_devices, nullptr)); + rs232a.rxd_handler().set(SCC2_TAG, FUNC(z80scc_device::rxa_w)); + rs232a.dcd_handler().set(SCC2_TAG, FUNC(z80scc_device::dcda_w)); + rs232a.cts_handler().set(SCC2_TAG, FUNC(z80scc_device::ctsa_w)); + + rs232_port_device &rs232b(RS232_PORT(config, RS232B_TAG, default_rs232_devices, nullptr)); + rs232b.rxd_handler().set(SCC2_TAG, FUNC(z80scc_device::rxb_w)); + rs232b.dcd_handler().set(SCC2_TAG, FUNC(z80scc_device::dcdb_w)); + rs232b.cts_handler().set(SCC2_TAG, FUNC(z80scc_device::ctsb_w)); + + MM58167(config, "rtc", 32.768_kHz_XTAL); +} + +/* ROM definition */ +ROM_START( sun2_120 ) // ROMs are located on the '501-1007' CPU PCB at locations B11 and B10; J400 is set to 1-2 for 27128 EPROMs and 3-4 for 27256 EPROMs + ROM_REGION16_BE(0x10000, "bootprom", ROMREGION_ERASEFF) + // There is an undumped revision 1.1.2, which uses 27256 EPROMs + ROM_SYSTEM_BIOS(0, "rev10f", "Bootrom Rev 1.0F") + ROMX_LOAD("1.0f.b11", 0x0000, 0x8000, CRC(8fb0050a) SHA1(399cdb894b2a66d847d76d8a5d266906fb1d3430), ROM_SKIP(1) | ROM_BIOS(0)) // actual rom stickers had fallen off + ROMX_LOAD("1.0f.b10", 0x0001, 0x8000, CRC(70de816d) SHA1(67e980497f463dbc529f64ec5f3e0046b3901b7e), ROM_SKIP(1) | ROM_BIOS(0)) // " + ROM_SYSTEM_BIOS(1, "revr", "Bootrom Rev R") + ROMX_LOAD("520-1102-03.b11", 0x0000, 0x4000, CRC(020bb0a8) SHA1(a7b60e89a40757975a5d345d57ea02781dea4f89), ROM_SKIP(1) | ROM_BIOS(1)) + ROMX_LOAD("520-1101-03.b10", 0x0001, 0x4000, CRC(b97c61f7) SHA1(9f08fe232cfc3da48539fa66673fc1f89a362b1e), ROM_SKIP(1) | ROM_BIOS(1)) + // There is an undumped revision Q, with roms: + //ROM_SYSTEM_BIOS( 8, "revq", "Bootrom Rev Q") + // ROMX_LOAD( "520-1104-02.b11", 0x0000, 0x4000, NO_DUMP, ROM_SKIP(1) | ROM_BIOS(8)) + // ROMX_LOAD( "520-1103-02.b10", 0x0001, 0x4000, NO_DUMP, ROM_SKIP(1) | ROM_BIOS(8)) + ROM_SYSTEM_BIOS( 2, "revn", "Bootrom Rev N") // SunOS 2.0 requires this bootrom version at a minimum; this version supports the sun-2 keyboard + ROMX_LOAD("revn.b11", 0x0000, 0x4000, CRC(b1e70965) SHA1(726b3ed9323750a1ae238cf6dccaed6ff5981ad1), ROM_SKIP(1) | ROM_BIOS(2)) // actual rom stickers had fallen off + ROMX_LOAD("revn.b10", 0x0001, 0x4000, CRC(95fd9242) SHA1(1eee2d291f4b18f6aafdde1a9521d88e454843b9), ROM_SKIP(1) | ROM_BIOS(2)) // " + ROM_SYSTEM_BIOS( 3, "revm", "Bootrom Rev M") // SunOS 1.0 apparently requires this bootrom revision; this version might only support the sun-1 keyboard? + ROMX_LOAD("sun2-revm-8.b11", 0x0000, 0x4000, CRC(98b8ae55) SHA1(55485f4d8fd1ebc218aa8527c8bb62752c34abf7), ROM_SKIP(1) | ROM_BIOS(3)) // handwritten label: "SUN2-RevM-8" + ROMX_LOAD("sun2-revm-0.b10", 0x0001, 0x4000, CRC(5117f431) SHA1(fce85c11ada1614152dde35bb329350f6fb2ecd9), ROM_SKIP(1) | ROM_BIOS(3)) // handwritten label: "SUN2-RevM-0" + + ROM_REGION(0x20, "idprom", ROMREGION_ERASEFF) + ROM_LOAD("sun2120-idprom.bin", 0x000000, 0x000020, CRC(eec8cd1d) SHA1(6a78dc0ea6f9cc7687cffea754d65864fb751ebf)) +ROM_END + +ROM_START( sun2_50 ) + ROM_REGION16_BE(0x8000, "bootprom", ROMREGION_ERASEFF) + // There is at least one undumped revision (Rev 1.1.2) which uses 27256 EPROMs; the sun2/50 board handles up to 27512 EPROMs + // bootrom rev Q + ROM_LOAD16_BYTE("250_q_8.rom", 0x0000, 0x4000, CRC(5bfacb5c) SHA1(ec7fb3fb0217b0138ba4748b7c79b8ff0cad896b)) + ROM_LOAD16_BYTE("250_q_0.rom", 0x0001, 0x4000, CRC(2ee29abe) SHA1(82f52b9f25e92387329581f7c8ba50a171784968)) + + ROM_REGION(0x20, "idprom", ROMREGION_ERASEFF) + ROM_LOAD("sun250-idprom.bin", 0x000000, 0x000020, CRC(927744ab) SHA1(d29302b69128165e69dd3a79b8c8d45f2163b88a)) +ROM_END + +} // anonymous namespace + + +/* Driver */ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1984, sun2_50, 0, 0, sun2vme, sun2, sun2_state, empty_init, "Sun Microsystems", "Sun 2/50", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1984, sun2_120, 0, 0, sun2mbus, sun2, sun2_state, empty_init, "Sun Microsystems", "Sun 2/120", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) |