mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
docs: causality audit -- the host-port failure is pre-existing, not caused by the two MAME edits
Four-config A/B (IRQ wiring kept in all four; both mc68681 edits reverted in cfg 4): the console line and L3FA6E4B0's return are identical (HOST PORT - 15 / 6) in cfg 1-4. Verdict: PRE-EXISTING. Neither timing edit causes or relocates the failure. Methodology correction: hp_ret.lua's labels were on the wrong rets addresses. The real returns are L3FA6E4B0 -> 6, L3FA71BC0 -> 0x00900040, L3FA753D0 -> 0x00000408, L3FA767E0 -> 0. hp_ret2.lua fixes the addresses. What 6 is: not a device code. L3FA6E4B0 reduces five descriptor fields (struct+0x60/ 0x80/0xa0/0xc0/0xe0, written from the four sub-test calls) to a 5-bit value; 6 = 0b00110 = "L3FA71BC0 nonzero, L3FA753D0 nonzero". The caller turns any nonzero into 0x400, which the dispatcher maps to HOST PORT - 15. Flagged: L3FA753D0 returns 0x408 while all its own checks pass, so "nonzero" != "failed its checks"; polarity unresolved. Leads: COUNTER_READY is set by the firmware's own Start-Counter-Command read (reg 0x0E), is not in IMR, and is not handled by the ISR -- not the cause. The DUART clock (3.6864 MHz) could not be confirmed from the service guide. Variant MAME files kept in harness/mame/mame_edits/. Regression holds.
This commit is contained in:
1 parent
031d30da67
commit
72a96862c7
12 files changed
+9183
No files matched your search
@@ -546,3 +546,90 @@ Final state of the acceptance instrument (900 frames):
|
||||
'LEVEL1/2 ERROR -> HOST PORT - 15 ' <-- unchanged
|
||||
regression (no VT1200_* env): PC=3FDCE400 samples=199 HOLD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# CAUSALITY AUDIT (four-config A/B) — the failure is PRE-EXISTING
|
||||
|
||||
Reviewed after the owner flagged that "the failure moved backwards" and that my two
|
||||
MAME edits are both *timing* changes while the newly-blamed sub-test is a *timer* test.
|
||||
Method: four configurations of the MAME tree (IRQ wiring kept in all four — without it
|
||||
the test fails even earlier), built with `harness/mame/hp_ab.sh <cfg>`:
|
||||
|
||||
| cfg | IRQ | TxRDY edit | overrun edit | console | L3FA6E4B0 return |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | on | on | on | `HOST PORT - 15` | 6 |
|
||||
| 2 | on | reverted | on | `HOST PORT - 15` | 6 |
|
||||
| 3 | on | on | reverted | `HOST PORT - 15` | 6 |
|
||||
| 4 | on | reverted | reverted | `HOST PORT - 15` | 6 |
|
||||
|
||||
**Verdict: PRE-EXISTING.** The console line and the caller's return are identical in all
|
||||
four configurations, including cfg 4 where both MAME edits are reverted to stock. Neither
|
||||
`mc68681` edit causes or relocates the failure; they only change `RXCHECK`'s own flag
|
||||
word (Section UPDATE). Variant files are kept in `harness/mame/mame_edits/` (`*.cfg1`,
|
||||
`*.cfg2`, `*.cfg3`, `*.upstream`).
|
||||
|
||||
## Methodology correction (important)
|
||||
|
||||
My earlier `hp_ret.lua` attached labels to the **wrong `rets` addresses**, so the return
|
||||
values I quoted were mis-attributed. Verified against the disassembly, the correct
|
||||
`rets` sites and their owning functions (prologue register mask) are:
|
||||
|
||||
| `rets` | function | return |
|
||||
|---|---|---|
|
||||
| `3FA71BB0` | **`L3FA6E4B0`** (the generic port-test routine) | 6 |
|
||||
| `3FA753C0` | `L3FA71BC0` (baud/timer sub-test) | `0x00900040` |
|
||||
| `3FA767D0` | `L3FA753D0` (RXCHECK sub-test) | `0x00000408` |
|
||||
| `3FA77800` | `L3FA767E0` (XMITPASS sub-test) | 0 |
|
||||
|
||||
`harness/mame/hp_ret2.lua` uses the corrected addresses. So the owner's premise "6 comes
|
||||
from `L3FA71BC0`" is off: **`L3FA71BC0` returns `0x00900040`**; the `6` is
|
||||
`L3FA6E4B0`'s own return.
|
||||
|
||||
## What `6` actually is — not a failure code
|
||||
|
||||
`L3FA6E4B0` (the routine the level-1 host-port caller invokes) ends its body by reducing
|
||||
five descriptor fields to a 5-bit value (`3FA718D0`–`3FA71B50`) and returning it:
|
||||
|
||||
```
|
||||
bit0 <- (struct+0x60 != 0) bit3 <- (struct+0xc0 != 0)
|
||||
bit1 <- (struct+0x80 != 0) bit4 <- (struct+0xe0 != 0)
|
||||
bit2 <- (struct+0xa0 != 0)
|
||||
```
|
||||
|
||||
with `struct+0x80`/`struct+0xa0`/`struct+0xc0`/`struct+0xe0` set from the four
|
||||
sub-test calls (`L3FA71BC0`, `L3FA753D0` x2 each). So:
|
||||
|
||||
* **`6` = `0b00110`** — a *bitmap of which sub-tests returned nonzero*, not a device
|
||||
status code: `L3FA71BC0` non-zero and `L3FA753D0` non-zero; `L3FA767E0` returned 0, and
|
||||
the second-trio fields were never written (the caller aborts after the first trio).
|
||||
* The host-port caller (`3FA85000`) is `move a8,a8 ; jreq <continue>`: **any** nonzero
|
||||
value takes the error path, which returns `0x400` (`3FA853A0`). `0x400` is what the
|
||||
status dispatcher turns into `LEVEL1/2 ERROR -> HOST PORT - 15`.
|
||||
|
||||
**Unresolved, and flagged:** the polarity is suspicious. `L3FA753D0` (RXCHECK) returns
|
||||
`0x408` *while all four of its own checks pass* (flag word 0 — see UPDATE), so "sub-test
|
||||
returned nonzero" is **not** the same as "sub-test failed its checks". Either its success
|
||||
path leaves a stale `a8`, or the five fields are pass flags and the caller's test is
|
||||
inverted relative to my reading. I could not settle this, so `6` should **not** be
|
||||
treated as a plain failure code until it is.
|
||||
|
||||
## The two leads
|
||||
|
||||
1. **Counter spuriously active — checked, not the cause.** `ISR` bit `0x08`
|
||||
(`COUNTER_READY`) is set from frame 1, but MAME sets it in the *Start Counter Command*
|
||||
read path (`mc68681.cpp` `case 0x0e: start_ct(); set_ISR_bits(INT_COUNTER_READY)`),
|
||||
and the firmware itself performs that read at boot (`R 0640000E pc=3F200150`). It is
|
||||
**not** masked into the IRQ (`IMR` = 7 = TxRDYA|RxRDYA|DeltaBreakA, no bit 3), and the
|
||||
DUART ISR `L3FA78D90` does not handle ISR bit 3, so it cannot disturb the test. `ACR`
|
||||
reads `0x0000` except when the sub-test writes `0x60`.
|
||||
2. **DUART clock — unverified.** The service guide has no crystal/baud figure for the
|
||||
DUART (`grep -i '3.6864|crystal|oscillator' docs/EK-V1000-SV-002_service-guide.txt`
|
||||
→ nothing; its only "baud" hit is test 16 "Test all baud rates", a level-2+ test).
|
||||
3.6864 MHz is the 68681 datasheet's nominal and remains the only evidence; **I could
|
||||
not confirm it** against the guide.
|
||||
|
||||
## Acceptance / regression (cfg 1, committed state)
|
||||
|
||||
* Console: `LEVEL1/2 TESTING **` then `LEVEL1/2 ERROR -> HOST PORT - 15` — **unchanged**.
|
||||
* Regression (no `VT1200_*`): `PC=3FDCE400 samples=199` — **holds**.
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
# hp_ab.sh <label> -- build the current MAME tree and report the L3FA71BC0
|
||||
# return value (hp_ret.lua) and the console transcript (cap.lua).
|
||||
set -e
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
M=/home/arti/code/k-space/mame0289/vt1200
|
||||
LABEL=${1:-cfg}
|
||||
|
||||
JOBS=8 "$HERE/build.sh" >/dev/null
|
||||
cd "$HERE"
|
||||
echo "== $LABEL =="
|
||||
export VT1200_VRAM=1 VT1200_BOARD_MODEL=handshake VT1200_BOARD_BUSY_TICKS=2
|
||||
export VT1200_BOARD_SWITCH="0640000D:70:70" VT1200_DUART=1 VT1200_DUART_SEL=1
|
||||
|
||||
rm -f debug.log
|
||||
timeout 300 "$M" vt1200 -rompath roms -video none -sound none -nothrottle \
|
||||
-debug -debugger none -debuglog -autoboot_script "$HERE/hp_ret.lua" -autoboot_delay 0 >/dev/null 2>&1 || true
|
||||
echo "-- returns (hp_ret) --"
|
||||
grep -v "Breakpoint\|^Currently\|^MAME" debug.log | grep -v '^$' | head -12
|
||||
|
||||
rm -f debug.log
|
||||
CAP_MAX=900 timeout 300 "$M" vt1200 -rompath roms -video none -sound none -nothrottle \
|
||||
-debug -debugger none -debuglog -autoboot_script "$HERE/cap.lua" -autoboot_delay 0 >/dev/null 2>&1 || true
|
||||
echo "-- console --"
|
||||
grep PRINT debug.log | head -6
|
||||
@@ -0,0 +1,15 @@
|
||||
local machine = manager.machine
|
||||
local cpu = machine.devices[':maincpu']
|
||||
local dbg = machine.debugger
|
||||
local prog = cpu.spaces['program']
|
||||
local rd = function(a) return prog:read_u16(a) end
|
||||
local last={}
|
||||
local keys={ ISR=0x06400050, IMR=0x06400050, ACR=0x06400040, CUR=0x06400060 }
|
||||
local n=0
|
||||
emu.register_frame_done(function()
|
||||
n=n+1
|
||||
local isr=rd(0x06400050) & 0xff
|
||||
if last.isr~=isr then print(string.format("f%4d ISR=%02X ACR=%04X", n, isr, rd(0x06400040))); last.isr=isr end
|
||||
if n>=520 then machine:exit() end
|
||||
end,"ctr")
|
||||
dbg.execution_state='run'
|
||||
@@ -0,0 +1,23 @@
|
||||
-- hp_ret2.lua -- return values, with the rets addresses verified from the disassembly:
|
||||
-- L3FA71BC0 rets @ 3FA753C0, L3FA753D0 (RXCHECK) @ 3FA767D0,
|
||||
-- L3FA767E0 (XMITPASS) @ 3FA77800.
|
||||
local machine = manager.machine
|
||||
local cpu = machine.devices[':maincpu']
|
||||
local dbg = machine.debugger
|
||||
if not dbg then print("ERROR: no debugger"); machine:exit(); return end
|
||||
local function bp(addr, msg)
|
||||
dbg:command('bpset ' .. addr .. ',,{ printf "' .. msg ..
|
||||
' a8=%08X a7=%08X a9=%08X a11=%08X a13=%08X\\n", a8, a7, a9, a11, a13 ; g }')
|
||||
end
|
||||
bp("3fa753c0", "RET-BC0")
|
||||
bp("3fa767d0", "RET-RXCHECK")
|
||||
bp("3fa77800", "RET-XMITPASS")
|
||||
bp("3fa84fe0", "RET-L3FA6E4B0")
|
||||
bp("3fa6e4b0", "ENTER-GENERIC")
|
||||
local n = 0
|
||||
emu.register_frame_done(function()
|
||||
n = n + 1
|
||||
if n >= tonumber(os.getenv("HP_FRAMES") or "700") then print("done "..n); machine:exit() end
|
||||
end, "vt1200-hp-ret2")
|
||||
dbg.visible_cpu = cpu
|
||||
dbg.execution_state = 'run'
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,334 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Mariusz Wojcieszek, R. Belmont
|
||||
#ifndef MAME_MACHINE_MC68681_H
|
||||
#define MAME_MACHINE_MC68681_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "diserial.h"
|
||||
|
||||
#define MC68681_RX_FIFO_SIZE 3
|
||||
|
||||
// forward declaration
|
||||
class duart_base_device;
|
||||
|
||||
// duart_channel class
|
||||
class duart_channel : public device_t, public device_serial_interface
|
||||
{
|
||||
public:
|
||||
duart_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
// device_serial overrides
|
||||
virtual void rcv_complete() override; // Rx completed receiving byte
|
||||
virtual void tra_complete() override; // Tx completed sending byte
|
||||
virtual void tra_callback() override; // Tx send bit
|
||||
|
||||
uint8_t read_chan_reg(int reg);
|
||||
void write_chan_reg(int reg, uint8_t data);
|
||||
void update_interrupts();
|
||||
|
||||
// VT1200 NOTE (local change, not upstream): saw the RxD line so the overrun
|
||||
// error can be latched on the start bit of the overrunning character (the
|
||||
// datasheet's timing), rather than at its completion in rx_fifo_push().
|
||||
void rx_w(int state);
|
||||
|
||||
void rx_fifo_push(uint8_t data, uint8_t errors);
|
||||
uint8_t read_rx_fifo();
|
||||
|
||||
void baud_updated();
|
||||
|
||||
uint8_t get_chan_CSR();
|
||||
|
||||
// Access methods needed for 68340 serial module register model
|
||||
uint8_t read_MR1(){ return MR1; }
|
||||
uint8_t read_MR2(){ return MR2; }
|
||||
void write_MR1(uint8_t data){ MR1 = data; }
|
||||
void write_MR2(uint8_t data){ MR2 = data; }
|
||||
|
||||
void tx_16x_clock_w(bool state);
|
||||
void rx_16x_clock_w(bool state);
|
||||
|
||||
int get_tx_rate() const { return tx_baud_rate; }
|
||||
|
||||
private:
|
||||
/* Registers */
|
||||
uint8_t CR; /* Command register */
|
||||
uint8_t CSR; /* Clock select register */
|
||||
uint8_t MR1; /* Mode register 1 */
|
||||
uint8_t MR2; /* Mode register 2 */
|
||||
uint8_t MR_ptr; /* Mode register pointer */
|
||||
uint8_t SR; /* Status register */
|
||||
|
||||
/* State */
|
||||
int tx_baud_rate, rx_baud_rate;
|
||||
|
||||
/* Receiver */
|
||||
uint8_t rx_enabled;
|
||||
uint16_t rx_fifo[MC68681_RX_FIFO_SIZE + 1];
|
||||
int rx_fifo_read_ptr;
|
||||
int rx_fifo_write_ptr;
|
||||
int rx_fifo_num;
|
||||
bool m_rx_line; // VT1200 NOTE (local): previous RxD line state
|
||||
|
||||
int m_ch;
|
||||
|
||||
/* Transmitter */
|
||||
uint8_t m_tx_data;
|
||||
bool m_tx_data_in_buffer;
|
||||
bool m_tx_break;
|
||||
uint8_t m_bits_transmitted;
|
||||
bool m_tx_enabled;
|
||||
|
||||
/* Rx/Tx clocking */
|
||||
uint8_t m_rx_prescaler , m_tx_prescaler;
|
||||
|
||||
duart_base_device *m_uart;
|
||||
|
||||
void write_MR(uint8_t data);
|
||||
void write_CR(uint8_t data);
|
||||
void write_TX(uint8_t data);
|
||||
void recalc_framing();
|
||||
};
|
||||
|
||||
class duart_base_device : public device_t
|
||||
{
|
||||
friend class duart_channel;
|
||||
|
||||
public:
|
||||
required_device<duart_channel> m_chanA;
|
||||
required_device<duart_channel> m_chanB;
|
||||
optional_device<duart_channel> m_chanC;
|
||||
optional_device<duart_channel> m_chanD;
|
||||
|
||||
// inline configuration helpers
|
||||
void set_clocks(int clk3, int clk4, int clk5, int clk6);
|
||||
void set_clocks(const XTAL &clk3, const XTAL &clk4, const XTAL &clk5, const XTAL &clk6) {
|
||||
set_clocks(clk3.value(), clk4.value(), clk5.value(), clk6.value());
|
||||
}
|
||||
|
||||
// API
|
||||
virtual uint8_t read(offs_t offset);
|
||||
virtual void write(offs_t offset, uint8_t data);
|
||||
|
||||
void rx_a_w(int state) { m_chanA->rx_w((uint8_t)state); }
|
||||
void rx_b_w(int state) { m_chanB->rx_w((uint8_t)state); }
|
||||
|
||||
auto irq_cb() { return write_irq.bind(); }
|
||||
auto a_tx_cb() { return write_a_tx.bind(); }
|
||||
auto b_tx_cb() { return write_b_tx.bind(); }
|
||||
auto inport_cb() { return read_inport.bind(); } // deprecated: use ipX_w() instead
|
||||
auto outport_cb() { return write_outport.bind(); }
|
||||
|
||||
// new-style push handlers for input port bits
|
||||
virtual void ip0_w(int state);
|
||||
virtual void ip1_w(int state);
|
||||
virtual void ip2_w(int state);
|
||||
virtual void ip3_w(int state);
|
||||
virtual void ip4_w(int state);
|
||||
virtual void ip5_w(int state);
|
||||
virtual void ip6_w(int state);
|
||||
|
||||
bool irq_pending() const { return (ISR & IMR) != 0; }
|
||||
|
||||
protected:
|
||||
duart_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
|
||||
devcb_write_line write_irq, write_a_tx, write_b_tx, write_c_tx, write_d_tx;
|
||||
devcb_read8 read_inport;
|
||||
devcb_write8 write_outport;
|
||||
int32_t ip3clk, ip4clk, ip5clk, ip6clk;
|
||||
|
||||
protected:
|
||||
virtual void update_interrupts();
|
||||
|
||||
private:
|
||||
TIMER_CALLBACK_MEMBER(duart_timer_callback);
|
||||
|
||||
protected:
|
||||
/* registers */
|
||||
uint8_t ACR; /* Auxiliary Control Register */
|
||||
uint8_t IMR; /* Interrupt Mask Register */
|
||||
uint8_t ISR; /* Interrupt Status Register */
|
||||
|
||||
private:
|
||||
uint8_t OPCR; /* Output Port Conf. Register */
|
||||
uint8_t OPR; /* Output Port Register */
|
||||
PAIR CTR; /* Counter/Timer Preset Value */
|
||||
uint8_t IPCR; /* Input Port Control Register */
|
||||
|
||||
/* state */
|
||||
uint8_t IP_last_state; /* last state of IP bits */
|
||||
|
||||
/* timer */
|
||||
uint8_t half_period;
|
||||
emu_timer *duart_timer;
|
||||
|
||||
bool m_irq_state;
|
||||
|
||||
uint32_t get_ct_rate();
|
||||
uint16_t get_ct_count();
|
||||
void start_ct(int count);
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data);
|
||||
void clear_ISR_bits(int mask);
|
||||
void set_ISR_bits(int mask);
|
||||
|
||||
int get_ch(duart_channel *ch)
|
||||
{
|
||||
if (ch == m_chanA)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (ch == m_chanB)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (ch == m_chanC)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
duart_channel *get_channel(int chan);
|
||||
};
|
||||
|
||||
class scn2681_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
scn2681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
class mc68681_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
uint8_t get_irq_vector();
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void update_interrupts() override;
|
||||
mc68681_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
bool m_read_vector; // if this is read and IRQ is active, it counts as pulling IACK
|
||||
|
||||
uint8_t IVR; /* Interrupt Vector Register */
|
||||
};
|
||||
|
||||
/**************************
|
||||
* ColdFire MCF5206e UART
|
||||
**************************/
|
||||
class mcf5206e_uart_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mcf5206e_uart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
uint8_t get_irq_vector();
|
||||
|
||||
// There is no GPIO on the coldfire UART module
|
||||
void cts_w(int state) { duart_base_device::ip0_w(state); }
|
||||
|
||||
virtual void ip1_w(int state) override {}
|
||||
virtual void ip2_w(int state) override {}
|
||||
virtual void ip3_w(int state) override {}
|
||||
virtual void ip4_w(int state) override {}
|
||||
virtual void ip5_w(int state) override {}
|
||||
virtual void ip6_w(int state) override {}
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void update_interrupts() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
mcf5206e_uart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
|
||||
bool m_read_vector; // if this is read and IRQ is active, it counts as pulling IACK
|
||||
|
||||
// ColdFire UART module is essentially two 68681 a-channels with a slighty different register map and no counter
|
||||
uint8_t IVR; /* Interrupt Vector Register */
|
||||
uint16_t UBG; /* Baud Rate Generator Prescale Register - Manual erronuosly calls this the timer preload register */
|
||||
|
||||
};
|
||||
|
||||
class sc28c94_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
sc28c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
auto c_tx_cb() { return write_c_tx.bind(); }
|
||||
auto d_tx_cb() { return write_d_tx.bind(); }
|
||||
|
||||
void rx_c_w(int state) { m_chanC->device_serial_interface::rx_w((uint8_t)state); }
|
||||
void rx_d_w(int state) { m_chanD->device_serial_interface::rx_w((uint8_t)state); }
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class mc68340_duart_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mc68340_duart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
mc68340_duart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
};
|
||||
|
||||
class xr68c681_device : public mc68681_device
|
||||
{
|
||||
public:
|
||||
xr68c681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
|
||||
bool m_XTXA,m_XRXA,m_XTXB,m_XRXB; /* X bits for the BRG (selects between 2 BRG tables) */
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SCN2681, scn2681_device)
|
||||
DECLARE_DEVICE_TYPE(MC68681, mc68681_device)
|
||||
DECLARE_DEVICE_TYPE(SC28C94, sc28c94_device)
|
||||
DECLARE_DEVICE_TYPE(MC68340_DUART, mc68340_duart_device)
|
||||
DECLARE_DEVICE_TYPE(MCF5206E_UART, mcf5206e_uart_device)
|
||||
DECLARE_DEVICE_TYPE(XR68C681, xr68c681_device)
|
||||
DECLARE_DEVICE_TYPE(DUART_CHANNEL, duart_channel)
|
||||
|
||||
#endif // MAME_MACHINE_MC68681_H
|
||||
@@ -0,0 +1,334 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Mariusz Wojcieszek, R. Belmont
|
||||
#ifndef MAME_MACHINE_MC68681_H
|
||||
#define MAME_MACHINE_MC68681_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "diserial.h"
|
||||
|
||||
#define MC68681_RX_FIFO_SIZE 3
|
||||
|
||||
// forward declaration
|
||||
class duart_base_device;
|
||||
|
||||
// duart_channel class
|
||||
class duart_channel : public device_t, public device_serial_interface
|
||||
{
|
||||
public:
|
||||
duart_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
// device_serial overrides
|
||||
virtual void rcv_complete() override; // Rx completed receiving byte
|
||||
virtual void tra_complete() override; // Tx completed sending byte
|
||||
virtual void tra_callback() override; // Tx send bit
|
||||
|
||||
uint8_t read_chan_reg(int reg);
|
||||
void write_chan_reg(int reg, uint8_t data);
|
||||
void update_interrupts();
|
||||
|
||||
// VT1200 NOTE (local change, not upstream): saw the RxD line so the overrun
|
||||
// error can be latched on the start bit of the overrunning character (the
|
||||
// datasheet's timing), rather than at its completion in rx_fifo_push().
|
||||
void rx_w(int state);
|
||||
|
||||
void rx_fifo_push(uint8_t data, uint8_t errors);
|
||||
uint8_t read_rx_fifo();
|
||||
|
||||
void baud_updated();
|
||||
|
||||
uint8_t get_chan_CSR();
|
||||
|
||||
// Access methods needed for 68340 serial module register model
|
||||
uint8_t read_MR1(){ return MR1; }
|
||||
uint8_t read_MR2(){ return MR2; }
|
||||
void write_MR1(uint8_t data){ MR1 = data; }
|
||||
void write_MR2(uint8_t data){ MR2 = data; }
|
||||
|
||||
void tx_16x_clock_w(bool state);
|
||||
void rx_16x_clock_w(bool state);
|
||||
|
||||
int get_tx_rate() const { return tx_baud_rate; }
|
||||
|
||||
private:
|
||||
/* Registers */
|
||||
uint8_t CR; /* Command register */
|
||||
uint8_t CSR; /* Clock select register */
|
||||
uint8_t MR1; /* Mode register 1 */
|
||||
uint8_t MR2; /* Mode register 2 */
|
||||
uint8_t MR_ptr; /* Mode register pointer */
|
||||
uint8_t SR; /* Status register */
|
||||
|
||||
/* State */
|
||||
int tx_baud_rate, rx_baud_rate;
|
||||
|
||||
/* Receiver */
|
||||
uint8_t rx_enabled;
|
||||
uint16_t rx_fifo[MC68681_RX_FIFO_SIZE + 1];
|
||||
int rx_fifo_read_ptr;
|
||||
int rx_fifo_write_ptr;
|
||||
int rx_fifo_num;
|
||||
bool m_rx_line; // VT1200 NOTE (local): previous RxD line state
|
||||
|
||||
int m_ch;
|
||||
|
||||
/* Transmitter */
|
||||
uint8_t m_tx_data;
|
||||
bool m_tx_data_in_buffer;
|
||||
bool m_tx_break;
|
||||
uint8_t m_bits_transmitted;
|
||||
bool m_tx_enabled;
|
||||
|
||||
/* Rx/Tx clocking */
|
||||
uint8_t m_rx_prescaler , m_tx_prescaler;
|
||||
|
||||
duart_base_device *m_uart;
|
||||
|
||||
void write_MR(uint8_t data);
|
||||
void write_CR(uint8_t data);
|
||||
void write_TX(uint8_t data);
|
||||
void recalc_framing();
|
||||
};
|
||||
|
||||
class duart_base_device : public device_t
|
||||
{
|
||||
friend class duart_channel;
|
||||
|
||||
public:
|
||||
required_device<duart_channel> m_chanA;
|
||||
required_device<duart_channel> m_chanB;
|
||||
optional_device<duart_channel> m_chanC;
|
||||
optional_device<duart_channel> m_chanD;
|
||||
|
||||
// inline configuration helpers
|
||||
void set_clocks(int clk3, int clk4, int clk5, int clk6);
|
||||
void set_clocks(const XTAL &clk3, const XTAL &clk4, const XTAL &clk5, const XTAL &clk6) {
|
||||
set_clocks(clk3.value(), clk4.value(), clk5.value(), clk6.value());
|
||||
}
|
||||
|
||||
// API
|
||||
virtual uint8_t read(offs_t offset);
|
||||
virtual void write(offs_t offset, uint8_t data);
|
||||
|
||||
void rx_a_w(int state) { m_chanA->rx_w((uint8_t)state); }
|
||||
void rx_b_w(int state) { m_chanB->rx_w((uint8_t)state); }
|
||||
|
||||
auto irq_cb() { return write_irq.bind(); }
|
||||
auto a_tx_cb() { return write_a_tx.bind(); }
|
||||
auto b_tx_cb() { return write_b_tx.bind(); }
|
||||
auto inport_cb() { return read_inport.bind(); } // deprecated: use ipX_w() instead
|
||||
auto outport_cb() { return write_outport.bind(); }
|
||||
|
||||
// new-style push handlers for input port bits
|
||||
virtual void ip0_w(int state);
|
||||
virtual void ip1_w(int state);
|
||||
virtual void ip2_w(int state);
|
||||
virtual void ip3_w(int state);
|
||||
virtual void ip4_w(int state);
|
||||
virtual void ip5_w(int state);
|
||||
virtual void ip6_w(int state);
|
||||
|
||||
bool irq_pending() const { return (ISR & IMR) != 0; }
|
||||
|
||||
protected:
|
||||
duart_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
|
||||
devcb_write_line write_irq, write_a_tx, write_b_tx, write_c_tx, write_d_tx;
|
||||
devcb_read8 read_inport;
|
||||
devcb_write8 write_outport;
|
||||
int32_t ip3clk, ip4clk, ip5clk, ip6clk;
|
||||
|
||||
protected:
|
||||
virtual void update_interrupts();
|
||||
|
||||
private:
|
||||
TIMER_CALLBACK_MEMBER(duart_timer_callback);
|
||||
|
||||
protected:
|
||||
/* registers */
|
||||
uint8_t ACR; /* Auxiliary Control Register */
|
||||
uint8_t IMR; /* Interrupt Mask Register */
|
||||
uint8_t ISR; /* Interrupt Status Register */
|
||||
|
||||
private:
|
||||
uint8_t OPCR; /* Output Port Conf. Register */
|
||||
uint8_t OPR; /* Output Port Register */
|
||||
PAIR CTR; /* Counter/Timer Preset Value */
|
||||
uint8_t IPCR; /* Input Port Control Register */
|
||||
|
||||
/* state */
|
||||
uint8_t IP_last_state; /* last state of IP bits */
|
||||
|
||||
/* timer */
|
||||
uint8_t half_period;
|
||||
emu_timer *duart_timer;
|
||||
|
||||
bool m_irq_state;
|
||||
|
||||
uint32_t get_ct_rate();
|
||||
uint16_t get_ct_count();
|
||||
void start_ct(int count);
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data);
|
||||
void clear_ISR_bits(int mask);
|
||||
void set_ISR_bits(int mask);
|
||||
|
||||
int get_ch(duart_channel *ch)
|
||||
{
|
||||
if (ch == m_chanA)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (ch == m_chanB)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (ch == m_chanC)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
duart_channel *get_channel(int chan);
|
||||
};
|
||||
|
||||
class scn2681_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
scn2681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
class mc68681_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
uint8_t get_irq_vector();
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void update_interrupts() override;
|
||||
mc68681_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
bool m_read_vector; // if this is read and IRQ is active, it counts as pulling IACK
|
||||
|
||||
uint8_t IVR; /* Interrupt Vector Register */
|
||||
};
|
||||
|
||||
/**************************
|
||||
* ColdFire MCF5206e UART
|
||||
**************************/
|
||||
class mcf5206e_uart_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mcf5206e_uart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
uint8_t get_irq_vector();
|
||||
|
||||
// There is no GPIO on the coldfire UART module
|
||||
void cts_w(int state) { duart_base_device::ip0_w(state); }
|
||||
|
||||
virtual void ip1_w(int state) override {}
|
||||
virtual void ip2_w(int state) override {}
|
||||
virtual void ip3_w(int state) override {}
|
||||
virtual void ip4_w(int state) override {}
|
||||
virtual void ip5_w(int state) override {}
|
||||
virtual void ip6_w(int state) override {}
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void update_interrupts() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
mcf5206e_uart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
|
||||
bool m_read_vector; // if this is read and IRQ is active, it counts as pulling IACK
|
||||
|
||||
// ColdFire UART module is essentially two 68681 a-channels with a slighty different register map and no counter
|
||||
uint8_t IVR; /* Interrupt Vector Register */
|
||||
uint16_t UBG; /* Baud Rate Generator Prescale Register - Manual erronuosly calls this the timer preload register */
|
||||
|
||||
};
|
||||
|
||||
class sc28c94_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
sc28c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
auto c_tx_cb() { return write_c_tx.bind(); }
|
||||
auto d_tx_cb() { return write_d_tx.bind(); }
|
||||
|
||||
void rx_c_w(int state) { m_chanC->device_serial_interface::rx_w((uint8_t)state); }
|
||||
void rx_d_w(int state) { m_chanD->device_serial_interface::rx_w((uint8_t)state); }
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class mc68340_duart_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mc68340_duart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
mc68340_duart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
};
|
||||
|
||||
class xr68c681_device : public mc68681_device
|
||||
{
|
||||
public:
|
||||
xr68c681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
|
||||
bool m_XTXA,m_XRXA,m_XTXB,m_XRXB; /* X bits for the BRG (selects between 2 BRG tables) */
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SCN2681, scn2681_device)
|
||||
DECLARE_DEVICE_TYPE(MC68681, mc68681_device)
|
||||
DECLARE_DEVICE_TYPE(SC28C94, sc28c94_device)
|
||||
DECLARE_DEVICE_TYPE(MC68340_DUART, mc68340_duart_device)
|
||||
DECLARE_DEVICE_TYPE(MCF5206E_UART, mcf5206e_uart_device)
|
||||
DECLARE_DEVICE_TYPE(XR68C681, xr68c681_device)
|
||||
DECLARE_DEVICE_TYPE(DUART_CHANNEL, duart_channel)
|
||||
|
||||
#endif // MAME_MACHINE_MC68681_H
|
||||
@@ -0,0 +1,328 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Mariusz Wojcieszek, R. Belmont
|
||||
#ifndef MAME_MACHINE_MC68681_H
|
||||
#define MAME_MACHINE_MC68681_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "diserial.h"
|
||||
|
||||
#define MC68681_RX_FIFO_SIZE 3
|
||||
|
||||
// forward declaration
|
||||
class duart_base_device;
|
||||
|
||||
// duart_channel class
|
||||
class duart_channel : public device_t, public device_serial_interface
|
||||
{
|
||||
public:
|
||||
duart_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
// device_serial overrides
|
||||
virtual void rcv_complete() override; // Rx completed receiving byte
|
||||
virtual void tra_complete() override; // Tx completed sending byte
|
||||
virtual void tra_callback() override; // Tx send bit
|
||||
|
||||
uint8_t read_chan_reg(int reg);
|
||||
void write_chan_reg(int reg, uint8_t data);
|
||||
void update_interrupts();
|
||||
|
||||
void rx_fifo_push(uint8_t data, uint8_t errors);
|
||||
uint8_t read_rx_fifo();
|
||||
|
||||
void baud_updated();
|
||||
|
||||
uint8_t get_chan_CSR();
|
||||
|
||||
// Access methods needed for 68340 serial module register model
|
||||
uint8_t read_MR1(){ return MR1; }
|
||||
uint8_t read_MR2(){ return MR2; }
|
||||
void write_MR1(uint8_t data){ MR1 = data; }
|
||||
void write_MR2(uint8_t data){ MR2 = data; }
|
||||
|
||||
void tx_16x_clock_w(bool state);
|
||||
void rx_16x_clock_w(bool state);
|
||||
|
||||
int get_tx_rate() const { return tx_baud_rate; }
|
||||
|
||||
private:
|
||||
/* Registers */
|
||||
uint8_t CR; /* Command register */
|
||||
uint8_t CSR; /* Clock select register */
|
||||
uint8_t MR1; /* Mode register 1 */
|
||||
uint8_t MR2; /* Mode register 2 */
|
||||
uint8_t MR_ptr; /* Mode register pointer */
|
||||
uint8_t SR; /* Status register */
|
||||
|
||||
/* State */
|
||||
int tx_baud_rate, rx_baud_rate;
|
||||
|
||||
/* Receiver */
|
||||
uint8_t rx_enabled;
|
||||
uint16_t rx_fifo[MC68681_RX_FIFO_SIZE + 1];
|
||||
int rx_fifo_read_ptr;
|
||||
int rx_fifo_write_ptr;
|
||||
int rx_fifo_num;
|
||||
|
||||
int m_ch;
|
||||
|
||||
/* Transmitter */
|
||||
uint8_t m_tx_data;
|
||||
bool m_tx_data_in_buffer;
|
||||
bool m_tx_break;
|
||||
uint8_t m_bits_transmitted;
|
||||
bool m_tx_enabled;
|
||||
|
||||
/* Rx/Tx clocking */
|
||||
uint8_t m_rx_prescaler , m_tx_prescaler;
|
||||
|
||||
duart_base_device *m_uart;
|
||||
|
||||
void write_MR(uint8_t data);
|
||||
void write_CR(uint8_t data);
|
||||
void write_TX(uint8_t data);
|
||||
void recalc_framing();
|
||||
};
|
||||
|
||||
class duart_base_device : public device_t
|
||||
{
|
||||
friend class duart_channel;
|
||||
|
||||
public:
|
||||
required_device<duart_channel> m_chanA;
|
||||
required_device<duart_channel> m_chanB;
|
||||
optional_device<duart_channel> m_chanC;
|
||||
optional_device<duart_channel> m_chanD;
|
||||
|
||||
// inline configuration helpers
|
||||
void set_clocks(int clk3, int clk4, int clk5, int clk6);
|
||||
void set_clocks(const XTAL &clk3, const XTAL &clk4, const XTAL &clk5, const XTAL &clk6) {
|
||||
set_clocks(clk3.value(), clk4.value(), clk5.value(), clk6.value());
|
||||
}
|
||||
|
||||
// API
|
||||
virtual uint8_t read(offs_t offset);
|
||||
virtual void write(offs_t offset, uint8_t data);
|
||||
|
||||
void rx_a_w(int state) { m_chanA->device_serial_interface::rx_w((uint8_t)state); }
|
||||
void rx_b_w(int state) { m_chanB->device_serial_interface::rx_w((uint8_t)state); }
|
||||
|
||||
auto irq_cb() { return write_irq.bind(); }
|
||||
auto a_tx_cb() { return write_a_tx.bind(); }
|
||||
auto b_tx_cb() { return write_b_tx.bind(); }
|
||||
auto inport_cb() { return read_inport.bind(); } // deprecated: use ipX_w() instead
|
||||
auto outport_cb() { return write_outport.bind(); }
|
||||
|
||||
// new-style push handlers for input port bits
|
||||
virtual void ip0_w(int state);
|
||||
virtual void ip1_w(int state);
|
||||
virtual void ip2_w(int state);
|
||||
virtual void ip3_w(int state);
|
||||
virtual void ip4_w(int state);
|
||||
virtual void ip5_w(int state);
|
||||
virtual void ip6_w(int state);
|
||||
|
||||
bool irq_pending() const { return (ISR & IMR) != 0; }
|
||||
|
||||
protected:
|
||||
duart_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
|
||||
devcb_write_line write_irq, write_a_tx, write_b_tx, write_c_tx, write_d_tx;
|
||||
devcb_read8 read_inport;
|
||||
devcb_write8 write_outport;
|
||||
int32_t ip3clk, ip4clk, ip5clk, ip6clk;
|
||||
|
||||
protected:
|
||||
virtual void update_interrupts();
|
||||
|
||||
private:
|
||||
TIMER_CALLBACK_MEMBER(duart_timer_callback);
|
||||
|
||||
protected:
|
||||
/* registers */
|
||||
uint8_t ACR; /* Auxiliary Control Register */
|
||||
uint8_t IMR; /* Interrupt Mask Register */
|
||||
uint8_t ISR; /* Interrupt Status Register */
|
||||
|
||||
private:
|
||||
uint8_t OPCR; /* Output Port Conf. Register */
|
||||
uint8_t OPR; /* Output Port Register */
|
||||
PAIR CTR; /* Counter/Timer Preset Value */
|
||||
uint8_t IPCR; /* Input Port Control Register */
|
||||
|
||||
/* state */
|
||||
uint8_t IP_last_state; /* last state of IP bits */
|
||||
|
||||
/* timer */
|
||||
uint8_t half_period;
|
||||
emu_timer *duart_timer;
|
||||
|
||||
bool m_irq_state;
|
||||
|
||||
uint32_t get_ct_rate();
|
||||
uint16_t get_ct_count();
|
||||
void start_ct(int count);
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data);
|
||||
void clear_ISR_bits(int mask);
|
||||
void set_ISR_bits(int mask);
|
||||
|
||||
int get_ch(duart_channel *ch)
|
||||
{
|
||||
if (ch == m_chanA)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (ch == m_chanB)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (ch == m_chanC)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
duart_channel *get_channel(int chan);
|
||||
};
|
||||
|
||||
class scn2681_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
scn2681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
class mc68681_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
uint8_t get_irq_vector();
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void update_interrupts() override;
|
||||
mc68681_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
bool m_read_vector; // if this is read and IRQ is active, it counts as pulling IACK
|
||||
|
||||
uint8_t IVR; /* Interrupt Vector Register */
|
||||
};
|
||||
|
||||
/**************************
|
||||
* ColdFire MCF5206e UART
|
||||
**************************/
|
||||
class mcf5206e_uart_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mcf5206e_uart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
uint8_t get_irq_vector();
|
||||
|
||||
// There is no GPIO on the coldfire UART module
|
||||
void cts_w(int state) { duart_base_device::ip0_w(state); }
|
||||
|
||||
virtual void ip1_w(int state) override {}
|
||||
virtual void ip2_w(int state) override {}
|
||||
virtual void ip3_w(int state) override {}
|
||||
virtual void ip4_w(int state) override {}
|
||||
virtual void ip5_w(int state) override {}
|
||||
virtual void ip6_w(int state) override {}
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void update_interrupts() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
mcf5206e_uart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
|
||||
bool m_read_vector; // if this is read and IRQ is active, it counts as pulling IACK
|
||||
|
||||
// ColdFire UART module is essentially two 68681 a-channels with a slighty different register map and no counter
|
||||
uint8_t IVR; /* Interrupt Vector Register */
|
||||
uint16_t UBG; /* Baud Rate Generator Prescale Register - Manual erronuosly calls this the timer preload register */
|
||||
|
||||
};
|
||||
|
||||
class sc28c94_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
sc28c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
auto c_tx_cb() { return write_c_tx.bind(); }
|
||||
auto d_tx_cb() { return write_d_tx.bind(); }
|
||||
|
||||
void rx_c_w(int state) { m_chanC->device_serial_interface::rx_w((uint8_t)state); }
|
||||
void rx_d_w(int state) { m_chanD->device_serial_interface::rx_w((uint8_t)state); }
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class mc68340_duart_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mc68340_duart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
mc68340_duart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
};
|
||||
|
||||
class xr68c681_device : public mc68681_device
|
||||
{
|
||||
public:
|
||||
xr68c681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
|
||||
bool m_XTXA,m_XRXA,m_XTXB,m_XRXB; /* X bits for the BRG (selects between 2 BRG tables) */
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SCN2681, scn2681_device)
|
||||
DECLARE_DEVICE_TYPE(MC68681, mc68681_device)
|
||||
DECLARE_DEVICE_TYPE(SC28C94, sc28c94_device)
|
||||
DECLARE_DEVICE_TYPE(MC68340_DUART, mc68340_duart_device)
|
||||
DECLARE_DEVICE_TYPE(MCF5206E_UART, mcf5206e_uart_device)
|
||||
DECLARE_DEVICE_TYPE(XR68C681, xr68c681_device)
|
||||
DECLARE_DEVICE_TYPE(DUART_CHANNEL, duart_channel)
|
||||
|
||||
#endif // MAME_MACHINE_MC68681_H
|
||||
@@ -0,0 +1,328 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Mariusz Wojcieszek, R. Belmont
|
||||
#ifndef MAME_MACHINE_MC68681_H
|
||||
#define MAME_MACHINE_MC68681_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "diserial.h"
|
||||
|
||||
#define MC68681_RX_FIFO_SIZE 3
|
||||
|
||||
// forward declaration
|
||||
class duart_base_device;
|
||||
|
||||
// duart_channel class
|
||||
class duart_channel : public device_t, public device_serial_interface
|
||||
{
|
||||
public:
|
||||
duart_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
// device_serial overrides
|
||||
virtual void rcv_complete() override; // Rx completed receiving byte
|
||||
virtual void tra_complete() override; // Tx completed sending byte
|
||||
virtual void tra_callback() override; // Tx send bit
|
||||
|
||||
uint8_t read_chan_reg(int reg);
|
||||
void write_chan_reg(int reg, uint8_t data);
|
||||
void update_interrupts();
|
||||
|
||||
void rx_fifo_push(uint8_t data, uint8_t errors);
|
||||
uint8_t read_rx_fifo();
|
||||
|
||||
void baud_updated();
|
||||
|
||||
uint8_t get_chan_CSR();
|
||||
|
||||
// Access methods needed for 68340 serial module register model
|
||||
uint8_t read_MR1(){ return MR1; }
|
||||
uint8_t read_MR2(){ return MR2; }
|
||||
void write_MR1(uint8_t data){ MR1 = data; }
|
||||
void write_MR2(uint8_t data){ MR2 = data; }
|
||||
|
||||
void tx_16x_clock_w(bool state);
|
||||
void rx_16x_clock_w(bool state);
|
||||
|
||||
int get_tx_rate() const { return tx_baud_rate; }
|
||||
|
||||
private:
|
||||
/* Registers */
|
||||
uint8_t CR; /* Command register */
|
||||
uint8_t CSR; /* Clock select register */
|
||||
uint8_t MR1; /* Mode register 1 */
|
||||
uint8_t MR2; /* Mode register 2 */
|
||||
uint8_t MR_ptr; /* Mode register pointer */
|
||||
uint8_t SR; /* Status register */
|
||||
|
||||
/* State */
|
||||
int tx_baud_rate, rx_baud_rate;
|
||||
|
||||
/* Receiver */
|
||||
uint8_t rx_enabled;
|
||||
uint16_t rx_fifo[MC68681_RX_FIFO_SIZE + 1];
|
||||
int rx_fifo_read_ptr;
|
||||
int rx_fifo_write_ptr;
|
||||
int rx_fifo_num;
|
||||
|
||||
int m_ch;
|
||||
|
||||
/* Transmitter */
|
||||
uint8_t m_tx_data;
|
||||
bool m_tx_data_in_buffer;
|
||||
bool m_tx_break;
|
||||
uint8_t m_bits_transmitted;
|
||||
bool m_tx_enabled;
|
||||
|
||||
/* Rx/Tx clocking */
|
||||
uint8_t m_rx_prescaler , m_tx_prescaler;
|
||||
|
||||
duart_base_device *m_uart;
|
||||
|
||||
void write_MR(uint8_t data);
|
||||
void write_CR(uint8_t data);
|
||||
void write_TX(uint8_t data);
|
||||
void recalc_framing();
|
||||
};
|
||||
|
||||
class duart_base_device : public device_t
|
||||
{
|
||||
friend class duart_channel;
|
||||
|
||||
public:
|
||||
required_device<duart_channel> m_chanA;
|
||||
required_device<duart_channel> m_chanB;
|
||||
optional_device<duart_channel> m_chanC;
|
||||
optional_device<duart_channel> m_chanD;
|
||||
|
||||
// inline configuration helpers
|
||||
void set_clocks(int clk3, int clk4, int clk5, int clk6);
|
||||
void set_clocks(const XTAL &clk3, const XTAL &clk4, const XTAL &clk5, const XTAL &clk6) {
|
||||
set_clocks(clk3.value(), clk4.value(), clk5.value(), clk6.value());
|
||||
}
|
||||
|
||||
// API
|
||||
virtual uint8_t read(offs_t offset);
|
||||
virtual void write(offs_t offset, uint8_t data);
|
||||
|
||||
void rx_a_w(int state) { m_chanA->device_serial_interface::rx_w((uint8_t)state); }
|
||||
void rx_b_w(int state) { m_chanB->device_serial_interface::rx_w((uint8_t)state); }
|
||||
|
||||
auto irq_cb() { return write_irq.bind(); }
|
||||
auto a_tx_cb() { return write_a_tx.bind(); }
|
||||
auto b_tx_cb() { return write_b_tx.bind(); }
|
||||
auto inport_cb() { return read_inport.bind(); } // deprecated: use ipX_w() instead
|
||||
auto outport_cb() { return write_outport.bind(); }
|
||||
|
||||
// new-style push handlers for input port bits
|
||||
virtual void ip0_w(int state);
|
||||
virtual void ip1_w(int state);
|
||||
virtual void ip2_w(int state);
|
||||
virtual void ip3_w(int state);
|
||||
virtual void ip4_w(int state);
|
||||
virtual void ip5_w(int state);
|
||||
virtual void ip6_w(int state);
|
||||
|
||||
bool irq_pending() const { return (ISR & IMR) != 0; }
|
||||
|
||||
protected:
|
||||
duart_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
|
||||
devcb_write_line write_irq, write_a_tx, write_b_tx, write_c_tx, write_d_tx;
|
||||
devcb_read8 read_inport;
|
||||
devcb_write8 write_outport;
|
||||
int32_t ip3clk, ip4clk, ip5clk, ip6clk;
|
||||
|
||||
protected:
|
||||
virtual void update_interrupts();
|
||||
|
||||
private:
|
||||
TIMER_CALLBACK_MEMBER(duart_timer_callback);
|
||||
|
||||
protected:
|
||||
/* registers */
|
||||
uint8_t ACR; /* Auxiliary Control Register */
|
||||
uint8_t IMR; /* Interrupt Mask Register */
|
||||
uint8_t ISR; /* Interrupt Status Register */
|
||||
|
||||
private:
|
||||
uint8_t OPCR; /* Output Port Conf. Register */
|
||||
uint8_t OPR; /* Output Port Register */
|
||||
PAIR CTR; /* Counter/Timer Preset Value */
|
||||
uint8_t IPCR; /* Input Port Control Register */
|
||||
|
||||
/* state */
|
||||
uint8_t IP_last_state; /* last state of IP bits */
|
||||
|
||||
/* timer */
|
||||
uint8_t half_period;
|
||||
emu_timer *duart_timer;
|
||||
|
||||
bool m_irq_state;
|
||||
|
||||
uint32_t get_ct_rate();
|
||||
uint16_t get_ct_count();
|
||||
void start_ct(int count);
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data);
|
||||
void clear_ISR_bits(int mask);
|
||||
void set_ISR_bits(int mask);
|
||||
|
||||
int get_ch(duart_channel *ch)
|
||||
{
|
||||
if (ch == m_chanA)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (ch == m_chanB)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (ch == m_chanC)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
duart_channel *get_channel(int chan);
|
||||
};
|
||||
|
||||
class scn2681_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
scn2681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
class mc68681_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
uint8_t get_irq_vector();
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void update_interrupts() override;
|
||||
mc68681_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
bool m_read_vector; // if this is read and IRQ is active, it counts as pulling IACK
|
||||
|
||||
uint8_t IVR; /* Interrupt Vector Register */
|
||||
};
|
||||
|
||||
/**************************
|
||||
* ColdFire MCF5206e UART
|
||||
**************************/
|
||||
class mcf5206e_uart_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mcf5206e_uart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
uint8_t get_irq_vector();
|
||||
|
||||
// There is no GPIO on the coldfire UART module
|
||||
void cts_w(int state) { duart_base_device::ip0_w(state); }
|
||||
|
||||
virtual void ip1_w(int state) override {}
|
||||
virtual void ip2_w(int state) override {}
|
||||
virtual void ip3_w(int state) override {}
|
||||
virtual void ip4_w(int state) override {}
|
||||
virtual void ip5_w(int state) override {}
|
||||
virtual void ip6_w(int state) override {}
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void update_interrupts() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
mcf5206e_uart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
|
||||
bool m_read_vector; // if this is read and IRQ is active, it counts as pulling IACK
|
||||
|
||||
// ColdFire UART module is essentially two 68681 a-channels with a slighty different register map and no counter
|
||||
uint8_t IVR; /* Interrupt Vector Register */
|
||||
uint16_t UBG; /* Baud Rate Generator Prescale Register - Manual erronuosly calls this the timer preload register */
|
||||
|
||||
};
|
||||
|
||||
class sc28c94_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
sc28c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
auto c_tx_cb() { return write_c_tx.bind(); }
|
||||
auto d_tx_cb() { return write_d_tx.bind(); }
|
||||
|
||||
void rx_c_w(int state) { m_chanC->device_serial_interface::rx_w((uint8_t)state); }
|
||||
void rx_d_w(int state) { m_chanD->device_serial_interface::rx_w((uint8_t)state); }
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class mc68340_duart_device : public duart_base_device
|
||||
{
|
||||
public:
|
||||
mc68340_duart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
mc68340_duart_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
};
|
||||
|
||||
class xr68c681_device : public mc68681_device
|
||||
{
|
||||
public:
|
||||
xr68c681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
virtual int calc_baud(int ch, bool rx, uint8_t data) override;
|
||||
|
||||
bool m_XTXA,m_XRXA,m_XTXB,m_XRXB; /* X bits for the BRG (selects between 2 BRG tables) */
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SCN2681, scn2681_device)
|
||||
DECLARE_DEVICE_TYPE(MC68681, mc68681_device)
|
||||
DECLARE_DEVICE_TYPE(SC28C94, sc28c94_device)
|
||||
DECLARE_DEVICE_TYPE(MC68340_DUART, mc68340_duart_device)
|
||||
DECLARE_DEVICE_TYPE(MCF5206E_UART, mcf5206e_uart_device)
|
||||
DECLARE_DEVICE_TYPE(XR68C681, xr68c681_device)
|
||||
DECLARE_DEVICE_TYPE(DUART_CHANNEL, duart_channel)
|
||||
|
||||
#endif // MAME_MACHINE_MC68681_H
|
||||
Reference in new issue
Block a user