summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/bbc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/bbc.cpp')
-rw-r--r--src/mame/machine/bbc.cpp1671
1 files changed, 0 insertions, 1671 deletions
diff --git a/src/mame/machine/bbc.cpp b/src/mame/machine/bbc.cpp
deleted file mode 100644
index bd284f53c6a..00000000000
--- a/src/mame/machine/bbc.cpp
+++ /dev/null
@@ -1,1671 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Gordon Jefferyes, Nigel Barnes
-/******************************************************************************
- BBC Model B
-
- MESS Driver By:
-
- Gordon Jefferyes
- mess_bbc@romvault.com
-
-******************************************************************************/
-
-#include <cctype>
-#include "emu.h"
-#include "cpu/m6502/m6502.h"
-#include "sound/tms5220.h"
-#include "machine/6522via.h"
-#include "machine/wd_fdc.h"
-#include "includes/bbc.h"
-#include "machine/mc146818.h"
-#include "bus/centronics/ctronics.h"
-#include "imagedev/cassette.h"
-
-
-TIMER_CALLBACK_MEMBER(bbc_state::reset_timer_cb)
-{
- m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
-}
-
-/****************************************
- BBC Model B memory handling functions
-****************************************/
-
-uint8_t bbc_state::bbc_ram_r(offs_t offset)
-{
- if (m_internal && m_internal->overrides_ram())
- return m_internal->ram_r(offset);
- else
- return m_ram->pointer()[offset & m_ram->mask()];
-}
-
-void bbc_state::bbc_ram_w(offs_t offset, uint8_t data)
-{
- if (m_internal && m_internal->overrides_ram())
- m_internal->ram_w(offset, data);
- else
- m_ram->pointer()[offset & m_ram->mask()] = data;
-}
-
-uint8_t bbc_state::bbc_romsel_r(offs_t offset)
-{
- if (m_internal && m_internal->overrides_rom())
- return m_internal->romsel_r(offset);
- else
- return 0xfe;
-}
-
-void bbc_state::bbc_romsel_w(offs_t offset, uint8_t data)
-{
- /* no sideways expansion board fitted so address only the 4 on board ROM sockets */
- m_romsel = data & 0x03;
-
- /* pass romsel to internal expansion board */
- if (m_internal && m_internal->overrides_rom())
- m_internal->romsel_w(offset, data);
-}
-
-uint8_t bbc_state::bbc_paged_r(offs_t offset)
-{
- uint8_t data;
-
- if (m_internal && m_internal->overrides_rom())
- {
- data = m_internal->paged_r(offset);
- }
- else
- {
- if (m_rom[m_romsel] && m_rom[m_romsel]->present())
- {
- data = m_rom[m_romsel]->read(offset);
- }
- else
- {
- data = m_region_swr->base()[offset + (m_romsel << 14)];
- }
- }
-
- return data;
-}
-
-void bbc_state::bbc_paged_w(offs_t offset, uint8_t data)
-{
- if (m_internal && m_internal->overrides_rom())
- {
- m_internal->paged_w(offset, data);
- }
- else
- {
- if (m_rom[m_romsel])
- {
- m_rom[m_romsel]->write(offset, data);
- }
- }
-}
-
-uint8_t bbc_state::bbc_mos_r(offs_t offset)
-{
- if (m_internal && m_internal->overrides_mos())
- return m_internal->mos_r(offset);
- else
- return m_region_mos->base()[offset];
-}
-
-void bbc_state::bbc_mos_w(offs_t offset, uint8_t data)
-{
- if (m_internal && m_internal->overrides_mos())
- m_internal->mos_w(offset, data);
-}
-
-uint8_t bbc_state::bbc_fred_r(offs_t offset)
-{
- uint8_t data = 0xff;
-
- data &= m_1mhzbus->fred_r(offset);
-
- if (m_cart[0])
- data &= m_cart[0]->read(offset, 1, 0, m_romsel & 0x01, 0, 0);
- if (m_cart[1])
- data &= m_cart[1]->read(offset, 1, 0, m_romsel & 0x01, 0, 0);
-
- return data;
-}
-
-void bbc_state::bbc_fred_w(offs_t offset, uint8_t data)
-{
- m_1mhzbus->fred_w(offset, data);
-
- if (m_cart[0])
- m_cart[0]->write(offset, data, 1, 0, m_romsel & 0x01, 0, 0);
- if (m_cart[1])
- m_cart[1]->write(offset, data, 1, 0, m_romsel & 0x01, 0, 0);
-}
-
-uint8_t bbc_state::bbc_jim_r(offs_t offset)
-{
- uint8_t data = 0xff;
-
- data &= m_1mhzbus->jim_r(offset);
-
- if(m_cart[0])
- data &= m_cart[0]->read(offset, 0, 1, m_romsel & 0x01, 0, 0);
- if (m_cart[1])
- data &= m_cart[1]->read(offset, 0, 1, m_romsel & 0x01, 0, 0);
-
- return data;
-}
-
-void bbc_state::bbc_jim_w(offs_t offset, uint8_t data)
-{
- m_1mhzbus->jim_w(offset, data);
-
- if (m_cart[0])
- m_cart[0]->write(offset, data, 0, 1, m_romsel & 0x01, 0, 0);
- if (m_cart[1])
- m_cart[1]->write(offset, data, 0, 1, m_romsel & 0x01, 0, 0);
-}
-
-
-/****************************************
- BBC Model B+ memory handling functions
-****************************************/
-
-uint8_t bbc_state::bbcbp_fetch_r(offs_t offset)
-{
- switch (offset & 0xf000)
- {
- case 0xa000:
- /* Code executing from sideways RAM between 0xa000-0xafff will access the shadow RAM (if selected) */
- if (m_vdusel && m_paged_ram)
- {
- m_bank2->set_base(m_ram->pointer() + 0xb000);
- }
- else
- {
- m_bank2->set_base(m_ram->pointer() + 0x3000);
- }
- break;
-
- case 0xc000:
- case 0xd000:
- /* Access shadow RAM if VDU drivers and shadow RAM selected */
- if (m_vdusel)
- {
- m_bank2->set_base(m_ram->pointer() + 0xb000);
- }
- else
- {
- m_bank2->set_base(m_ram->pointer() + 0x3000);
- }
- break;
-
- default:
- m_bank2->set_base(m_ram->pointer() + 0x3000);
- break;
- }
- return m_maincpu->space(AS_PROGRAM).read_byte(offset);
-}
-
-void bbc_state::bbcbp_romsel_w(offs_t offset, uint8_t data)
-{
- /* the BBC Model B+ addresses all 16 ROM sockets and extra 12K of RAM at 0x8000 and 20K of shadow RAM at 0x3000 */
- switch (offset & 0x07)
- {
- case 0x00:
- m_paged_ram = BIT(data, 7);
-
- m_romsel = data & 0x0f;
- break;
-
- case 0x04:
- /* the video display should now use this flag to display the shadow RAM memory */
- m_vdusel = BIT(data, 7);
- setvideoshadow(m_vdusel);
- break;
- }
-
- /* pass romsel to internal expansion board */
- if (m_internal && m_internal->overrides_rom())
- m_internal->romsel_w(offset, data);
-}
-
-uint8_t bbc_state::bbcbp_paged_r(offs_t offset)
-{
- uint8_t data;
- std::string region_tag;
-
- if (m_paged_ram && offset < 0x3000)
- {
- data = m_ram->pointer()[offset + 0x8000];
- }
- else
- {
- if (m_internal && m_internal->overrides_rom())
- {
- data = m_internal->paged_r(offset);
- }
- else
- {
- /* 32K sockets */
- if (m_rom[m_romsel & 0x0e] && m_rom[m_romsel & 0x0e]->present())
- {
- data = m_rom[m_romsel & 0x0e]->read(offset | (m_romsel & 0x01) << 14);
- }
- else
- {
- data = m_region_swr->base()[offset + (m_romsel << 14)];
- }
- }
- }
-
- return data;
-}
-
-void bbc_state::bbcbp_paged_w(offs_t offset, uint8_t data)
-{
- if (m_paged_ram && offset < 0x3000)
- {
- m_ram->pointer()[offset + 0x8000] = data;
- }
- else
- {
- if (m_internal && m_internal->overrides_rom())
- {
- m_internal->paged_w(offset, data);
- }
- else
- {
- /* 32K sockets */
- if (m_rom[m_romsel & 0x0e])
- {
- m_rom[m_romsel & 0x0e]->write(offset | (m_romsel & 0x01) << 14, data);
- }
- }
- }
-}
-
-
-/****************************************
- BBC Master memory handling functions
-****************************************/
-
-/*
- ROMSEL - &FE30 write only
- b7 RAM 1 = Page in ANDY &8000-&8FFF
- 0 = Page in ROM &8000-&8FFF
- b6 Not Used
- b5 Not Used
- b4 Not Used
- b3-b0 ROM/RAM Bank Select
-
- ACCCON - &FE34 read/write register
- b7 IRR 1 = Causes an IRQ to the processor
- b6 TST 1 = Selects &FC00-&FEFF read from OS-ROM
- b5 IFJ 1 = Internal 1MHz bus
- 0 = External 1MHz bus
- b4 ITU 1 = Internal Tube
- 0 = External Tube
- b3 Y 1 = Read/Write HAZEL &C000-&DFFF RAM
- 0 = Read/Write ROM &C000-&DFFF OS-ROM
- b2 X 1 = Read/Write LYNNE
- 0 = Read/Write main memory &3000-&8000
- b1 E 1 = Causes shadow if VDU code
- 0 = Main all the time
- b0 D 1 = Display LYNNE as screen
- 0 = Display main RAM screen
-
- HAZEL is the 8K of RAM used by the MOS, filing system, and other ROMs at &C000-&DFFF
-
- ANDY is the name of the 4K of RAM used by the MOS at &8000-&8FFF
-*/
-
-uint8_t bbc_state::bbcm_fetch_r(offs_t offset)
-{
- if (m_acccon_x || (m_acccon_e && offset >= 0xc000 && offset <= 0xdfff))
- {
- m_bank2->set_base(m_ram->pointer() + 0xb000);
- }
- else
- {
- m_bank2->set_base(m_ram->pointer() + 0x3000);
- }
- return m_maincpu->space(AS_PROGRAM).read_byte(offset);
-}
-
-uint8_t bbc_state::bbcm_acccon_r()
-{
- return m_acccon;
-}
-
-void bbc_state::bbcm_acccon_w(uint8_t data)
-{
- m_acccon = data;
-
- m_acccon_irr = BIT(data,7);
- m_acccon_tst = BIT(data,6);
- m_acccon_ifj = BIT(data,5);
- m_acccon_itu = BIT(data,4);
- m_acccon_y = BIT(data,3);
- m_acccon_x = BIT(data,2);
- m_acccon_e = BIT(data,1);
- m_acccon_d = BIT(data,0);
-
- /* Bit IRR causes Interrupt Request. */
- m_irqs->in_w<6>(m_acccon_irr);
-
- /* Bit D causes the CRT controller to display the contents of LYNNE. */
- setvideoshadow(m_acccon_d);
-
- /* Bit X causes all accesses to 0x3000-0x7fff to be re-directed to LYNNE.*/
- if (m_acccon_x)
- {
- m_bank2->set_base(m_ram->pointer() + 0xb000);
- }
- else
- {
- m_bank2->set_base(m_ram->pointer() + 0x3000);
- }
-
- /* Bit TST controls paging of ROM reads in the 0xfc00-0xfeff region */
- /* if 0 the I/O is paged for both reads and writes */
- /* if 1 the ROM is paged in for reads but writes still go to I/O */
- m_bankdev->set_bank(m_acccon_tst);
-}
-
-void bbc_state::bbcm_romsel_w(offs_t offset, uint8_t data)
-{
- m_paged_ram = BIT(data, 7);
- m_romsel = data & 0x0f;
-
- /* pass romsel to internal expansion board */
- if (m_internal && m_internal->overrides_rom())
- m_internal->romsel_w(offset, data);
-}
-
-uint8_t bbc_state::bbcm_paged_r(offs_t offset)
-{
- uint8_t data = 0xff;
-
- if (m_paged_ram && offset < 0x1000)
- {
- data = m_ram->pointer()[offset + 0x8000];
- }
- else
- {
- switch (m_romsel)
- {
- case 0: case 1:
- if (m_cart[0] && m_cart[0]->present())
- {
- data = m_cart[0]->read(offset, 0, 0, m_romsel & 0x01, 1, 0);
- }
- else
- {
- data = bus_video_data();
- }
- break;
- case 2: case 3:
- if (m_cart[1] && m_cart[1]->present())
- {
- data = m_cart[1]->read(offset, 0, 0, m_romsel & 0x01, 1, 0);
- }
- else
- {
- data = bus_video_data();
- }
- break;
- default:
- if (m_internal && m_internal->overrides_rom())
- {
- data = m_internal->paged_r(offset);
- }
- else
- {
- switch (m_romsel)
- {
- case 4: case 5: case 6: case 7:
- /* 32K sockets */
- if (m_rom[m_romsel & 0x0e] && m_rom[m_romsel & 0x0e]->present())
- {
- data = m_rom[m_romsel & 0x0e]->read(offset | (m_romsel & 0x01) << 14);
- }
- else
- {
- data = m_region_swr->base()[offset + (m_romsel << 14)];
- }
- break;
- default:
- /* 16K sockets */
- if (m_rom[m_romsel] && m_rom[m_romsel]->present())
- {
- data = m_rom[m_romsel]->read(offset);
- }
- else
- {
- data = m_region_swr->base()[offset + (m_romsel << 14)];
- }
- break;
- }
- }
- break;
- }
- }
-
- return data;
-}
-
-void bbc_state::bbcm_paged_w(offs_t offset, uint8_t data)
-{
- if (m_paged_ram && offset < 0x1000)
- {
- m_ram->pointer()[offset + 0x8000] = data;
- }
- else
- {
- switch (m_romsel)
- {
- case 0: case 1:
- if (m_cart[0])
- {
- m_cart[0]->write(offset, data, 0, 0, m_romsel & 0x01, 1, 0);
- }
- break;
- case 2: case 3:
- if (m_cart[1])
- {
- m_cart[1]->write(offset, data, 0, 0, m_romsel & 0x01, 1, 0);
- }
- break;
- default:
- if (m_internal && m_internal->overrides_rom())
- {
- m_internal->paged_w(offset, data);
- }
- else
- {
- switch (m_romsel)
- {
- case 4: case 5: case 6: case 7:
- /* 32K sockets */
- if (m_rom[m_romsel & 0x0e])
- {
- m_rom[m_romsel & 0x0e]->write(offset | (m_romsel & 0x01) << 14, data);
- }
- break;
- default:
- /* 16K sockets */
- if (m_rom[m_romsel])
- {
- m_rom[m_romsel]->write(offset, data);
- }
- break;
- }
- }
- break;
- }
- }
-}
-
-uint8_t bbc_state::bbcmc_paged_r(offs_t offset)
-{
- uint8_t data = 0xff;
-
- if (m_paged_ram && offset < 0x1000)
- {
- data = m_ram->pointer()[offset + 0x8000];
- }
- else
- {
- if (m_internal && m_internal->overrides_rom())
- {
- data = m_internal->paged_r(offset);
- }
- else
- {
- switch (m_romsel)
- {
- case 0: case 1: case 4: case 5: case 6: case 7:
- /* 32K sockets */
- if (m_rom[m_romsel & 0x0e] && m_rom[m_romsel & 0x0e]->present())
- {
- data = m_rom[m_romsel & 0x0e]->read(offset | (m_romsel & 0x01) << 14);
- }
- else
- {
- data = m_region_swr->base()[offset + (m_romsel << 14)];
- }
- break;
- default:
- /* 16K sockets */
- if (m_rom[m_romsel] && m_rom[m_romsel]->present())
- {
- data = m_rom[m_romsel]->read(offset);
- }
- else
- {
- data = m_region_swr->base()[offset + (m_romsel << 14)];
- }
- break;
- }
- }
- }
-
- return data;
-}
-
-void bbc_state::bbcmc_paged_w(offs_t offset, uint8_t data)
-{
- if (m_paged_ram && offset < 0x1000)
- {
- m_ram->pointer()[offset + 0x8000] = data;
- }
- else
- {
- if (m_internal && m_internal->overrides_rom())
- {
- m_internal->paged_w(offset, data);
- }
- else
- {
- switch (m_romsel)
- {
- case 0: case 1: case 4: case 5: case 6: case 7:
- /* 32K sockets */
- if (m_rom[m_romsel & 0x0e])
- {
- m_rom[m_romsel & 0x0e]->write(offset | (m_romsel & 0x01) << 14, data);
- }
- break;
- default:
- /* 16K sockets */
- if (m_rom[m_romsel])
- {
- m_rom[m_romsel]->write(offset, data);
- }
- break;
- }
- }
- }
-}
-
-uint8_t bbc_state::bbcm_hazel_r(offs_t offset)
-{
- uint8_t data;
-
- if (m_acccon_y)
- {
- data = m_ram->pointer()[offset + 0x9000];
- }
- else
- {
- if (m_internal && m_internal->overrides_mos())
- data = m_internal->mos_r(offset);
- else
- data = m_region_mos->base()[offset];
- }
-
- return data;
-}
-
-void bbc_state::bbcm_hazel_w(offs_t offset, uint8_t data)
-{
- if (m_acccon_y)
- {
- m_ram->pointer()[offset + 0x9000] = data;
- }
-}
-
-uint8_t bbc_state::bbcm_tube_r(offs_t offset)
-{
- uint8_t data = 0xfe;
-
- if (m_acccon_itu)
- {
- /* internal Tube */
- if (m_intube) data = m_intube->host_r(offset);
- }
- else
- {
- /* external Tube */
- if (m_extube) data = m_extube->host_r(offset);
- }
-
- return data;
-}
-
-void bbc_state::bbcm_tube_w(offs_t offset, uint8_t data)
-{
- if (m_acccon_itu)
- {
- /* internal Tube */
- if (m_intube) m_intube->host_w(offset, data);
- }
- else
- {
- /* external Tube */
- if (m_extube) m_extube->host_w(offset, data);
- }
-}
-
-
-/******************************************************************************
-
-System VIA 6522
-
-PA0-PA7
-Port A forms a slow data bus to the keyboard sound and speech processors
-PortA Keyboard
-D0 Pin 8
-D1 Pin 9
-D2 Pin 10
-D3 Pin 11
-D4 Pin 5
-D5 Pin 6
-D6 Pin 7
-D7 Pin 12
-
-PB0-PB2 outputs
----------------
-These 3 outputs form the address to an 8 bit addressable latch.
-(IC32 74LS259)
-
-PB3 output
-----------
-This output holds the data to be written to the selected
-addressable latch bit.
-
-PB4 and PB5 inputs
-------------------
-These are the inputs from the joystick FIRE buttons. They are
-normally at logic 1 with no button pressed and change to 0
-when a button is pressed.
-
-PB6 and PB7 inputs from the speech processor (model B and B+)
--------------------------------------------------------------
-PB6 is the speech processor 'ready' output and PB7 is from the
-speech processor 'interrupt' output.
-
-PB6 and PB7 outputs to Master CMOS RAM/RTC
-------------------------------------------
-PB6 operates the 146818 chip enable when set to '1'. PB7 operates
-the 146818 address strobe line.
-
-CA1 input
----------
-This is the vertical sync input from the 6845. CA1 is set up to
-interrupt the 6502 every 20ms (50Hz) as a vertical sync from
-the video circuitry is detected. The operation system changes
-the display flash colours on this interrupt so that they occur
-during the screen blanking period.
-----------------------------------------------------------------
-This is required for a lot of time function within the machine
-and must be triggered every 20ms. (Should check at some point
-how this 20ms signal is made, and see if none standard shaped
-screen modes change this time period.)
-
-CB1 input
----------
-The CB1 input is the end of conversion (EOC) signal from the
-7002 analogue to digital converter. It can be used to interrupt
-the 6502 whenever a conversion is complete.
-
-CA2 input
----------
-This input comes from the keyboard circuit, and is used to
-generate an interrupt whenever a key is pressed. See the
-keyboard circuit section for more details.
-
-CB2 input
----------
-This is the light pen strobe signal (LPSTB) from the light pen.
-If also connects to the 6845 video processor,
-CB2 can be programmed to interrupt the processor whenever
-a light pen strobe occurs.
-----------------------------------------------------------------
-CB2 is not needed in the initial emulation
-and should be set to logic low, should be mapped through to
-a light pen emulator later.
-
-IRQ output
-This connects to the IRQ line of the 6502
-
-
-The addressable latch
-This 8 bit addressable latch is operated from port B lines 0-3.
-PB0-PB2 are set to the required address of the output bit to be set.
-PB3 is set to the value which should be programmed at that bit.
-The function of the 8 output bits from this latch are:-
-
-B0 - Write Enable to the sound generator IC
-B1 - READ select on the speech processor
-B2 - WRITE select on the speech processor
-B3 - Keyboard write enable
-B4,B5 - these two outputs define the number to be added to the
-start of screen address in hardware to control hardware scrolling:-
-Mode Size Start of screen Number to add B5 B4
-0,1,2 20K &3000 12K 1 1
-3 16K &4000 16K 0 0
-4,5 10K &5800 (or &1800) 22K 1 0
-6 8K &6000 (or &2000) 24K 0 1
-B6 - Operates the CAPS lock LED (Pin 17 keyboard connector)
-B7 - Operates the SHIFT lock LED (Pin 16 keyboard connector)
-******************************************************************************/
-
-
-INTERRUPT_GEN_MEMBER(bbc_state::bbcb_keyscan)
-{
- /* only do auto scan if keyboard is not enabled */
- if (m_latch->q3_r())
- {
- /* KBD IC1 4 bit addressable counter */
- /* KBD IC3 4 to 10 line decoder */
- /* keyboard not enabled so increment counter */
- m_column = (m_column + 1) % 16;
-
- /* KBD IC4 8 input NAND gate */
- /* set the value of via_system ca2, by checking for any keys
- being pressed on the selected m_column */
- if ((m_keyboard[m_column]->read() | 0x01) != 0xff)
- {
- m_via6522_0->write_ca2(1);
- }
- else
- {
- m_via6522_0->write_ca2(0);
- }
- }
-}
-
-
-int bbc_state::bbc_keyboard(int data)
-{
- int bit;
- int row;
- int res;
-
- m_column = data & 0x0f;
- row = (data>>4) & 0x07;
-
- bit = 0;
-
- res = m_keyboard[m_column]->read();
-
- /* Normal keyboard result */
- if ((res & (1<<row)) == 0)
- {
- bit = 1;
- }
-
- if ((res | 1) != 0xff)
- {
- m_via6522_0->write_ca2(1);
- }
- else
- {
- m_via6522_0->write_ca2(0);
- }
-
- return (data & 0x7f) | (bit<<7);
-}
-
-
-WRITE_LINE_MEMBER(bbc_state::snd_enable_w)
-{
- if (!state && m_sn)
- {
- m_sn->write(m_via_system_porta);
- }
-}
-
-WRITE_LINE_MEMBER(bbc_state::speech_rsq_w)
-{
- if (m_tms)
- {
- m_tms->rsq_w(state);
- if (!m_latch->q1_r() && m_latch->q2_r())
- {
- m_via_system_porta = m_tms->status_r();
- }
- }
-}
-
-WRITE_LINE_MEMBER(bbc_state::speech_wsq_w)
-{
- /* Write select on the speech processor */
- if (m_tms)
- {
- m_tms->wsq_w(state);
- if (m_latch->q1_r() && !m_latch->q2_r())
- {
- m_tms->data_w(m_via_system_porta);
- }
- }
-}
-
-WRITE_LINE_MEMBER(bbc_state::kbd_enable_w)
-{
- if (!state)
- {
- m_via_system_porta = bbc_keyboard(m_via_system_porta);
- }
-}
-
-
-void bbc_state::mc146818_set()
-{
- /* if chip enabled */
- if (m_mc146818_ce)
- {
- /* if data select is set then access the data in the 146818 */
- if (m_latch->q2_r()) // DS
- {
- if (m_latch->q1_r()) // WR
- {
- m_via_system_porta = m_rtc->read(1);
- }
- else
- {
- m_rtc->write(1, m_via_system_porta);
- }
- }
-
- /* if address select is set then set the address in the 146818 */
- if (m_mc146818_as)
- {
- m_rtc->write(0, m_via_system_porta);
- }
- }
-}
-
-
-uint8_t bbc_state::via_system_porta_r()
-{
- return m_via_system_porta;
-}
-
-void bbc_state::via_system_porta_w(uint8_t data)
-{
- m_via_system_porta = data;
-
- /* Write enable to the sound generator */
- //if (!m_latch->q0_r() && m_sn)
- //{
- // m_sn->write(m_via_system_porta);
- //}
- /* Keyboard write enable */
- if (!m_latch->q3_r())
- {
- m_via_system_porta = bbc_keyboard(m_via_system_porta);
- }
-
- if (m_rtc)
- {
- mc146818_set();
- }
-}
-
-
-uint8_t bbc_state::via_system_portb_r()
-{
- uint8_t data = 0xff;
-
- /* B/B+/Master only */
- if (m_analog)
- {
- data &= ~0x30;
- data |= m_analog->pb_r();
- }
-
- /* Master Compact only */
- if (m_i2cmem)
- {
- data &= ~0x30;
- data |= m_i2cmem->read_sda() << 4;
- }
-
- /* B/B+ only */
- if (m_tms)
- {
- // TODO: Fix speech, it's never worked
- //data &= ~0xc0;
- //data |= m_tms->intq_r() << 6;
- //data |= m_tms->readyq_r() << 7;
- }
-
- return data;
-}
-
-void bbc_state::via_system_portb_w(uint8_t data)
-{
- m_latch->write_nibble_d3(data);
-
- /* Master only */
- if (m_rtc)
- {
- /* set Chip Enable and Address Strobe lines */
- m_mc146818_ce = BIT(data, 6);
- m_mc146818_as = BIT(data, 7);
- mc146818_set();
- }
-
- /* Master Compact only */
- if (m_i2cmem)
- {
- m_i2cmem->write_sda(BIT(data, 4));
- m_i2cmem->write_scl(BIT(data, 5));
- }
-}
-
-
-WRITE_LINE_MEMBER(bbc_state::lpstb_w)
-{
- m_via6522_0->write_cb2(state);
- if (!state)
- m_hd6845->assert_light_pen_input();
-}
-
-/**************************************
- BBC Joystick Support
-**************************************/
-
-int bbc_state::get_analogue_input(int channel_number)
-{
- if (m_analog)
- return ((0xff - m_analog->ch_r(channel_number)) << 8);
- else
- return 0xff;
-}
-
-void bbc_state::upd7002_eoc(int data)
-{
- m_via6522_0->write_cb1(data);
-}
-
-/***************************************
- BBC 2C199 Serial Interface Cassette
-****************************************/
-
-
-void bbc_state::mc6850_receive_clock(int new_clock)
-{
- m_rxd_cass = new_clock;
- update_acia_rxd();
-
- //
- // Somehow the "serial processor" generates 16 clock signals towards
- // the 6850. Exact details are unknown, faking it with the following
- // loop.
- //
- for (int i = 0; i < 16; i++ )
- {
- m_acia->write_rxc(1);
- m_acia->write_rxc(0);
- }
-}
-
-TIMER_CALLBACK_MEMBER(bbc_state::tape_timer_cb)
-{
- if ( m_cass_out_enabled )
- {
- // 0 = 18-18 18-17-1
- // 1 = 9-9-9-9 9-9-9-8-1
-
- switch ( m_cass_out_samples_to_go )
- {
- case 0:
- if ( m_cass_out_phase == 0 )
- {
- // get bit value
- m_cass_out_bit = m_txd;
- if ( m_cass_out_bit )
- {
- m_cass_out_phase = 3;
- m_cass_out_samples_to_go = 9;
- }
- else
- {
- m_cass_out_phase = 1;
- m_cass_out_samples_to_go = 18;
- }
- m_cassette->output( +1.0 );
- }
- else
- {
- // switch phase
- m_cass_out_phase--;
- m_cass_out_samples_to_go = m_cass_out_bit ? 9 : 18;
- m_cassette->output( ( m_cass_out_phase & 1 ) ? +1.0 : -1.0 );
- }
- break;
- case 1:
- if ( m_cass_out_phase == 0 )
- {
- m_cassette->output( 0.0 );
- }
- break;
- }
-
- m_cass_out_samples_to_go--;
- }
- else
- {
- double dev_val = m_cassette->input();
-
- // look for edges on the cassette wave
- if (((dev_val>=0.0) && (m_last_dev_val<0.0)) || ((dev_val<0.0) && (m_last_dev_val>=0.0)))
- {
- if (m_wav_len>(9*3))
- {
- //this is too long to receive anything so reset the serial IC. This is a hack, this should be done as a timer in the MC6850 code.
- logerror ("Cassette length %d\n",m_wav_len);
- m_nr_high_tones = 0;
- m_dcd_cass = 0;
- update_acia_dcd();
- m_len0=0;
- m_len1=0;
- m_len2=0;
- m_len3=0;
- m_wav_len=0;
- }
-
- m_len3=m_len2;
- m_len2=m_len1;
- m_len1=m_len0;
- m_len0=m_wav_len;
-
- m_wav_len=0;
- logerror ("cassette %d %d %d %d\n",m_len3,m_len2,m_len1,m_len0);
-
- if ((m_len0+m_len1)>=(18+18-5))
- {
- /* Clock a 0 onto the serial line */
- logerror("Serial value 0\n");
- m_nr_high_tones = 0;
- m_dcd_cass = 0;
- update_acia_dcd();
- mc6850_receive_clock(0);
- m_len0=0;
- m_len1=0;
- m_len2=0;
- m_len3=0;
- }
-
- if (((m_len0+m_len1+m_len2+m_len3)<=41) && (m_len3!=0))
- {
- /* Clock a 1 onto the serial line */
- logerror("Serial value 1\n");
- m_nr_high_tones++;
- if ( m_nr_high_tones > 100 )
- {
- m_dcd_cass = 1;
- update_acia_dcd();
- }
- mc6850_receive_clock(1);
- m_len0=0;
- m_len1=0;
- m_len2=0;
- m_len3=0;
- }
- }
-
- m_wav_len++;
- m_last_dev_val=dev_val;
- }
-}
-
-WRITE_LINE_MEMBER(bbc_state::write_rxd)
-{
- m_rxd_serial = state;
- update_acia_rxd();
-}
-
-void bbc_state::update_acia_rxd()
-{
- m_acia->write_rxd(BIT(m_serproc_data, 6) ? m_rxd_serial : m_rxd_cass);
-}
-
-
-WRITE_LINE_MEMBER(bbc_state::write_dcd)
-{
- m_dcd_serial = state;
- update_acia_dcd();
-}
-
-void bbc_state::update_acia_dcd()
-{
- m_acia->write_dcd(BIT(m_serproc_data, 6) ? m_dcd_serial : m_dcd_cass);
-}
-
-
-WRITE_LINE_MEMBER(bbc_state::write_cts)
-{
- m_cts_serial = state;
- update_acia_cts();
-}
-
-void bbc_state::update_acia_cts()
-{
- m_acia->write_cts(BIT(m_serproc_data, 6) ? m_cts_serial : 0);
-}
-
-
-WRITE_LINE_MEMBER(bbc_state::write_rts)
-{
- if (BIT(m_serproc_data, 6))
- {
- m_rs232->write_rts(state);
- m_cass_out_enabled = 0;
- }
- else
- {
- m_cass_out_enabled = state ? 0 : 1;
- }
-}
-
-
-WRITE_LINE_MEMBER(bbc_state::write_txd)
-{
- if (BIT(m_serproc_data, 6))
- {
- m_rs232->write_txd(state);
- }
- else
- {
- m_txd = state;
- }
-}
-
-
-void bbc_state::cassette_motor(bool motor_state)
-{
- const bool prev_state = ((m_cassette->get_state() & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_ENABLED) ? true : false;
-
- /* cassette relay sound */
- if (prev_state != motor_state)
- m_samples->start(0, motor_state ? 1 : 0);
-
- if (motor_state)
- {
- m_cassette->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
- m_tape_timer->adjust(attotime::zero, 0, attotime::from_hz(44100));
- }
- else
- {
- m_cassette->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
- m_tape_timer->reset();
- m_len0 = 0;
- m_len1 = 0;
- m_len2 = 0;
- m_len3 = 0;
- m_wav_len = 0;
- m_cass_out_phase = 0;
- m_cass_out_samples_to_go = 4;
- }
- m_motor_led = !motor_state;
-}
-
-
-/*
- Serial processor control
- x--- ---- - Motor OFF(0)/ON(1)
- -x-- ---- - Cassette(0)/RS243 input(1)
- --xx x--- - Receive baud rate generator control
- ---- -xxx - Transmit baud rate generator control
- These possible settings apply to both the receive
- and transmit baud generator control bits:
- 000 - 16MHz / 13 / 1 - 19200 baud
- 001 - 16MHz / 13 / 16 - 1200 baud
- 010 - 16MHz / 13 / 4 - 4800 baud
- 011 - 16MHz / 13 / 128 - 150 baud
- 100 - 16MHz / 13 / 2 - 9600 baud
- 101 - 16MHz / 13 / 64 - 300 baud
- 110 - 16MHz / 13 / 8 - 2400 baud
- 110 - 16MHz / 13 / 256 - 75 baud
-*/
-
-void bbc_state::serial_ula_w(uint8_t data)
-{
- static const int serial_clocks[8] =
- {
- 1, // 000
- 16, // 001
- 4, // 010
- 128, // 011
- 2, // 100
- 64, // 101
- 8, // 110
- 256 // 111
- };
-
- m_serproc_data = data;
- update_acia_rxd();
- update_acia_dcd();
- update_acia_cts();
- if (m_cassette) cassette_motor(BIT(m_serproc_data, 7));
-
- // Set transmit clock rate
- m_acia_clock->set_clock_scale( (double) 1 / serial_clocks[ data & 0x07 ] );
-}
-
-WRITE_LINE_MEMBER(bbc_state::write_acia_clock)
-{
- m_acia->write_txc(state);
-
- if (BIT(m_serproc_data, 6))
- m_acia->write_rxc(state);
-}
-
-
-/**************************************
- 1MHz Bus interrupts
-***************************************/
-
-
-WRITE_LINE_MEMBER(bbc_state::bus_nmi_w)
-{
- m_bus_nmi = state;
- update_nmi();
-}
-
-
-/**************************************
- WD1770 disc control function
-***************************************/
-
-
-void bbc_state::update_nmi()
-{
- if (m_fdc_irq || m_fdc_drq || m_adlc_irq || m_bus_nmi)
- {
- m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
- }
- else
- {
- m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
- }
-}
-
-WRITE_LINE_MEMBER(bbc_state::fdc_intrq_w)
-{
- m_fdc_irq = state;
- update_nmi();
-}
-
-WRITE_LINE_MEMBER(bbc_state::fdc_drq_w)
-{
- m_fdc_drq = state;
- update_nmi();
-}
-
-/*
- B+ drive control:
-
- Bit Meaning
- -----------------
- 7,6 Not used.
- 5 Reset drive controller chip. (0 = reset controller, 1 = no reset)
- 4 Interrupt Enable (0 = enable int, 1 = disable int)
- 3 Double density select (0 = double, 1 = single).
- 2 Side select (0 = side 0, 1 = side 1).
- 1 Drive select 1.
- 0 Drive select 0.
-*/
-
-void bbc_state::bbcbp_drive_control_w(uint8_t data)
-{
- floppy_image_device *floppy = nullptr;
-
- // bit 0, 1: drive select
- if (BIT(data, 0)) floppy = m_wd_fdc->subdevice<floppy_connector>("0")->get_device();
- if (BIT(data, 1)) floppy = m_wd_fdc->subdevice<floppy_connector>("1")->get_device();
- m_wd_fdc->set_floppy(floppy);
-
- // bit 2: side select
- if (floppy)
- floppy->ss_w(BIT(data, 2));
-
- // bit 3: density
- m_wd_fdc->dden_w(BIT(data, 3));
-
- // bit 4: interrupt enable (S5 wire link not fitted)
-
- // bit 5: reset
- m_wd_fdc->mr_w(BIT(data, 5));
-}
-
-/*
- Master drive control:
-
- Bit Meaning
- -----------------
- 7,6 Not used.
- 5 Double density select (0 = double, 1 = single).
- 4 Side select (0 = side 0, 1 = side 1).
- 3 Drive select 2.
- 2 Reset drive controller chip. (0 = reset controller, 1 = no reset)
- 1 Drive select 1.
- 0 Drive select 0.
-*/
-
-void bbc_state::bbcm_drive_control_w(uint8_t data)
-{
- floppy_image_device *floppy = nullptr;
-
- // bit 0, 1, 3: drive select
- if (BIT(data, 0)) floppy = m_wd_fdc->subdevice<floppy_connector>("0")->get_device();
- if (BIT(data, 1)) floppy = m_wd_fdc->subdevice<floppy_connector>("1")->get_device();
- m_wd_fdc->set_floppy(floppy);
-
- // bit 4: side select
- if (floppy)
- floppy->ss_w(BIT(data, 4));
-
- // bit 5: density
- m_wd_fdc->dden_w(BIT(data, 5));
-
- // bit 2: reset
- m_wd_fdc->mr_w(BIT(data, 2));
-}
-
-
-/**************************************
- Machine Initialisation functions
-***************************************/
-
-void bbc_state::init_bbc()
-{
- m_rxd_cass = 0;
- m_nr_high_tones = 0;
- m_serproc_data = 0;
- m_cass_out_enabled = 0;
- m_tape_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bbc_state::tape_timer_cb), this));
- m_reset_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bbc_state::reset_timer_cb), this));
-
- /* vertical sync pulse from video circuit */
- m_via6522_0->write_ca1(1);
-
- /* light pen strobe detect (not emulated) */
- m_via6522_0->write_cb2(1);
-
- update_palette(monitor_type::COLOUR);
-}
-
-void bbc_state::init_ltmp()
-{
- init_bbc();
-
- /* LTM machines used a 9" Hantarex MT3000 green monitor */
- update_palette(monitor_type::GREEN);
-}
-
-void bbc_state::init_cfa()
-{
- init_bbc();
-
- update_palette(monitor_type::GREEN);
-}
-
-
-/**************************************
- Helpers for ROM management
-***************************************/
-
-std::string bbc_state::get_rom_name(uint8_t* header)
-{
- std::string title = "";
- /* check for valid copyright */
- uint8_t offset = header[7];
- if (header[offset + 0] == 0 && header[offset + 1] == '(' && header[offset + 2] == 'C' && header[offset + 3] == ')')
- {
- /* extract ROM title from header*/
- for (int pos = 9; pos < header[7]; pos++)
- title.append(1, header[pos] == 0x00 ? 0x20 : header[pos]);
- }
- return title;
-}
-
-void bbc_state::insert_device_rom(memory_region *rom)
-{
- std::string region_tag;
-
- if (rom == nullptr) return;
-
- /* check whether ROM already present */
- for (int bank = 15; bank >= 0; bank--)
- {
- /* compare first 1K of bank with what we want to insert */
- if (!memcmp(rom->base(), m_region_swr->base() + (bank * 0x4000), 0x400))
- {
- osd_printf_verbose("Found '%s' in romslot%d\n", get_rom_name(rom->base()), bank);
- return;
- }
- }
-
- /* iterate over romslots until an empty socket is found */
- for (int bank = 15; bank >= 0; bank--)
- {
- /* if bank has socket and is empty */
- if (m_rom[bank] && !memregion(region_tag.assign(m_rom[bank]->tag()).append(BBC_ROM_REGION_TAG).c_str()))
- {
- uint8_t *swr = m_region_swr->base() + (bank * 0x4000);
- switch (rom->bytes())
- {
- case 0x8000:
- /* 32K (or 2x16K) ROM, check whether ROM exists in this and next bank */
- if (swr[0x0006] == 0xff && swr[0x4006] == 0xff)
- {
- memcpy(m_region_swr->base() + (bank * 0x4000), rom->base(), rom->bytes());
- osd_printf_verbose("Inserting '%s' into romslot%d\n", get_rom_name(rom->base() + 0x4000), bank + 1);
- osd_printf_verbose("Inserting '%s' into romslot%d\n", get_rom_name(rom->base()), bank);
- return;
- }
- break;
- case 0x4000:
- case 0x2000:
- /* 16/8K ROM, check whether ROM exists in this bank */
- if (swr[0x0006] == 0xff)
- {
- memcpy(m_region_swr->base() + (bank * 0x4000), rom->base(), rom->bytes());
- osd_printf_verbose("Inserting '%s' into romslot%d\n", get_rom_name(rom->base()), bank);
- return;
- }
- break;
- }
- }
- }
-
- /* unable to insert ROM */
- fatalerror("Unable to insert '%s'. Add a sideways ROM board for more sockets.\n", get_rom_name(rom->base()).c_str());
-}
-
-void bbc_state::setup_device_roms()
-{
- std::string region_tag;
- memory_region *rom_region;
- device_t* exp_device;
- device_t* ext_device;
-
- /* insert ROM(s) for internal expansion boards */
- if (m_internal && (exp_device = dynamic_cast<device_t*>(m_internal->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- }
-
- /* insert ROM for FDC devices (BBC Model B only), always place into romslot 0 */
- if (m_fdc && m_fdc->insert_rom() && (exp_device = dynamic_cast<device_t*>(m_fdc->get_card_device())))
- {
- if (exp_device->memregion("dfs_rom"))
- {
- memcpy(m_region_swr->base(), exp_device->memregion("dfs_rom")->base(), exp_device->memregion("dfs_rom")->bytes());
- }
- }
-
- /* configure romslots */
- for (int i = 0; i < 16; i++)
- {
- if (m_rom[i] && (rom_region = memregion(region_tag.assign(m_rom[i]->tag()).append(BBC_ROM_REGION_TAG).c_str())))
- {
- if (m_rom[i]->get_rom_size())
- memcpy(m_region_swr->base() + (i * 0x4000), rom_region->base(), std::min((int32_t)m_rom[i]->get_slot_size(), (int32_t)m_rom[i]->get_rom_size()));
- else
- memset(m_region_swr->base() + (i * 0x4000), 0, 0x4000);
- }
- }
-
- /* configure cartslots */
- for (int i = 0; i < 2; i++)
- {
- if (m_cart[i] && (rom_region = memregion(region_tag.assign(m_cart[i]->tag()).append(ELECTRON_CART_ROM_REGION_TAG).c_str())))
- {
- memcpy(m_region_swr->base() + (i * 0x8000), rom_region->base(), rom_region->bytes());
- }
- }
-
- /* insert ROM(s) for Expansion port devices (Compact only), with additional Mertec slots */
- if (m_exp && (ext_device = dynamic_cast<device_t*>(m_exp->get_card_device())))
- {
- /* only the Mertec device has ext_rom region and should be placed in romslots 0,1 */
- if (ext_device->memregion("ext_rom"))
- {
- memcpy(m_region_swr->base(), ext_device->memregion("ext_rom")->base(), ext_device->memregion("ext_rom")->bytes());
- }
-
- bbc_analogue_slot_device* analogue_port = ext_device->subdevice<bbc_analogue_slot_device>("analogue");
- if (analogue_port && (exp_device = dynamic_cast<device_t*>(analogue_port->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- }
-
- bbc_userport_slot_device* user_port = ext_device->subdevice<bbc_userport_slot_device>("userport");
- if (user_port && (exp_device = dynamic_cast<device_t*>(user_port->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- }
-
- bbc_1mhzbus_slot_device* exp_port = ext_device->subdevice<bbc_1mhzbus_slot_device>("2mhzbus");
- while (exp_port != nullptr)
- {
- if ((exp_device = dynamic_cast<device_t*>(exp_port->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- exp_port = exp_device->subdevice<bbc_1mhzbus_slot_device>("1mhzbus");
- }
- else
- {
- exp_port = nullptr;
- }
- }
- }
-
- /* insert ROM(s) for 1MHz bus devices, with pass-through */
- if (m_1mhzbus)
- {
- bbc_1mhzbus_slot_device* exp_port = m_1mhzbus;
- while (exp_port != nullptr)
- {
- if ((exp_device = dynamic_cast<device_t*>(exp_port->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- exp_port = exp_device->subdevice<bbc_1mhzbus_slot_device>("1mhzbus");
- }
- else
- {
- exp_port = nullptr;
- }
- }
- }
-
- /* insert ROM(s) for Tube devices */
- if (m_tube && m_tube->insert_rom() && (exp_device = dynamic_cast<device_t*>(m_tube->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- }
- if (m_intube && m_intube->insert_rom() && (exp_device = dynamic_cast<device_t*>(m_intube->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- }
- if (m_extube && m_extube->insert_rom() && (exp_device = dynamic_cast<device_t*>(m_extube->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- }
-
- /* insert ROM(s) for Userport devices */
- if (m_userport && (exp_device = dynamic_cast<device_t*>(m_userport->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- }
-
- /* insert ROM(s) for Analogue port devices */
- if (m_analog && (exp_device = dynamic_cast<device_t*>(m_analog->get_card_device())))
- {
- insert_device_rom(exp_device->memregion("exp_rom"));
- }
-
- /* list all inserted ROMs */
- for (int i = 15; i >= 0; i--)
- {
- osd_printf_verbose("ROM %X : %s\n", i, get_rom_name(m_region_swr->base() + (i * 0x4000)));
- }
-}
-
-
-/**************************************
- Machine start/reset
-***************************************/
-
-void bbc_state::machine_start()
-{
- setup_device_roms();
-
- m_motor_led.resolve();
-}
-
-void bbc_state::machine_reset()
-{
- /* install econet hardware */
- if (m_bbcconfig.read_safe(0) & 0x04)
- m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xfea0, 0xfebf, read8sm_delegate(*m_adlc, FUNC(mc6854_device::read)), write8sm_delegate(*m_adlc, FUNC(mc6854_device::write)));
- else
- m_maincpu->space(AS_PROGRAM).install_read_handler(0xfea0, 0xfebf, read8smo_delegate(*this, FUNC(bbc_state::bbc_fe_r)));
-
- /* power-on reset timer, should produce "boo...beep" startup sound before sn76496 is initialised */
- //m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
- //m_reset_timer->adjust(attotime::from_msec(138.6));
-}
-
-
-void bbcbp_state::machine_start()
-{
- setup_device_roms();
-
- m_motor_led.resolve();
-}
-
-void bbcbp_state::machine_reset()
-{
- /* bank 1 regular lower RAM from 0000 to 2fff */
- m_bank1->set_base(m_ram->pointer());
- /* bank 2 screen/shadow RAM from 3000 to 7fff */
- m_bank2->set_base(m_ram->pointer() + 0x3000);
-}
-
-
-void bbcm_state::machine_start()
-{
- setup_device_roms();
-
- m_motor_led.resolve();
- m_power_led.resolve();
-
- m_power_led = 0;
-}
-
-void bbcm_state::machine_reset()
-{
- /* bank 1 regular lower RAM from 0000 to 2fff */
- m_bank1->set_base(m_ram->pointer());
- /* bank 2 screen/shadow RAM from 3000 to 7fff */
- m_bank2->set_base(m_ram->pointer() + 0x3000);
-
- m_bankdev->set_bank(0);
-}