(MESS) New driver added: Xerox Alto 2 [Juergen Buchmueller]

out of whatsnew: Did not add Unicode support for debugger from branch yet, for now few special chars are converted to be plain ASCII
This commit is contained in:
Miodrag Milanovic 2014-04-22 12:21:07 +00:00
parent 92d6b69712
commit c046734f76
54 changed files with 15824 additions and 2 deletions

45
.gitattributes vendored
View File

@ -1430,6 +1430,46 @@ src/emu/cpu/adsp2100/adsp2100.h svneol=native#text/plain
src/emu/cpu/alph8201/8201dasm.c svneol=native#text/plain
src/emu/cpu/alph8201/alph8201.c svneol=native#text/plain
src/emu/cpu/alph8201/alph8201.h svneol=native#text/plain
src/emu/cpu/alto2/a2curt.c svneol=native#text/plain
src/emu/cpu/alto2/a2curt.h svneol=native#text/plain
src/emu/cpu/alto2/a2dht.c svneol=native#text/plain
src/emu/cpu/alto2/a2dht.h svneol=native#text/plain
src/emu/cpu/alto2/a2disk.c svneol=native#text/plain
src/emu/cpu/alto2/a2disk.h svneol=native#text/plain
src/emu/cpu/alto2/a2disp.c svneol=native#text/plain
src/emu/cpu/alto2/a2disp.h svneol=native#text/plain
src/emu/cpu/alto2/a2dvt.c svneol=native#text/plain
src/emu/cpu/alto2/a2dvt.h svneol=native#text/plain
src/emu/cpu/alto2/a2dwt.c svneol=native#text/plain
src/emu/cpu/alto2/a2dwt.h svneol=native#text/plain
src/emu/cpu/alto2/a2emu.c svneol=native#text/plain
src/emu/cpu/alto2/a2emu.h svneol=native#text/plain
src/emu/cpu/alto2/a2ether.c svneol=native#text/plain
src/emu/cpu/alto2/a2ether.h svneol=native#text/plain
src/emu/cpu/alto2/a2hw.c svneol=native#text/plain
src/emu/cpu/alto2/a2hw.h svneol=native#text/plain
src/emu/cpu/alto2/a2jkff.h svneol=native#text/plain
src/emu/cpu/alto2/a2kbd.c svneol=native#text/plain
src/emu/cpu/alto2/a2kbd.h svneol=native#text/plain
src/emu/cpu/alto2/a2ksec.c svneol=native#text/plain
src/emu/cpu/alto2/a2ksec.h svneol=native#text/plain
src/emu/cpu/alto2/a2kwd.c svneol=native#text/plain
src/emu/cpu/alto2/a2kwd.h svneol=native#text/plain
src/emu/cpu/alto2/a2mem.c svneol=native#text/plain
src/emu/cpu/alto2/a2mem.h svneol=native#text/plain
src/emu/cpu/alto2/a2mouse.c svneol=native#text/plain
src/emu/cpu/alto2/a2mouse.h svneol=native#text/plain
src/emu/cpu/alto2/a2mrt.c svneol=native#text/plain
src/emu/cpu/alto2/a2mrt.h svneol=native#text/plain
src/emu/cpu/alto2/a2part.c svneol=native#text/plain
src/emu/cpu/alto2/a2part.h svneol=native#text/plain
src/emu/cpu/alto2/a2ram.c svneol=native#text/plain
src/emu/cpu/alto2/a2ram.h svneol=native#text/plain
src/emu/cpu/alto2/a2roms.c svneol=native#text/plain
src/emu/cpu/alto2/a2roms.h svneol=native#text/plain
src/emu/cpu/alto2/alto2cpu.c svneol=native#text/plain
src/emu/cpu/alto2/alto2cpu.h svneol=native#text/plain
src/emu/cpu/alto2/alto2dsm.c svneol=native#text/plain
src/emu/cpu/am29000/am29000.c svneol=native#text/plain
src/emu/cpu/am29000/am29000.h svneol=native#text/plain
src/emu/cpu/am29000/am29dasm.c svneol=native#text/plain
@ -2192,6 +2232,8 @@ src/emu/imagedev/cassette.c svneol=native#text/plain
src/emu/imagedev/cassette.h svneol=native#text/plain
src/emu/imagedev/chd_cd.c svneol=native#text/plain
src/emu/imagedev/chd_cd.h svneol=native#text/plain
src/emu/imagedev/diablo.c svneol=native#text/plain
src/emu/imagedev/diablo.h svneol=native#text/plain
src/emu/imagedev/flopdrv.c svneol=native#text/plain
src/emu/imagedev/flopdrv.h svneol=native#text/plain
src/emu/imagedev/floppy.c svneol=native#text/plain
@ -2352,6 +2394,8 @@ src/emu/machine/cs4031.c svneol=native#text/plain
src/emu/machine/cs4031.h svneol=native#text/plain
src/emu/machine/cs8221.c svneol=native#text/plain
src/emu/machine/cs8221.h svneol=native#text/plain
src/emu/machine/diablo_hd.c svneol=native#text/plain
src/emu/machine/diablo_hd.h svneol=native#text/plain
src/emu/machine/dp8390.c svneol=native#text/plain
src/emu/machine/dp8390.h svneol=native#text/plain
src/emu/machine/ds1204.c svneol=native#text/plain
@ -7534,6 +7578,7 @@ src/mess/drivers/alesis.c svneol=native#text/plain
src/mess/drivers/alphasma.c svneol=native#text/plain
src/mess/drivers/alphatro.c svneol=native#text/plain
src/mess/drivers/altair.c svneol=native#text/plain
src/mess/drivers/alto2.c svneol=native#text/plain
src/mess/drivers/altos5.c svneol=native#text/plain
src/mess/drivers/amico2k.c svneol=native#text/plain
src/mess/drivers/amiga.c svneol=native#text/plain

View File

@ -0,0 +1,90 @@
/*****************************************************************************
*
* Xerox AltoII cursor task
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
/**
* @brief disable the cursor task and set the curt_blocks flag
*/
void alto2_cpu_device::f1_early_curt_block()
{
m_dsp.curt_blocks = true;
m_task_wakeup &= ~(1 << m_task);
LOG((LOG_CURT,2," BLOCK %s\n", task_name(m_task)));
}
/**
* @brief f2_load_xpreg late: load the x position register from BUS[6-15]
*/
void alto2_cpu_device::f2_late_load_xpreg()
{
m_dsp.xpreg = X_RDBITS(m_bus,16,6,15);
LOG((LOG_CURT, 9," XPREG<- BUS[6-15] (%#o)\n", m_dsp.xpreg));
}
/**
* @brief f2_load_csr late: load the cursor shift register from BUS[0-15]
*
* Shift CSR to xpreg % 16 position to make it easier to
* to handle the word xor in unload_word().
* <PRE>
* xpreg % 16 cursor bits
* [ first word ][ second word ]
* ----------------------------------------------
* 0 xxxxxxxxxxxxxxxx0000000000000000
* 1 0xxxxxxxxxxxxxxxx000000000000000
* 2 00xxxxxxxxxxxxxxxx00000000000000
* ...
* 14 00000000000000xxxxxxxxxxxxxxxx00
* 15 000000000000000xxxxxxxxxxxxxxxx0
* </PRE>
*/
void alto2_cpu_device::f2_late_load_csr()
{
m_dsp.csr = m_bus;
LOG((LOG_CURT, m_dsp.csr ? 2 : 9," CSR<- BUS (%#o)\n", m_dsp.csr));
}
/**
* @brief curt_activate: called by the CPU when the cursor task becomes active
*/
void alto2_cpu_device::activate_curt()
{
m_task_wakeup &= ~(1 << m_task);
m_dsp.curt_wakeup = false;
int x = 01777 - m_dsp.xpreg;
UINT32 bits = m_dsp.csr << (16 - (x & 15));
m_dsp.cursor0 = static_cast<UINT16>(bits >> 16);
m_dsp.cursor1 = static_cast<UINT16>(bits);
m_dsp.curxpos = x / 16;
}
/** @brief initialize the cursor task F1 and F2 functions */
void alto2_cpu_device::init_curt(int task)
{
set_f1(task, f1_block, &alto2_cpu_device::f1_early_curt_block, 0);
set_f2(task, f2_curt_load_xpreg, 0, &alto2_cpu_device::f2_late_load_xpreg);
set_f2(task, f2_curt_load_csr, 0, &alto2_cpu_device::f2_late_load_csr);
m_active_callback[task] = &alto2_cpu_device::activate_curt;
}
void alto2_cpu_device::exit_curt()
{
// nothing to do yet
}
void alto2_cpu_device::reset_curt()
{
m_dsp.curt_blocks = false;
m_dsp.xpreg = 0;
m_dsp.csr = 0;
m_dsp.curxpos = 0;
m_dsp.cursor0 = m_dsp.cursor1 = 0;
}

View File

@ -0,0 +1,30 @@
/*****************************************************************************
*
* Xerox AltoII cursor task (CURT)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2CURT_H_
#define _A2CURT_H_
//! F2 functions for cursor task
enum {
f2_curt_load_xpreg = f2_task_10, //!< f2 10: load x position register
f2_curt_load_csr = f2_task_11, //!< f2 11: load cursor shift register
};
void f1_early_curt_block(); //!< f1_curt_block early: disable the cursor task and set the curt_blocks flag
void f2_late_load_xpreg(); //!< f2_load_xpreg late: load the x position register from BUS[6-15]
void f2_late_load_csr(); //!< f2_load_csr late: load the cursor shift register from BUS[0-15]
void activate_curt(); //!< curt_activate: called by the CPU when the cursor task becomes active
void init_curt(int task = task_curt); //!< initialize cursor task
void exit_curt(); //!< deinitialize cursor task
void reset_curt(); //!< reset cursor task
#endif // _A2CURT_H_
#endif // ALTO2_DEFINE_CONSTANTS

69
src/emu/cpu/alto2/a2dht.c Normal file
View File

@ -0,0 +1,69 @@
/*****************************************************************************
*
* Xerox AltoII display horizontal task
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
/**
* @brief f1_dht_block early: disable the display word task
*/
void alto2_cpu_device::f1_early_dht_block()
{
m_dsp.dht_blocks = true;
// clear the wakeup for the display horizontal task
m_task_wakeup &= ~(1 << m_task);
LOG((LOG_DHT,2," BLOCK %s\n", task_name(m_task)));
}
/**
* @brief f2_dht_setmode late: set the next scanline's mode inverse and half clock and branch
*
* BUS[0] selects the pixel clock (0), or half pixel clock (1)
* BUS[1] selects normal mode (0), or inverse mode (1)
*
* The current BUS[0] drives the NEXT[09] line, i.e. branches to 0 or 1
*/
void alto2_cpu_device::f2_late_dht_setmode()
{
UINT16 r = X_RDBITS(m_bus,16,0,0);
m_dsp.setmode = m_bus;
LOG((LOG_DHT,2," SETMODE<- BUS (%#o), branch on BUS[0] (%#o | %#o)\n", m_bus, m_next2, r));
m_next2 |= r;
}
/**
* @brief called by the CPU when the display horizontal task becomes active
*/
void alto2_cpu_device::activate_dht()
{
m_task_wakeup &= ~(1 << m_task);
}
/**
* @brief initialize the display horizontal task
*
* @param task task number
*/
void alto2_cpu_device::init_dht(int task)
{
set_f1(task, f1_block, &alto2_cpu_device::f1_early_dht_block, 0);
set_f2(task, f2_dht_evenfield, 0, &alto2_cpu_device::f2_late_evenfield);
set_f2(task, f2_dht_setmode, 0, &alto2_cpu_device::f2_late_dht_setmode);
m_active_callback[task] = &alto2_cpu_device::activate_dht;
}
void alto2_cpu_device::exit_dht()
{
// nothing to do yet
}
void alto2_cpu_device::reset_dht()
{
m_dsp.dht_blocks = true;
m_dsp.setmode = 0;
}

29
src/emu/cpu/alto2/a2dht.h Normal file
View File

@ -0,0 +1,29 @@
/*****************************************************************************
*
* Xerox AltoII display horizontal task (DHT)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2DHT_H_
#define _A2DHT_H_
//! F2 functions for display horizontal task
enum {
f2_dht_evenfield = f2_task_10, //!< f2 10: load even field
f2_dht_setmode = f2_task_11, //!< f2 11: set mode
};
void f1_early_dht_block(); //!< F1 func: disable the display word task
void f2_late_dht_setmode(); //!< F2 func: set the next scanline's mode inverse and half clock and branch
void activate_dht(); //!< called by the CPU when the display horizontal task becomes active
void init_dht(int task = task_dht); //!< initialize display horizontal task
void exit_dht(); //!< deinitialize display horizontal task
void reset_dht(); //!< reset the display horizontal task
#endif // _A2DHT_H_
#endif // ALTO2_DEFINE_CONSTANTS

1897
src/emu/cpu/alto2/a2disk.c Normal file

File diff suppressed because it is too large Load Diff

109
src/emu/cpu/alto2/a2disk.h Normal file
View File

@ -0,0 +1,109 @@
/*****************************************************************************
*
* Xerox AltoII disk controller block
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2DISK_H_
#define _A2DISK_H_
diablo_hd_device* m_drive[2]; //!< two diablo_hd_device drives
//! disk controller context
struct {
UINT8 drive; //!< selected drive from KADDR[14] (written to data out with SENDADR)
UINT16 kaddr; //!< A[0-15] disk hardware address (sector, cylinder, head, drive, restore)
UINT16 kadr; //!< C[0-15] with read/write/check modes for header, label and data
UINT16 kstat; //!< S[0-15] disk status
UINT16 kcom; //!< disk command (5 bits kcom[1-5])
UINT8 krecno; //!< record number (2 bits indexing header, label, data, -/-)
UINT8 egate; //!< current erase gate signal to the DIABLO hd
UINT8 wrgate; //!< current write gate signal to the DIABLO hd
UINT8 rdgate; //!< current read gate signal to the DIABLO hd
UINT32 shiftin; //!< input shift register
UINT32 shiftout; //!< output shift register
UINT32 datain; //!< disk data in latch
UINT32 dataout; //!< disk data out latch
UINT8 krwc; //!< read/write/check for current record
UINT8 kfer; //!< disk fatal error signal state
UINT8 wdtskena; //!< disk word task enable (active low)
UINT8 wddone; //!< previous state of WDDONE
UINT8 wdinit0; //!< disk word task init at the early microcycle
UINT8 wdinit; //!< disk word task init at the late microcycle
UINT8 strobe; //!< strobe (still) active
emu_timer* strobon_timer; //!< set strobe on timer
UINT8 bitclk; //!< current bitclk state (either crystal clock, or rdclk from the drive)
#if USE_BITCLK_TIMER
emu_timer* bitclk_timer; //!< bit clock timer
#else
int bitclk_time[2]; //!< per drive time in clocks per bit
#endif
UINT8 datin; //!< current datin from the drive
UINT8 bitcount; //!< bit counter
UINT8 carry; //!< carry output of the bitcounter
UINT8 seclate; //!< sector late (monoflop output)
emu_timer* seclate_timer; //!< sector late timer
UINT8 seekok; //!< seekok state (SKINC' & LAI' & ff_44a.Q')
UINT8 ok_to_run; //!< ok to run signal (set to 1 some time after reset)
emu_timer* ok_to_run_timer; //!< ok to run timer
UINT8 ready_mf31a; //!< ready monoflop 31a
emu_timer* ready_timer; //!< ready timer
UINT8 seclate_mf31b; //!< seclate monoflop 31b
jkff_t ff_21a; //!< JK flip-flop 21a (sector task)
jkff_t ff_21a_old; //!< -"- previous state
jkff_t ff_21b; //!< JK flip-flop 21b (sector task)
jkff_t ff_22a; //!< JK flip-flop 22a (sector task)
jkff_t ff_22b; //!< JK flip-flop 22b (sector task)
jkff_t ff_43b; //!< JK flip-flop 43b (word task)
jkff_t ff_53a; //!< JK flip-flop 53a (word task)
jkff_t ff_43a; //!< JK flip-flop 43a (word task)
jkff_t ff_53b; //!< brief JK flip-flop 53b (word task)
jkff_t ff_44a; //!< JK flip-flop 44a (LAI' clocked)
jkff_t ff_44b; //!< JK flip-flop 44b (CKSUM)
jkff_t ff_45a; //!< JK flip-flop 45a (ready latch)
jkff_t ff_45b; //!< JK flip-flop 45b (seqerr latch)
} m_dsk;
jkff_t m_sysclka0[4]; //!< simulate previous sysclka
jkff_t m_sysclka1[4]; //!< simulate current sysclka
jkff_t m_sysclkb0[4]; //!< simulate previous sysclkb
jkff_t m_sysclkb1[4]; //!< simulate current sysclkb
void kwd_timing(int bitclk, int datin, int block); //!< disk word timing
TIMER_CALLBACK_MEMBER( disk_seclate ); //!< timer callback to take away the SECLATE pulse (monoflop)
TIMER_CALLBACK_MEMBER( disk_ok_to_run ); //!< timer callback to take away the OK TO RUN pulse (reset)
TIMER_CALLBACK_MEMBER( disk_strobon ); //!< timer callback to pulse the STROBE' signal to the drive
TIMER_CALLBACK_MEMBER( disk_ready_mf31a ); //!< timer callback to change the READY monoflop 31a
#if USE_BITCLK_TIMER
TIMER_CALLBACK_MEMBER( disk_bitclk ); //!< callback to update the disk controller with a new bitclk
#else
void disk_bitclk(void *ptr, int arg); //!< function to update the disk controller with a new bitclk
#endif
void disk_block(int task); //!< called if one of the disk tasks (task_kwd or task_ksec) blocks
void bs_early_read_kstat(); //!< bus source: bus driven by disk status register KSTAT
void bs_early_read_kdata(); //!< bus source: bus driven by disk data register KDATA input
void f1_late_strobe(); //!< F1 func: initiates a disk seek
void f1_late_load_kstat(); //!< F1 func: load disk status register
void f1_late_load_kdata(); //!< F1 func: load data out register, or the disk address register
void f1_late_increcno(); //!< F1 func: advances shift registers holding KADR
void f1_late_clrstat(); //!< F1 func: reset all error latches
void f1_late_load_kcom(); //!< F1 func: load the KCOM register from bus
void f1_late_load_kadr(); //!< F1 func: load the KADR register from bus
void f2_late_init(); //!< F2 func: branch on disk word task active and init
void f2_late_rwc(); //!< F2 func: branch on read/write/check state of the current record
void f2_late_recno(); //!< F2 func: branch on the current record number by a lookup table
void f2_late_xfrdat(); //!< F2 func: branch on the data transfer state
void f2_late_swrnrdy(); //!< F2 func: branch on the disk ready signal
void f2_late_nfer(); //!< f2_nfer late: branch on the disk fatal error condition
void f2_late_strobon(); //!< f2_strobon late: branch on the seek busy status
void init_disk(); //!< initialize the disk controller
void exit_disk(); //!< deinitialize the disk controller
void reset_disk(); //!< reset the disk controller
#endif // _A2DISK_H_
#endif // ALTO2_DEFINE_CONSTANTS

876
src/emu/cpu/alto2/a2disp.c Normal file
View File

@ -0,0 +1,876 @@
/*****************************************************************************
*
* Xerox AltoII display interface
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
#include "a2roms.h"
/**
* @brief PROM a38 contains the STOPWAKE' and MBEMBPTY' signals for the FIFO
* <PRE>
* The inputs to a38 are the UNLOAD counter RA[0-3] and the DDR<- counter
* WA[0-3], and the designer decided to reverse the address lines :-)
*
* a38 counter
* -------------
* A0 RA[0]
* A1 RA[1]
* A2 RA[2]
* A3 RA[3]
* A4 WA[0]
* A5 WA[1]
* A6 WA[2]
* A7 WA[3]
*
* Only two bits of a38 are used:
* O1 (002) = STOPWAKE'
* O3 (010) = MBEMPTY'
* </PRE>
*/
//! P3601 256x4 BPROM; display FIFO control: STOPWAKE, MBEMPTY
static const prom_load_t pl_displ_a38 =
{
"displ.a38",
0,
"fd30beb7",
"65e4a19ba4ff748d525122128c514abedd55d866",
/* size */ 0400,
/* amap */ AMAP_REVERSE_0_7, // reverse address lines A0-A7
/* axor */ 0,
/* dxor */ 0,
/* width */ 4,
/* shift */ 0,
/* dmap */ DMAP_DEFAULT,
/* dand */ ZERO,
/* type */ sizeof(UINT8)
};
//! PROM a38 bit O1 is STOPWAKE' (stop DWT if bit is zero)
#define FIFO_STOPWAKE(a38) (0 == (a38 & disp_a38_STOPWAKE) ? true : false)
//! PROM a38 bit O3 is MBEMPTY' (FIFO is empty if bit is zero)
#define FIFO_MBEMPTY(a38) (0 == (a38 & disp_a38_MBEMPTY) ? true : false)
/**
* @brief emulation of PROM a63 in the display schematics page 8
* <PRE>
* The PROM's address lines are driven by a clock CLK, which is
* pixel clock / 24, and an inverted half-scanline signal H[1]'.
*
* It is 32x8 bits and its output bits (B) are connected to the
* signals, as well as its own address lines (A) through a latch
* of the type SN74774 like this:
*
* PROM 174 A others
* ------------------------
* B0 D5 - HBLANK
* B1 D0 - HSYNC
* B2 D4 A0 -
* B3 D1 A1 -
* B4 D3 A2 -
* B5 D2 A3 -
* B6 - - SCANEND
* B7 - - HLCGATE
* ------------------------
* H[1]' - A4 -
*
* The display_state_machine() is called at a rate of pixelclock/24.
*
* Decoded states of this PROM:
*
* STATE PROM binary HBLANK HSYNC NEXT SCANEND HLCGATE
* ----------------------------------------------------------
* 000 0007 00000111 1 1 001 0 0
* 001 0013 00001011 1 1 002 0 0
* 002 0015 00001101 1 0 003 0 0
* 003 0021 00010001 1 0 004 0 0
* 004 0024 00010100 0 0 005 0 0
* 005 0030 00011000 0 0 006 0 0
* 006 0034 00011100 0 0 007 0 0
* 007 0040 00100000 0 0 010 0 0
* 010 0044 00100100 0 0 011 0 0
* 011 0050 00101000 0 0 012 0 0
* 012 0054 00101100 0 0 013 0 0
* 013 0060 00110000 0 0 014 0 0
* 014 0064 00110100 0 0 015 0 0
* 015 0070 00111000 0 0 016 0 0
* 016 0074 00111100 0 0 017 0 0
* 017 0200 10000000 0 0 000 0 1
* 020 0004 00000100 0 0 001 0 0
* 021 0010 00001000 0 0 002 0 0
* 022 0014 00001100 0 0 003 0 0
* 023 0020 00010000 0 0 004 0 0
* 024 0024 00010100 0 0 005 0 0
* 025 0030 00011000 0 0 006 0 0
* 026 0034 00011100 0 0 007 0 0
* 027 0040 00100000 0 0 010 0 0
* 030 0044 00100100 0 0 011 0 0
* 031 0050 00101000 0 0 012 0 0
* 032 0054 00101100 0 0 013 0 0
* 033 0060 00110000 0 0 014 0 0
* 034 0064 00110100 0 0 015 0 0
* 035 0070 00111000 0 0 016 0 0
* 036 0175 01111101 1 0 017 1 0
* 037 0203 10000011 1 1 000 0 1
* </PRE>
*/
//! 82S23 32x8 BPROM; display HBLANK, HSYNC, SCANEND, HLCGATE ...
static const prom_load_t pl_displ_a63 =
{
"displ.a63",
0,
"82a20d60",
"39d90703568be5419ada950e112d99227873fdea",
/* size */ 0040,
/* amap */ AMAP_DEFAULT,
/* axor */ 0,
/* dxor */ 0,
/* width */ 8,
/* shift */ 0,
/* dmap */ DMAP_DEFAULT,
/* dand */ ZERO,
/* type */ sizeof(UINT8)
};
//!< test the HBLANK (horizontal blanking) signal in PROM a63 being high
#define A63_HBLANK(a) ((a & disp_a63_HBLANK) ? true : false)
//!< test the HSYNC (horizontal synchonisation) signal in PROM a63 being high
#define A63_HSYNC(a) ((a & disp_a63_HSYNC) ? true : false)
//!< test the SCANEND (scanline end) signal in PROM a63 being high
#define A63_SCANEND(a) ((a & disp_a63_SCANEND) ? true : false)
//!< test the HLCGATE (horz. line counter gate) signal in PROM a63 being high
#define A63_HLCGATE(a) ((a & disp_a63_HLCGATE) ? true : false)
/**
* @brief PROM a66 is a 256x4 bit (type 3601)
* <PRE>
* Address lines are driven by H[1] to H[128] of the the horz. line counters.
* PROM is enabled when H[256] and H[512] are both 0.
*
* Q1 is VSYNC for the odd field (with H1024=0)
* Q2 is VSYNC for the even field (with H1024=1)
* Q3 is VBLANK for the odd field (with H1024=0)
* Q4 is VBLANK for the even field (with H1024=1)
* </PRE>
*/
//! P3601 256x4 BPROM; display VSYNC and VBLANK
static const prom_load_t pl_displ_a66 =
{
"displ.a66",
0,
"9f91aad9",
"69b1d4c71f4e18103112e8601850c2654e9265cf",
/* size */ 0400,
/* amap */ AMAP_DEFAULT,
/* axor */ 0,
/* dxor */ 0,
/* width */ 4,
/* shift */ 0,
/* dmap */ DMAP_DEFAULT,
/* dand */ ZERO,
/* type */ sizeof(UINT8)
};
//! test the VSYNC (vertical synchronisation) signal in PROM a66 being high
#define A66_VSYNC(a) (a & (HLC1024 ? disp_a66_VSYNC_ODD : disp_a66_VSYNC_EVEN) ? false : true)
//! test the VBLANK (vertical blanking) signal in PROM a66 being high
#define A66_VBLANK(a) (a & (HLC1024 ? disp_a66_VBLANK_ODD : disp_a66_VBLANK_EVEN) ? false : true)
/**
* @brief double the bits for a byte (left and right of display word) to a word
*/
static const UINT16 double_bits[256] = {
0x0000,0x0003,0x000c,0x000f,0x0030,0x0033,0x003c,0x003f,
0x00c0,0x00c3,0x00cc,0x00cf,0x00f0,0x00f3,0x00fc,0x00ff,
0x0300,0x0303,0x030c,0x030f,0x0330,0x0333,0x033c,0x033f,
0x03c0,0x03c3,0x03cc,0x03cf,0x03f0,0x03f3,0x03fc,0x03ff,
0x0c00,0x0c03,0x0c0c,0x0c0f,0x0c30,0x0c33,0x0c3c,0x0c3f,
0x0cc0,0x0cc3,0x0ccc,0x0ccf,0x0cf0,0x0cf3,0x0cfc,0x0cff,
0x0f00,0x0f03,0x0f0c,0x0f0f,0x0f30,0x0f33,0x0f3c,0x0f3f,
0x0fc0,0x0fc3,0x0fcc,0x0fcf,0x0ff0,0x0ff3,0x0ffc,0x0fff,
0x3000,0x3003,0x300c,0x300f,0x3030,0x3033,0x303c,0x303f,
0x30c0,0x30c3,0x30cc,0x30cf,0x30f0,0x30f3,0x30fc,0x30ff,
0x3300,0x3303,0x330c,0x330f,0x3330,0x3333,0x333c,0x333f,
0x33c0,0x33c3,0x33cc,0x33cf,0x33f0,0x33f3,0x33fc,0x33ff,
0x3c00,0x3c03,0x3c0c,0x3c0f,0x3c30,0x3c33,0x3c3c,0x3c3f,
0x3cc0,0x3cc3,0x3ccc,0x3ccf,0x3cf0,0x3cf3,0x3cfc,0x3cff,
0x3f00,0x3f03,0x3f0c,0x3f0f,0x3f30,0x3f33,0x3f3c,0x3f3f,
0x3fc0,0x3fc3,0x3fcc,0x3fcf,0x3ff0,0x3ff3,0x3ffc,0x3fff,
0xc000,0xc003,0xc00c,0xc00f,0xc030,0xc033,0xc03c,0xc03f,
0xc0c0,0xc0c3,0xc0cc,0xc0cf,0xc0f0,0xc0f3,0xc0fc,0xc0ff,
0xc300,0xc303,0xc30c,0xc30f,0xc330,0xc333,0xc33c,0xc33f,
0xc3c0,0xc3c3,0xc3cc,0xc3cf,0xc3f0,0xc3f3,0xc3fc,0xc3ff,
0xcc00,0xcc03,0xcc0c,0xcc0f,0xcc30,0xcc33,0xcc3c,0xcc3f,
0xccc0,0xccc3,0xcccc,0xcccf,0xccf0,0xccf3,0xccfc,0xccff,
0xcf00,0xcf03,0xcf0c,0xcf0f,0xcf30,0xcf33,0xcf3c,0xcf3f,
0xcfc0,0xcfc3,0xcfcc,0xcfcf,0xcff0,0xcff3,0xcffc,0xcfff,
0xf000,0xf003,0xf00c,0xf00f,0xf030,0xf033,0xf03c,0xf03f,
0xf0c0,0xf0c3,0xf0cc,0xf0cf,0xf0f0,0xf0f3,0xf0fc,0xf0ff,
0xf300,0xf303,0xf30c,0xf30f,0xf330,0xf333,0xf33c,0xf33f,
0xf3c0,0xf3c3,0xf3cc,0xf3cf,0xf3f0,0xf3f3,0xf3fc,0xf3ff,
0xfc00,0xfc03,0xfc0c,0xfc0f,0xfc30,0xfc33,0xfc3c,0xfc3f,
0xfcc0,0xfcc3,0xfccc,0xfccf,0xfcf0,0xfcf3,0xfcfc,0xfcff,
0xff00,0xff03,0xff0c,0xff0f,0xff30,0xff33,0xff3c,0xff3f,
0xffc0,0xffc3,0xffcc,0xffcf,0xfff0,0xfff3,0xfffc,0xffff
};
#define HLC1 ((m_dsp.hlc >> 0) & 1) //!< horizontal line counter bit 0 (mid of the scanline)
#define HLC2 ((m_dsp.hlc >> 1) & 1) //!< horizontal line counter bit 1
#define HLC4 ((m_dsp.hlc >> 2) & 1) //!< horizontal line counter bit 2
#define HLC8 ((m_dsp.hlc >> 3) & 1) //!< horizontal line counter bit 3
#define HLC16 ((m_dsp.hlc >> 4) & 1) //!< horizontal line counter bit 4
#define HLC32 ((m_dsp.hlc >> 5) & 1) //!< horizontal line counter bit 5
#define HLC64 ((m_dsp.hlc >> 6) & 1) //!< horizontal line counter bit 6
#define HLC128 ((m_dsp.hlc >> 7) & 1) //!< horizontal line counter bit 7
#define HLC256 ((m_dsp.hlc >> 8) & 1) //!< horizontal line counter bit 8
#define HLC512 ((m_dsp.hlc >> 9) & 1) //!< horizontal line counter bit 9
#define HLC1024 ((m_dsp.hlc >> 10) & 1) //!< horizontal line counter bit 10 (odd/even field)
#define GET_SETMODE_SPEEDY(mode) X_RDBITS(mode,16,0,0) //!< get the pixel clock speed from a SETMODE<- bus value
#define GET_SETMODE_INVERSE(mode) X_RDBITS(mode,16,1,1) //!< get the inverse video flag from a SETMODE<- bus value
//!< helper to extract A3-A0 from a PROM a63 value
#define A63_NEXT(n) ((n >> 2) & 017)
//! update the internal bitmap to a byte array
void alto2_cpu_device::update_bitmap_word(UINT16* bitmap, int x, int y, UINT16 word)
{
// mixing with the cursor
if (x == m_dsp.curxpos + 0)
word ^= m_dsp.cursor0;
if (x == m_dsp.curxpos + 1)
word ^= m_dsp.cursor1;
// no change?
if (word == bitmap[x])
return;
bitmap[x] = word;
UINT8* pix = m_dsp.scanline[y] + x * 16;
*pix++ = (word >> 15) & 1;
*pix++ = (word >> 14) & 1;
*pix++ = (word >> 13) & 1;
*pix++ = (word >> 12) & 1;
*pix++ = (word >> 11) & 1;
*pix++ = (word >> 10) & 1;
*pix++ = (word >> 9) & 1;
*pix++ = (word >> 8) & 1;
*pix++ = (word >> 7) & 1;
*pix++ = (word >> 6) & 1;
*pix++ = (word >> 5) & 1;
*pix++ = (word >> 4) & 1;
*pix++ = (word >> 3) & 1;
*pix++ = (word >> 2) & 1;
*pix++ = (word >> 1) & 1;
*pix++ = (word >> 0) & 1;
}
/**
* @brief unload the next word from the display FIFO and shift it to the screen
*/
void alto2_cpu_device::unload_word()
{
int x = m_unload_word;
int y = ((m_dsp.hlc - m_dsp.vblank) & ~02001) ^ HLC1024;
if (y < 0 || y >= ALTO2_DISPLAY_HEIGHT || x >= ALTO2_DISPLAY_VISIBLE_WORDS)
{
m_unload_time = -1;
return;
}
UINT16* bitmap = m_dsp.raw_bitmap + y * ALTO2_DISPLAY_SCANLINE_WORDS;
UINT16 word = m_dsp.inverse;
UINT8 a38 = m_disp_a38[m_dsp.ra * 16 + m_dsp.wa];
if (FIFO_MBEMPTY(a38))
{
LOG((LOG_DISPL,1, " DSP FIFO underrun y:%d x:%d\n", y, x));
}
else
{
word ^= m_dsp.fifo[m_dsp.ra];
m_dsp.ra = (m_dsp.ra + 1) % ALTO2_DISPLAY_FIFO;
LOG((LOG_DISPL,3, " DSP pull %04x from FIFO[%02o] y:%d x:%d\n",
word, (m_dsp.ra - 1) & (ALTO2_DISPLAY_FIFO - 1), y, x));
}
if (m_dsp.halfclock)
{
UINT16 word1 = double_bits[word / 256];
UINT16 word2 = double_bits[word % 256];
update_bitmap_word(bitmap, x, y, word1);
x++;
if (x < ALTO2_DISPLAY_VISIBLE_WORDS)
{
update_bitmap_word(bitmap, x, y, word2);
x++;
}
m_unload_time += ALTO2_DISPLAY_BITTIME(32);
}
else
{
update_bitmap_word(bitmap, x, y, word);
x++;
m_unload_time += ALTO2_DISPLAY_BITTIME(16);
}
if (x < ALTO2_DISPLAY_VISIBLE_WORDS)
m_unload_word = x;
else
m_unload_time = -1;
}
/**
* @brief function called by the CPU to enter the next display state
*
* There are 32 states per scanline and 875 scanlines per frame.
*/
void alto2_cpu_device::display_state_machine()
{
LOG((LOG_DISPL,5,"DSP%03o:", m_dsp.state));
if (020 == m_dsp.state)
{
LOG((LOG_DISPL,2," HLC=%d", m_dsp.hlc));
}
UINT8 a63 = m_disp_a63[m_dsp.state];
if (A63_HLCGATE(a63))
{
// count horizontal line counters and wrap
m_dsp.hlc += 1;
if (m_dsp.hlc > ALTO2_DISPLAY_HLC_END)
m_dsp.hlc = ALTO2_DISPLAY_HLC_START;
// wake up the memory refresh task _twice_ on each scanline
m_task_wakeup |= 1 << task_mrt;
}
// PROM a66 is disabled, if any of HLC256 or HLC512 are high
UINT8 a66 = (HLC256 || HLC512) ? 017 : m_disp_a66[m_dsp.hlc & 0377];
// next address from PROM a63, use A4 from HLC1
UINT8 next = ((HLC1 ^ 1) << 4) | A63_NEXT(a63);
if (A66_VBLANK(a66))
{
// Rising edge of VBLANK: remember HLC[1-10] where the VBLANK starts
m_dsp.vblank = m_dsp.hlc & ~02000;
LOG((LOG_DISPL,1, " VBLANK"));
// VSYNC is always within VBLANK, thus we handle it only here
if (A66_VSYNC(a66))
{
if (!A66_VSYNC(m_dsp.a66))
{
LOG((LOG_DISPL,1, " VSYNC/ (wake DVT)"));
/*
* The display vertical task DVT is woken once per field
* at the beginning of vertical retrace.
*/
m_task_wakeup |= 1 << task_dvt;
// TODO: upade odd or even field of the internal bitmap now?
}
}
}
else
{
// Falling edge of VBLANK?
if (A66_VBLANK(m_dsp.a66))
{
/*
* VBLANKPULSE:
* The display horizontal task DHT is woken once at the
* beginning of each field, and thereafter whenever the
* display word task blocks.
*
* The DHT can block itself, in which case neither it nor
* the word task can be woken until the start of the
* next field.
*/
LOG((LOG_DISPL,1, " VBLANKPULSE (wake DHT)"));
m_dsp.dht_blocks = false;
m_dsp.dwt_blocks = false;
m_task_wakeup |= 1 << task_dht;
/*
* VBLANKPULSE also resets the cursor task block flip flop,
* which is built from two NAND gates a40c and a40d (74H01).
*/
m_dsp.curt_blocks = false;
}
if (!A63_HBLANK(a63) && A63_HBLANK(m_dsp.a63))
{
// Falling edge of a63 HBLANK starts unloading of FIFO words
LOG((LOG_DISPL,1, " HBLANK\\ UNLOAD"));
m_unload_time = ALTO2_DISPLAY_BITTIME(m_dsp.halfclock ? 32 : 16);
m_unload_word = 0;
}
}
/*
* The wakeup request for the display word task (DWT) is controlled by
* the state of the 16 word FIFO. If DWT has not executed a BLOCK,
* if DHT is not blocked, and if the buffer is not full, DWT wakeups
* are generated.
*/
UINT8 a38 = m_disp_a38[m_dsp.ra * 16 + m_dsp.wa];
if (!m_dsp.dwt_blocks && !m_dsp.dht_blocks && !FIFO_STOPWAKE(a38))
{
m_task_wakeup |= 1 << task_dwt;
LOG((LOG_DISPL,1, " (wake DWT)"));
}
// Stop waking up the DWT when SCANEND is active
if (A63_SCANEND(a63))
{
m_task_wakeup &= ~(1 << task_dwt);
LOG((LOG_DISPL,1, " SCANEND"));
}
LOG((LOG_DISPL,1, "%s", A63_HBLANK(a63) ? " HBLANK": ""));
if (A63_HSYNC(a63))
{
// Active HSYNC
if (!A63_HSYNC(m_dsp.a63))
{
// Rising edge of HSYNC => CLRBUF
LOG((LOG_DISPL,1, " HSYNC/ (CLRBUF)"));
/*
* The hardware sets the buffer empty and clears the DWT block
* flip-flop at the beginning of horizontal retrace for
* every scanline.
*/
m_dsp.wa = 0;
m_dsp.ra = 0;
m_dsp.dwt_blocks = false;
// now take the new values from the last SETMODE<-
m_dsp.inverse = GET_SETMODE_INVERSE(m_dsp.setmode) ? 0xffff : 0x0000;
m_dsp.halfclock = GET_SETMODE_SPEEDY(m_dsp.setmode) ? true : false;
// stop the CPU execution loop from calling unload_word()
m_unload_time = -1;
}
else
{
LOG((LOG_DISPL,1, " HSYNC"));
}
}
else
// Falling edge of HSYNC?
if (A63_HSYNC(m_dsp.a63))
{
/*
* CLRBUF' also resets the 2nd cursor task block flip flop,
* which is built from two NAND gates a30c and a30d (74H00).
* If both flip flops are reset, the NOR gate a20d (74S02)
* decodes this as WAKECURT signal.
*/
m_dsp.curt_wakeup = true;
if (!m_dsp.curt_blocks)
m_task_wakeup |= 1 << task_curt;
}
LOG((LOG_DISPL,1, " NEXT:%03o\n", next));
m_dsp.a63 = a63;
m_dsp.a66 = a66;
m_dsp.state = next;
m_dsp_time += ALTO2_DISPLAY_BITTIME(32);
}
/**
* @brief branch on evenfield
*
* NEXT(09) = even field ? 1 : 0
*/
void alto2_cpu_device::f2_late_evenfield()
{
UINT16 r = HLC1024 ^ 1;
LOG((LOG_DISPL,2," EVENFIELD branch (%#o | %#o)\n", m_next2, r));
m_next2 |= r;
}
/**
* @brief initialize the display context to useful values
*
* Zap the display context to all 0s.
* Allocate a bitmap array to save blitting to the screen when
* there is no change in the data words.
*/
void alto2_cpu_device::init_disp()
{
memset(&m_dsp, 0, sizeof(m_dsp));
save_item(NAME(m_dsp.state));
save_item(NAME(m_dsp.hlc));
save_item(NAME(m_dsp.setmode));
save_item(NAME(m_dsp.inverse));
save_item(NAME(m_dsp.halfclock));
save_item(NAME(m_dsp.fifo));
save_item(NAME(m_dsp.wa));
save_item(NAME(m_dsp.ra));
save_item(NAME(m_dsp.a63));
save_item(NAME(m_dsp.a66));
save_item(NAME(m_dsp.dht_blocks));
save_item(NAME(m_dsp.dwt_blocks));
save_item(NAME(m_dsp.curt_blocks));
save_item(NAME(m_dsp.curt_wakeup));
save_item(NAME(m_dsp.vblank));
save_item(NAME(m_dsp.xpreg));
save_item(NAME(m_dsp.csr));
save_item(NAME(m_dsp.curxpos));
save_item(NAME(m_dsp.cursor0));
save_item(NAME(m_dsp.cursor1));
m_disp_a38 = prom_load(machine(), &pl_displ_a38, memregion("displ_a38")->base());
m_disp_a63 = prom_load(machine(), &pl_displ_a63, memregion("displ_a63")->base());
m_disp_a66 = prom_load(machine(), &pl_displ_a66, memregion("displ_a66")->base());
m_dsp.hlc = ALTO2_DISPLAY_HLC_START;
m_dsp.raw_bitmap = auto_alloc_array(machine(), UINT16, ALTO2_DISPLAY_HEIGHT * ALTO2_DISPLAY_SCANLINE_WORDS);
m_dsp.scanline = auto_alloc_array(machine(), UINT8*, ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H);
for (int y = 0; y < ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H; y++)
m_dsp.scanline[y] = auto_alloc_array(machine(), UINT8, ALTO2_DISPLAY_TOTAL_WIDTH);
m_dsp.bitmap = auto_bitmap_ind16_alloc(machine(), ALTO2_DISPLAY_WIDTH, ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H);
m_dsp.state = 0;
}
void alto2_cpu_device::exit_disp()
{
// nothing to do yet
}
void alto2_cpu_device::reset_disp()
{
m_dsp.state = 0;
m_dsp.hlc = ALTO2_DISPLAY_HLC_START;
m_dsp.a63 = 0;
m_dsp.a66 = 0;
m_dsp.setmode = 0;
m_dsp.inverse = 0;
m_dsp.halfclock = false;
m_dsp.wa = 0;
m_dsp.ra = 0;
m_dsp.dht_blocks = false;
m_dsp.dwt_blocks = false;
m_dsp.curt_blocks = false;
m_dsp.curt_wakeup = false;
m_dsp.vblank = 0;
m_dsp.xpreg = 0;
m_dsp.csr = 0;
m_dsp.curxpos = 0;
m_dsp.cursor0 = 0;
m_dsp.cursor1 = 0;
memset(m_dsp.raw_bitmap, 0, sizeof(UINT16) * ALTO2_DISPLAY_HEIGHT * ALTO2_DISPLAY_SCANLINE_WORDS);
for (int y = 0; y < ALTO2_DISPLAY_HEIGHT; y++)
memset(m_dsp.scanline[y], 0, sizeof(UINT8) * ALTO2_DISPLAY_TOTAL_WIDTH);
m_dsp.odd_frame = false;
for (int y = ALTO2_DISPLAY_HEIGHT; y < ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H; y++)
memset(m_dsp.scanline[y], 1, sizeof(UINT8) * ALTO2_DISPLAY_TOTAL_WIDTH);
fake_status_printf(1, "* Fake Status *");
}
/* Video update */
UINT32 alto2_cpu_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
pen_t palette_bw[2];
palette_bw[0] = screen.palette()->white_pen();
palette_bw[1] = screen.palette()->black_pen();
// copy even or odd field
for (int y = m_dsp.odd_frame ? 0 : 1; y < ALTO2_DISPLAY_HEIGHT; y += 2)
draw_scanline8(*m_dsp.bitmap, 0, y, ALTO2_DISPLAY_WIDTH, m_dsp.scanline[y], palette_bw);
// copy fake status scanlines
for (int y = ALTO2_DISPLAY_HEIGHT; y < ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H; y++)
draw_scanline8(*m_dsp.bitmap, 0, y, ALTO2_DISPLAY_WIDTH, m_dsp.scanline[y], palette_bw);
// copy bitmap
copybitmap(bitmap, *m_dsp.bitmap, 0, 0, 0, 0, cliprect);
return 0;
}
void alto2_cpu_device::screen_eof(screen_device &screen, bool state)
{
if (state)
m_dsp.odd_frame = !m_dsp.odd_frame;
}
/*****************************************************************************
*
* FAKE STATUS LINE
*
*****************************************************************************/
typedef struct {
UINT8 code;
UINT8 bits[10];
} bdf_6x10_t;
/**
* STARTFONT 2.1
* COMMENT "$ucs-fonts: 6x10.bdf,v 1.34 2002-11-10 19:12:30+00 mgk25 Rel $"
* COMMENT "Send bug reports to Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/>"
* FONT -Misc-Fixed-Medium-R-Normal--10-100-75-75-C-60-ISO10646-1
* SIZE 10 75 75
* FONTBOUNDINGBOX 6 10 0 -2
* STARTPROPERTIES 22
* FONTNAME_REGISTRY ""
* FOUNDRY "Misc"
* FAMILY_NAME "Fixed"
* WEIGHT_NAME "Medium"
* SLANT "R"
* SETWIDTH_NAME "Normal"
* ADD_STYLE_NAME ""
* PIXEL_SIZE 10
* POINT_SIZE 100
* RESOLUTION_X 75
* RESOLUTION_Y 75
* SPACING "C"
* AVERAGE_WIDTH 60
* CHARSET_REGISTRY "ISO10646"
* CHARSET_ENCODING "1"
* FONT_ASCENT 8
* FONT_DESCENT 2
* DEFAULT_CHAR 0
* COPYRIGHT "Public domain terminal emulator font. Share and enjoy."
* _XMBDFED_INFO "Edited with xmbdfed 4.5."
* CAP_HEIGHT 7
* X_HEIGHT 5
* ENDPROPERTIES
* CHARS 1597
*/
static const bdf_6x10_t bdf_6x10[] = {
/* space */ { 32, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* exclam */ { 33, {0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00 }},
/* quotedbl */ { 34, {0x00, 0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* numbersign */ { 35, {0x00, 0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50, 0x00, 0x00 }},
/* dollar */ { 36, {0x00, 0x20, 0x70, 0xA0, 0x70, 0x28, 0x70, 0x20, 0x00, 0x00 }},
/* percent */ { 37, {0x00, 0x48, 0xA8, 0x50, 0x20, 0x50, 0xA8, 0x90, 0x00, 0x00 }},
/* ampersand */ { 38, {0x00, 0x40, 0xA0, 0xA0, 0x40, 0xA8, 0x90, 0x68, 0x00, 0x00 }},
/* quotesingle */ { 39, {0x00, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* parenleft */ { 40, {0x00, 0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00, 0x00 }},
/* parenright */ { 41, {0x00, 0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40, 0x00, 0x00 }},
/* asterisk */ { 42, {0x00, 0x00, 0x88, 0x50, 0xF8, 0x50, 0x88, 0x00, 0x00, 0x00 }},
/* plus */ { 43, {0x00, 0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00, 0x00 }},
/* comma */ { 44, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x20, 0x40, 0x00 }},
/* hyphen */ { 45, {0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* period */ { 46, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, 0x20, 0x00 }},
/* slash */ { 47, {0x00, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00 }},
/* zero */ { 48, {0x00, 0x20, 0x50, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00, 0x00 }},
/* one */ { 49, {0x00, 0x20, 0x60, 0xA0, 0x20, 0x20, 0x20, 0xF8, 0x00, 0x00 }},
/* two */ { 50, {0x00, 0x70, 0x88, 0x08, 0x30, 0x40, 0x80, 0xF8, 0x00, 0x00 }},
/* three */ { 51, {0x00, 0xF8, 0x08, 0x10, 0x30, 0x08, 0x88, 0x70, 0x00, 0x00 }},
/* four */ { 52, {0x00, 0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00, 0x00 }},
/* five */ { 53, {0x00, 0xF8, 0x80, 0xB0, 0xC8, 0x08, 0x88, 0x70, 0x00, 0x00 }},
/* six */ { 54, {0x00, 0x30, 0x40, 0x80, 0xB0, 0xC8, 0x88, 0x70, 0x00, 0x00 }},
/* seven */ { 55, {0x00, 0xF8, 0x08, 0x10, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00 }},
/* eight */ { 56, {0x00, 0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* nine */ { 57, {0x00, 0x70, 0x88, 0x98, 0x68, 0x08, 0x10, 0x60, 0x00, 0x00 }},
/* colon */ { 58, {0x00, 0x00, 0x20, 0x70, 0x20, 0x00, 0x20, 0x70, 0x20, 0x00 }},
/* semicolon */ { 59, {0x00, 0x00, 0x20, 0x70, 0x20, 0x00, 0x30, 0x20, 0x40, 0x00 }},
/* less */ { 60, {0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00 }},
/* equal */ { 61, {0x00, 0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00 }},
/* greater */ { 62, {0x00, 0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00 }},
/* question */ { 63, {0x00, 0x70, 0x88, 0x10, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00 }},
/* at */ { 64, {0x00, 0x70, 0x88, 0x98, 0xA8, 0xB0, 0x80, 0x70, 0x00, 0x00 }},
/* A */ { 65, {0x00, 0x20, 0x50, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }},
/* B */ { 66, {0x00, 0xF0, 0x48, 0x48, 0x70, 0x48, 0x48, 0xF0, 0x00, 0x00 }},
/* C */ { 67, {0x00, 0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70, 0x00, 0x00 }},
/* D */ { 68, {0x00, 0xF0, 0x48, 0x48, 0x48, 0x48, 0x48, 0xF0, 0x00, 0x00 }},
/* E */ { 69, {0x00, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }},
/* F */ { 70, {0x00, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x00 }},
/* G */ { 71, {0x00, 0x70, 0x88, 0x80, 0x80, 0x98, 0x88, 0x70, 0x00, 0x00 }},
/* H */ { 72, {0x00, 0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88, 0x00, 0x00 }},
/* I */ { 73, {0x00, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* J */ { 74, {0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00, 0x00 }},
/* K */ { 75, {0x00, 0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88, 0x00, 0x00 }},
/* L */ { 76, {0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00, 0x00 }},
/* M */ { 77, {0x00, 0x88, 0x88, 0xD8, 0xA8, 0x88, 0x88, 0x88, 0x00, 0x00 }},
/* N */ { 78, {0x00, 0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00, 0x00 }},
/* O */ { 79, {0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* P */ { 80, {0x00, 0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x00 }},
/* Q */ { 81, {0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0xA8, 0x70, 0x08, 0x00 }},
/* R */ { 82, {0x00, 0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88, 0x00, 0x00 }},
/* S */ { 83, {0x00, 0x70, 0x88, 0x80, 0x70, 0x08, 0x88, 0x70, 0x00, 0x00 }},
/* T */ { 84, {0x00, 0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }},
/* U */ { 85, {0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* V */ { 86, {0x00, 0x88, 0x88, 0x88, 0x50, 0x50, 0x50, 0x20, 0x00, 0x00 }},
/* W */ { 87, {0x00, 0x88, 0x88, 0x88, 0xA8, 0xA8, 0xD8, 0x88, 0x00, 0x00 }},
/* X */ { 88, {0x00, 0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00, 0x00 }},
/* Y */ { 89, {0x00, 0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }},
/* Z */ { 90, {0x00, 0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00, 0x00 }},
/* bracketleft */ { 91, {0x00, 0x70, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, 0x00, 0x00 }},
/* backslash */ { 92, {0x00, 0x80, 0x80, 0x40, 0x20, 0x10, 0x08, 0x08, 0x00, 0x00 }},
/* bracketright */ { 93, {0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, 0x00 }},
/* asciicircum */ { 94, {0x00, 0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* underscore */ { 95, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00 }},
/* grave */ { 96, {0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* a */ { 97, {0x00, 0x00, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }},
/* b */ { 98, {0x00, 0x80, 0x80, 0xB0, 0xC8, 0x88, 0xC8, 0xB0, 0x00, 0x00 }},
/* c */ { 99, {0x00, 0x00, 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x00, 0x00 }},
/* d */ { 100, {0x00, 0x08, 0x08, 0x68, 0x98, 0x88, 0x98, 0x68, 0x00, 0x00 }},
/* e */ { 101, {0x00, 0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }},
/* f */ { 102, {0x00, 0x30, 0x48, 0x40, 0xF0, 0x40, 0x40, 0x40, 0x00, 0x00 }},
/* g */ { 103, {0x00, 0x00, 0x00, 0x78, 0x88, 0x88, 0x78, 0x08, 0x88, 0x70 }},
/* h */ { 104, {0x00, 0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, 0x00 }},
/* i */ { 105, {0x00, 0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* j */ { 106, {0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x48, 0x48, 0x30 }},
/* k */ { 107, {0x00, 0x80, 0x80, 0x88, 0x90, 0xE0, 0x90, 0x88, 0x00, 0x00 }},
/* l */ { 108, {0x00, 0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* m */ { 109, {0x00, 0x00, 0x00, 0xD0, 0xA8, 0xA8, 0xA8, 0x88, 0x00, 0x00 }},
/* n */ { 110, {0x00, 0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, 0x00 }},
/* o */ { 111, {0x00, 0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* p */ { 112, {0x00, 0x00, 0x00, 0xB0, 0xC8, 0x88, 0xC8, 0xB0, 0x80, 0x80 }},
/* q */ { 113, {0x00, 0x00, 0x00, 0x68, 0x98, 0x88, 0x98, 0x68, 0x08, 0x08 }},
/* r */ { 114, {0x00, 0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80, 0x00, 0x00 }},
/* s */ { 115, {0x00, 0x00, 0x00, 0x70, 0x80, 0x70, 0x08, 0xF0, 0x00, 0x00 }},
/* t */ { 116, {0x00, 0x40, 0x40, 0xF0, 0x40, 0x40, 0x48, 0x30, 0x00, 0x00 }},
/* u */ { 117, {0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }},
/* v */ { 118, {0x00, 0x00, 0x00, 0x88, 0x88, 0x50, 0x50, 0x20, 0x00, 0x00 }},
/* w */ { 119, {0x00, 0x00, 0x00, 0x88, 0x88, 0xA8, 0xA8, 0x50, 0x00, 0x00 }},
/* x */ { 120, {0x00, 0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, 0x00 }},
/* y */ { 121, {0x00, 0x00, 0x00, 0x88, 0x88, 0x98, 0x68, 0x08, 0x88, 0x70 }},
/* z */ { 122, {0x00, 0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00, 0x00 }},
/* braceleft */ { 123, {0x00, 0x18, 0x20, 0x10, 0x60, 0x10, 0x20, 0x18, 0x00, 0x00 }},
/* bar */ { 124, {0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }},
/* braceright */ { 125, {0x00, 0x60, 0x10, 0x20, 0x18, 0x20, 0x10, 0x60, 0x00, 0x00 }},
/* asciitilde */ { 126, {0x00, 0x48, 0xA8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* space */ { 160, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* exclamdown */ { 161, {0x00, 0x20, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }},
/* cent */ { 162, {0x00, 0x00, 0x20, 0x78, 0xA0, 0xA0, 0xA0, 0x78, 0x20, 0x00 }},
/* sterling */ { 163, {0x00, 0x30, 0x48, 0x40, 0xE0, 0x40, 0x48, 0xB0, 0x00, 0x00 }},
/* currency */ { 164, {0x00, 0x00, 0x00, 0x88, 0x70, 0x50, 0x70, 0x88, 0x00, 0x00 }},
/* yen */ { 165, {0x00, 0x88, 0x88, 0x50, 0x20, 0xF8, 0x20, 0x20, 0x20, 0x00 }},
/* brokenbar */ { 166, {0x00, 0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20, 0x00, 0x00 }},
/* section */ { 167, {0x00, 0x70, 0x80, 0xE0, 0x90, 0x48, 0x38, 0x08, 0x70, 0x00 }},
/* dieresis */ { 168, {0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* copyright */ { 169, {0x00, 0x70, 0x88, 0xA8, 0xC8, 0xA8, 0x88, 0x70, 0x00, 0x00 }},
/* ordfeminine */ { 170, {0x00, 0x38, 0x48, 0x58, 0x28, 0x00, 0x78, 0x00, 0x00, 0x00 }},
/* guillemotleft */ { 171, {0x00, 0x00, 0x00, 0x24, 0x48, 0x90, 0x48, 0x24, 0x00, 0x00 }},
/* logicalnot */ { 172, {0x00, 0x00, 0x00, 0x00, 0x78, 0x08, 0x00, 0x00, 0x00, 0x00 }},
/* hyphen */ { 173, {0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* registered */ { 174, {0x00, 0x70, 0x88, 0xE8, 0xC8, 0xC8, 0x88, 0x70, 0x00, 0x00 }},
/* macron */ { 175, {0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* degree */ { 176, {0x00, 0x20, 0x50, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* plusminus */ { 177, {0x00, 0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0xF8, 0x00, 0x00 }},
/* twosuperior */ { 178, {0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* threesuperior */ { 179, {0x70, 0x08, 0x30, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* acute */ { 180, {0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* mu */ { 181, {0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0xC8, 0xB0, 0x80, 0x00 }},
/* paragraph */ { 182, {0x00, 0x78, 0xE8, 0xE8, 0x68, 0x28, 0x28, 0x28, 0x00, 0x00 }},
/* periodcentered */ { 183, {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* cedilla */ { 184, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20 }},
/* onesuperior */ { 185, {0x20, 0x60, 0x20, 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00 }},
/* ordmasculine */ { 186, {0x00, 0x30, 0x48, 0x48, 0x30, 0x00, 0x78, 0x00, 0x00, 0x00 }},
/* guillemotright */ { 187, {0x00, 0x00, 0x00, 0x90, 0x48, 0x24, 0x48, 0x90, 0x00, 0x00 }},
/* onequarter */ { 188, {0x40, 0xC0, 0x40, 0x40, 0xE4, 0x0C, 0x14, 0x3C, 0x04, 0x00 }},
/* onehalf */ { 189, {0x40, 0xC0, 0x40, 0x40, 0xE8, 0x14, 0x04, 0x08, 0x1C, 0x00 }},
/* threequarters */ { 190, {0xC0, 0x20, 0x40, 0x20, 0xC8, 0x18, 0x28, 0x78, 0x08, 0x00 }},
/* questiondown */ { 191, {0x00, 0x20, 0x00, 0x20, 0x20, 0x40, 0x88, 0x70, 0x00, 0x00 }},
/* Agrave */ { 192, {0x40, 0x20, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }},
/* Aacute */ { 193, {0x10, 0x20, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }},
/* Acircumflex */ { 194, {0x20, 0x50, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }},
/* Atilde */ { 195, {0x48, 0xB0, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }},
/* Adieresis */ { 196, {0x50, 0x00, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }},
/* Aring */ { 197, {0x20, 0x50, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }},
/* AE */ { 198, {0x00, 0x3C, 0x50, 0x90, 0x9C, 0xF0, 0x90, 0x9C, 0x00, 0x00 }},
/* Ccedilla */ { 199, {0x00, 0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70, 0x20, 0x40 }},
/* Egrave */ { 200, {0x40, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }},
/* Eacute */ { 201, {0x10, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }},
/* Ecircumflex */ { 202, {0x20, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }},
/* Edieresis */ { 203, {0x50, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }},
/* Igrave */ { 204, {0x40, 0x20, 0x70, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* Iacute */ { 205, {0x10, 0x20, 0x70, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* Icircumflex */ { 206, {0x20, 0x50, 0x70, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* Idieresis */ { 207, {0x50, 0x00, 0x70, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* Eth */ { 208, {0x00, 0xF0, 0x48, 0x48, 0xE8, 0x48, 0x48, 0xF0, 0x00, 0x00 }},
/* Ntilde */ { 209, {0x28, 0x50, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00, 0x00 }},
/* Ograve */ { 210, {0x40, 0x20, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* Oacute */ { 211, {0x10, 0x20, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* Ocircumflex */ { 212, {0x20, 0x50, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* Otilde */ { 213, {0x28, 0x50, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* Odieresis */ { 214, {0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* multiply */ { 215, {0x00, 0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, 0x00 }},
/* Oslash */ { 216, {0x00, 0x70, 0x98, 0x98, 0xA8, 0xC8, 0xC8, 0x70, 0x00, 0x00 }},
/* Ugrave */ { 217, {0x40, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* Uacute */ { 218, {0x10, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* Ucircumflex */ { 219, {0x20, 0x50, 0x00, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* Udieresis */ { 220, {0x50, 0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* Yacute */ { 221, {0x10, 0x20, 0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x00, 0x00 }},
/* Thorn */ { 222, {0x00, 0x80, 0xF0, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x00 }},
/* germandbls */ { 223, {0x00, 0x70, 0x88, 0x90, 0xA0, 0x90, 0x88, 0xB0, 0x00, 0x00 }},
/* agrave */ { 224, {0x40, 0x20, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }},
/* aacute */ { 225, {0x10, 0x20, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }},
/* acircumflex */ { 226, {0x20, 0x50, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }},
/* atilde */ { 227, {0x28, 0x50, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }},
/* adieresis */ { 228, {0x00, 0x50, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }},
/* aring */ { 229, {0x20, 0x50, 0x20, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }},
/* ae */ { 230, {0x00, 0x00, 0x00, 0x78, 0x14, 0x7C, 0x90, 0x7C, 0x00, 0x00 }},
/* ccedilla */ { 231, {0x00, 0x00, 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x20, 0x40 }},
/* egrave */ { 232, {0x40, 0x20, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }},
/* eacute */ { 233, {0x10, 0x20, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }},
/* ecircumflex */ { 234, {0x20, 0x50, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }},
/* edieresis */ { 235, {0x00, 0x50, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }},
/* igrave */ { 236, {0x40, 0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* iacute */ { 237, {0x20, 0x40, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* icircumflex */ { 238, {0x20, 0x50, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* idieresis */ { 239, {0x00, 0x50, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }},
/* eth */ { 240, {0x00, 0xC0, 0x30, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* ntilde */ { 241, {0x28, 0x50, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, 0x00 }},
/* ograve */ { 242, {0x40, 0x20, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* oacute */ { 243, {0x10, 0x20, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* ocircumflex */ { 244, {0x20, 0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* otilde */ { 245, {0x28, 0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* odieresis */ { 246, {0x00, 0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }},
/* divide */ { 247, {0x00, 0x00, 0x20, 0x00, 0xF8, 0x00, 0x20, 0x00, 0x00, 0x00 }},
/* oslash */ { 248, {0x00, 0x00, 0x00, 0x78, 0x98, 0xA8, 0xC8, 0xF0, 0x00, 0x00 }},
/* ugrave */ { 249, {0x40, 0x20, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }},
/* uacute */ { 250, {0x10, 0x20, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }},
/* ucircumflex */ { 251, {0x20, 0x50, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }},
/* udieresis */ { 252, {0x00, 0x50, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }},
/* yacute */ { 253, {0x00, 0x10, 0x20, 0x88, 0x88, 0x98, 0x68, 0x08, 0x88, 0x70 }},
/* thorn */ { 254, {0x00, 0x00, 0x80, 0xF0, 0x88, 0x88, 0x88, 0xF0, 0x80, 0x80 }},
/* ydieresis */ { 255, {0x00, 0x50, 0x00, 0x88, 0x88, 0x98, 0x68, 0x08, 0x88, 0x70 }},
/* char0 */ { 0, {0x00, 0xA8, 0x00, 0x88, 0x00, 0x88, 0x00, 0xA8, 0x00, 0x00 }}
};
void alto2_cpu_device::fake_status_putch(int x, UINT8 ch)
{
const bdf_6x10_t* pf = bdf_6x10;
while (pf->code != ch && pf->code != 0)
pf++;
int dx = 6 * x;
if (dx >= ALTO2_DISPLAY_WIDTH)
return;
for (int dy = 0; dy < 10; dy++)
{
UINT8* pix = m_dsp.scanline[ALTO2_DISPLAY_HEIGHT + 1 + dy] + dx;
UINT8 bits = ~pf->bits[dy];
pix[0] = (bits >> 7) & 1;
pix[1] = (bits >> 6) & 1;
pix[2] = (bits >> 5) & 1;
pix[3] = (bits >> 4) & 1;
pix[4] = (bits >> 3) & 1;
pix[5] = (bits >> 2) & 1;
}
}
void alto2_cpu_device::fake_status_printf(int x, const char* format, ...)
{
static char buff[256];
va_list ap;
va_start(ap, format);
vsnprintf(buff, sizeof(buff), format, ap);
va_end(ap);
char* src = buff;
while (*src)
fake_status_putch(x++, *src++);
}

303
src/emu/cpu/alto2/a2disp.h Normal file
View File

@ -0,0 +1,303 @@
/*****************************************************************************
*
* Xerox AltoII display block
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
/**
* @brief start value for the horizontal line counter
*
* This value is loaded into the three 4 bit counters (type 9316)
* with numbers 65, 67, and 75.
* 65: A=0 B=1 C=1 D=0
* 67: A=1 B=0 C=0 D=1
* 75: A=0 B=0 C=0 D=0
*
* The value is 150
*/
#define ALTO2_DISPLAY_HLC_START (2+4+16+128)
/**
* @brief end value for the horizontal line counter
*
* This is decoded by H30, an 8 input NAND gate.
* The value is 1899; horz. line count range 150...1899 = 1750.
*
* There are 1750 / 2 = 875 total scanlines.
*/
#define ALTO2_DISPLAY_HLC_END (1+2+8+32+64+256+512+1024)
/**
* @brief display total height, including overscan (vertical blanking and synch)
*
* The display is interleaved in two fields, alternatingly drawing the even and odd
* scanlines to the monitor. The frame rate is 60Hz, which is actually the rate
* of the half-frames. The rate for full frames is thus 30Hz.
*/
#define ALTO2_DISPLAY_TOTAL_HEIGHT ((ALTO2_DISPLAY_HLC_END + 1 - ALTO2_DISPLAY_HLC_START) / 2)
/**
* @brief display total width, including horizontal blanking
*
* Known facts:
*
* We have 606x808 visible pixels, and the pixel clock is said to be 50ns
* (20MHz), while the crystal in the schematics is labeled 20.16 MHz,
* so the pixel clock would actually be 49.6031ns.
*
* The total number of scanlines is, according to the docs, 875.
*
* 875 scanlines at 30 frames per second, thus the scanline rate is 26.250 kHz.
*
* If I divide 20.16 MHz by 26.250 kHz, I get 768 pixels for the total width
* of a scanline in pixels.
*
* The horizontal blanking period would then be 768 - 606 = 162 pixels, and
* thus 162 * 49.6031ns ~= 8036ns = 8.036us for the HBLANK time.
*
* In the display schematics there is a divide by 24 logic, and when
* dividing the 768 pixels per scanline by 24, we have 32 phases of a scanline.
*
* A S8223 PROM (a63) with 32x8 bits contains the status of the HBLANK and
* HSYNC signals for these phases, the SCANEND and HLCGATE signals, as well
* as its own next address A0-A3!
*
*/
#define ALTO2_DISPLAY_TOTAL_WIDTH 768
#define ALTO2_DISPLAY_FIFO 16 //!< the display fifo has 16 words
#define ALTO2_DISPLAY_SCANLINE_WORDS (ALTO2_DISPLAY_TOTAL_WIDTH/16) //!< words per scanline
#define ALTO2_DISPLAY_HEIGHT 808 //!< number of visible scanlines per frame; 808 really, but there are some empty lines?
#define ALTO2_DISPLAY_WIDTH 606 //!< visible width of the display; 38 x 16 bit words - 2 pixels
#define ALTO2_DISPLAY_VISIBLE_WORDS ((ALTO2_DISPLAY_WIDTH+15)/16) //!< visible words per scanline
#define ALTO2_DISPLAY_BITCLOCK 20160000ll //!< display bit clock in in Hertz (20.16MHz)
#define ALTO2_DISPLAY_BITTIME(n) (U64(1000000000000)*(n)/ALTO2_DISPLAY_BITCLOCK) //!< display bit time in in pico seconds (~= 49.6031ns)
#define ALTO2_DISPLAY_SCANLINE_TIME ALTO2_DISPLAY_BITTIME(ALTO2_DISPLAY_TOTAL_WIDTH)//!< time for a scanline in pico seconds (768 * 49.6031ns ~= 38095.1808ns)
#define ALTO2_DISPLAY_VISIBLE_TIME ALTO2_DISPLAY_BITTIME(ALTO2_DISPLAY_WIDTH) //!< time of the visible part of a scanline in pico seconds (606 * 49.6031ns ~= 30059.4786ns)
#define ALTO2_DISPLAY_WORD_TIME ALTO2_DISPLAY_BITTIME(16) //!< time for a word in pico seconds (16 pixels * 49.6031ns ~= 793.6496ns)
#define ALTO2_DISPLAY_VBLANK_TIME ((ALTO2_DISPLAY_TOTAL_HEIGHT-ALTO2_DISPLAY_HEIGHT)*HZ_TO_ATTOSECONDS(26250)/2)
#else // ALTO2_DEFINE_CONSTANTS
/**
* @brief structure of the display context
*
* Schematics of the task clear and wakeup signal generators
* <PRE>
* A quote (') appended to a signal name means inverted signal.
*
* AND | NAND| NOR | FF | Q N174
* -----+--- -----+--- -----+--- -----+--- -----
* 0 0 | 0 0 0 | 1 0 0 | 1 S'\0| 1 delay
* 0 1 | 0 0 1 | 1 0 1 | 0 R'\0| 0
* 1 0 | 0 1 0 | 1 1 0 | 0
* 1 1 | 1 1 1 | 0 1 1 | 0
*
*
* DVTAC'
* >-------+ +-----+
* | | FF |
* VBLANK'+----+ DELVBLANK' +---+ DELVBLANK +----+ +--|S' |
* >------|N174|------+-----|inv|--------------|NAND| VBLANKPULSE | | WAKEDVT'
* +----+ | +---+ | o--+-----------|R' Q|---------------------->
* | +-| | | | |
* +----+ | DDELVBLANK' | +----+ | +-----+
* +-|N174|-----------------------------+ | +---+
* | +----+ | +------oAND|
* | | DSP07.01 | | o----------+
* +-------------+ >---------|------o | |
* | +---+ |
* | |
* | +-----+ |
* | | FF | | +-----+
* DHTAC' +---+ | | | | | FF |
* >--------------oNOR| *07.25 +----+ +-|S' | DHTBLK' | | |
* BLOCK' | |---------------|NAND| | Q|--+----------|--|S1' | WAKEDHT'
* >--------------o | DCSYSCLK | o--------|R' | | >--------|--|S2' Q|--------->
* +---+ >---------| | +-----+ | DHTAC' +--|R' |
* +----+ | +-----+
* +------------+
* |
* DWTAC' +---+ | +-----+
* >--------------oNOR| *07.26 +----+ | | FF |
* BLOCK' | |---------|NAND| DSP07.01 | | |
* >--------------o | DCSYSCLK| o----------|---|S1' | DWTCN' +---+ DWTCN
* +---+ >-------| | +---|S2' Q|--------|inv|-----------+----
* +----+ +---|R' | +---+ |
* | +-----+ |
* SCANEND +----+ | |
* >-------------|NAND| CLRBUF' | .----------------------+
* DCLK | o----------------+ |
* >-------------| | | +-----+
* +----+ +--| NAND|
* STOPWAKE' | |preWake +----+ WAKEDWT'
* >-----------| o--------|N174|--------->
* VBLANK' | | +----+
* >-----------| |
* +-----+
* a40c
* VBLANKPULSE +----+
* -------------|NAND|
* | o--+
* +--| | |
* | +----+ |
* +----------|-+
* +----------+ |
* CURTAC' +---+ | +----+ | a20d
* >--------------oNOR| *07.27 +----+ +--|NAND| | +----+
* BLOCK' | |---------|NAND| DSP07.07 | o----+----o NOR| preWK +----+ WAKECURT'
* >--------------o | DCSYSCLK| o-----------| | | |--------|N174|--------->
* +---+ >-------| | +----+ +----o | +----+
* +----+ a40d | +----+
* a30c |
* CURTAC' +----+ |
* >------------|NAND| DSP07.03 |
* | o--+------------+
* +--| | |
* | +----+ |
* +----------|-+
* +----------+ |
* | +----+ |
* +--|NAND| |
* CLRBUF' | o----+
* >------------| |
* +----+
* a30d
* </PRE>
*/
#ifndef _A2DISP_H_
#define _A2DISP_H_
struct {
UINT16 state; //!< current state of the display_state_machine()
UINT16 hlc; //!< horizontal line counter
UINT16 setmode; //!< value written by last SETMODE<-
UINT16 inverse; //!< set to 0xffff if line is inverse, 0x0000 otherwise
bool halfclock; //!< set 0 for normal pixel clock, 1 for half pixel clock
UINT16 fifo[ALTO2_DISPLAY_FIFO]; //!< display word fifo
UINT8 wa; //!< fifo input pointer (write address; 4-bit)
UINT8 ra; //!< fifo output pointer (read address; 4-bit)
UINT8 a63; //!< most recent value read from the PROM a63
UINT8 a66; //!< most recent value read from the PROM a66
bool dht_blocks; //!< set non-zero, if the DHT executed BLOCK
bool dwt_blocks; //!< set non-zero, if the DWT executed BLOCK
bool curt_blocks; //!< set non-zero, if the CURT executed BLOCK
bool curt_wakeup; //!< set non-zero, if CURT wakeups are generated
UINT16 vblank; //!< most recent HLC with VBLANK still high (11-bit)
UINT16 xpreg; //!< cursor cursor x position register (10-bit)
UINT16 csr; //!< cursor shift register (16-bit)
UINT32 curxpos; //!< helper: first cursor word in scanline
UINT16 cursor0; //!< helper: shifted cursor data for left word
UINT16 cursor1; //!< helper: shifted cursor data for right word
UINT16 *raw_bitmap; //!< array of words of the raw bitmap that is displayed
UINT8 **scanline; //!< array of scanlines with 1 byte per pixel
bitmap_ind16 *bitmap; //!< MAME bitmap with 16 bit indices
bool odd_frame; //!< true, if odd frame is drawn
} m_dsp;
/**
* @brief PROM a38 contains the STOPWAKE' and MBEMBPTY' signals for the FIFO
* <PRE>
* The inputs to a38 are the UNLOAD counter RA[0-3] and the DDR<- counter
* WA[0-3], and the designer decided to reverse the address lines :-)
*
* a38 counter FIFO counter
* --------------------------
* A0 RA[0] fifo_rd
* A1 RA[1]
* A2 RA[2]
* A3 RA[3]
* A4 WA[0] fifo_wr
* A5 WA[1]
* A6 WA[2]
* A7 WA[3]
*
* Only two bits of a38 are used:
* O1 (002) = STOPWAKE'
* O3 (010) = MBEMPTY'
* </PRE>
*/
UINT8* m_disp_a38;
//! output bits of PROM A38
enum {
disp_a38_STOPWAKE = (1 << 1),
disp_a38_MBEMPTY = (1 << 3)
};
/**
* @brief emulation of PROM a63 in the display schematics page 8
* <PRE>
* The PROM's address lines are driven by a clock CLK, which is
* pixel clock / 24, and an inverted half-scanline signal H[1]'.
*
* It is 32x8 bits and its output bits (B) are connected to the
* signals, as well as its own address lines (A) through a latch
* of the type SN74774 like this:
*
* B 174 A others
* ------------------------
* 0 5 - HBLANK
* 1 0 - HSYNC
* 2 4 0
* 3 1 1
* 4 3 2
* 5 2 3
* 6 - - SCANEND
* 7 - - HLCGATE
* ------------------------
* H[1]' - 4
*
* The display_state_machine() is called by the CPU at a rate of pixelclock/24,
* which happens to be very close to every 7th CPU micrcocycle.
* </PRE>
*/
UINT8* m_disp_a63;
enum {
disp_a63_HBLANK = (1 << 0), //!< PROM a63 B0 is latched as HBLANK signal
disp_a63_HSYNC = (1 << 1), //!< PROM a63 B1 is latched as HSYNC signal
disp_a63_A0 = (1 << 2), //!< PROM a63 B2 is the latched next address bit A0
disp_a63_A1 = (1 << 3), //!< PROM a63 B3 is the latched next address bit A1
disp_a63_A2 = (1 << 4), //!< PROM a63 B4 is the latched next address bit A2
disp_a63_A3 = (1 << 5), //!< PROM a63 B5 is the latched next address bit A3
disp_a63_SCANEND = (1 << 6), //!< PROM a63 B6 SCANEND signal, which resets the FIFO counters
disp_a63_HLCGATE = (1 << 7) //!< PROM a63 B7 HLCGATE signal, which enables counting the HLC
};
/**
* @brief vertical blank and synch PROM
*
* PROM a66 is a 256x4 bit (type 3601), containing the vertical blank + synch.
* Address lines are driven by H[1] to H[128] of the the horz. line counters.
* The PROM is enabled whenever H[256] and H[512] are both 0.
*/
UINT8* m_disp_a66;
enum {
disp_a66_VSYNC_ODD = (1 << 0), //!< Q1 (001) is VSYNC for the odd field (with H1024=1)
disp_a66_VSYNC_EVEN = (1 << 1), //!< Q2 (002) is VSYNC for the even field (with H1024=0)
disp_a66_VBLANK_ODD = (1 << 2), //!< Q3 (004) is VBLANK for the odd field (with H1024=1)
disp_a66_VBLANK_EVEN = (1 << 3) //!< Q4 (010) is VBLANK for the even field (with H1024=0)
};
void update_bitmap_word(UINT16* bitmap, int x, int y, UINT16 word); //!< update a word in the screen bitmap
void unload_word(); //!< unload the next word from the display FIFO and shift it to the screen
void display_state_machine(); //!< function called by the CPU to enter the next display state
void f2_late_evenfield(void); //!< branch on the evenfield flip-flop
void init_disp(); //!< initialize the display context
void exit_disp(); //!< deinitialize the display context
void reset_disp(); //!< reset the display context
void fake_status_putch(int x, UINT8 ch);
void fake_status_printf(int x, const char* format, ...);
#endif // _A2DISP_H_
#endif // ALTO2_DEFINE_CONSTANTS

48
src/emu/cpu/alto2/a2dvt.c Normal file
View File

@ -0,0 +1,48 @@
/*****************************************************************************
*
* Xerox AltoII display vertical task
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
/**
* @brief f1_dvt_block early: disable the display word task
*/
void alto2_cpu_device::f1_early_dvt_block()
{
// m_task_wakeup &= ~(1 << m_task);
LOG((LOG_DVT,2," BLOCK %s\n", task_name(m_task)));
}
/**
* @brief called by the CPU when the display vertical task becomes active
*/
void alto2_cpu_device::activate_dvt()
{
m_task_wakeup &= ~(1 << m_task);
}
/**
* @brief initialize display vertical task
*/
void alto2_cpu_device::init_dvt(int task)
{
set_f1(task, f1_block, &alto2_cpu_device::f1_early_dvt_block, 0);
set_f2(task, f2_dvt_evenfield, 0, &alto2_cpu_device::f2_late_evenfield);
m_active_callback[task] = &alto2_cpu_device::activate_dvt;
}
void alto2_cpu_device::exit_dvt()
{
// nothing to do yet
}
void alto2_cpu_device::reset_dvt()
{
// nothing to do yet
}

27
src/emu/cpu/alto2/a2dvt.h Normal file
View File

@ -0,0 +1,27 @@
/*****************************************************************************
*
* Xerox AltoII display vertical task (DVT)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2DVT_H_
#define _A2DVT_H_
//! F2 functions for display vertical task
enum {
f2_dvt_evenfield = f2_task_10 //!< f2 10: load even field
};
void f1_early_dvt_block(); //!< F1 func: disable the display word task
void activate_dvt(); //!< called by the CPU when the display vertical task becomes active
void init_dvt(int task = task_dvt); //!< initialize the display vertical task
void exit_dvt(); //!< deinitialize the display vertical task
void reset_dvt(); //!< reset the display vertical task
#endif // _A2DVT_H_
#endif // ALTO2_DEFINE_CONSTANTS

64
src/emu/cpu/alto2/a2dwt.c Normal file
View File

@ -0,0 +1,64 @@
/*****************************************************************************
*
* Xerox AltoII display word task
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
//! PROM a38 bit O1 is STOPWAKE' (stop DWT if bit is zero)
#define FIFO_STOPWAKE(a38) (0 == (a38 & disp_a38_STOPWAKE) ? true : false)
/**
* @brief block the display word task
*/
void alto2_cpu_device::f1_early_dwt_block()
{
m_dsp.dwt_blocks = true;
/* clear the wakeup for the display word task */
m_task_wakeup &= ~(1 << m_task);
LOG((LOG_DWT,2," BLOCK %s\n", task_name(m_task)));
/* wakeup the display horizontal task, if it didn't block itself */
if (!m_dsp.dht_blocks)
m_task_wakeup |= 1 << task_dht;
}
/**
* @brief load the display data register
*/
void alto2_cpu_device::f2_late_dwt_load_ddr()
{
LOG((LOG_DWT,2," DDR<- BUS (%#o)\n", m_bus));
m_dsp.fifo[m_dsp.wa] = m_bus;
m_dsp.wa = (m_dsp.wa + 1) % ALTO2_DISPLAY_FIFO;
UINT8 a38 = m_disp_a38[m_dsp.ra * 16 + m_dsp.wa];
if (FIFO_STOPWAKE(a38))
m_task_wakeup &= ~(1 << task_dwt);
LOG((LOG_DWT,2, " DWT push %04x into FIFO[%02o]%s\n",
m_bus, (m_dsp.wa - 1) & (ALTO2_DISPLAY_FIFO - 1),
FIFO_STOPWAKE(a38) ? " STOPWAKE" : ""));
}
void alto2_cpu_device::init_dwt(int task)
{
set_f1(task, f1_block, &alto2_cpu_device::f1_early_dwt_block, 0);
set_f2(task, f2_dwt_load_ddr, 0, &alto2_cpu_device::f2_late_dwt_load_ddr);
}
void alto2_cpu_device::exit_dwt()
{
// nothing to do yet
}
void alto2_cpu_device::reset_dwt()
{
m_dsp.dwt_blocks = false;
memset(m_dsp.fifo, 0, sizeof(m_dsp.fifo));
m_dsp.wa = 0;
m_dsp.ra = 0;
}

27
src/emu/cpu/alto2/a2dwt.h Normal file
View File

@ -0,0 +1,27 @@
/*****************************************************************************
*
* Xerox AltoII display word task (DWT)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2DWT_H_
#define _A2DWT_H_
//! F2 functions for display word task
enum {
f2_dwt_load_ddr = f2_task_10 //!< f2 10: load display data register
};
void f1_early_dwt_block(); //!< F1 func: block the display word task
void f2_late_dwt_load_ddr(); //!< F2 func: load the display data register
void init_dwt(int task = task_dwt); //!< initialize the display word task
void exit_dwt(); //!< deinitialize the display word task
void reset_dwt(); //!< reset the display word task
#endif // _A2DWT_H_
#endif // ALTO2_DEFINE_CONSTANTS

690
src/emu/cpu/alto2/a2emu.c Normal file
View File

@ -0,0 +1,690 @@
/*****************************************************************************
*
* Xerox AltoII emulator task
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
/** @brief CTL2K_U3 address line for F2 function */
#define CTL2K_U3(f2) (f2 == f2_emu_idisp ? 0x80 : 0x00)
/**
* width,from,to of the 16 bit instruction register
* 1 1 1 1 1 1
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* =============================================================
* x - - - - - - - - - - - - - - - arithmetic operation
* 0 m m - - - - - - - - - - - - - memory function
* 0 0 0 - - - - - - - - - - - - - jump functions
* 0 0 1 d d - - - - - - - - - - - LDA dstAC
* 0 1 0 d d - - - - - - - - - - - STA dstAC
* 0 1 1 - - - - - - - - - - - - - augmented functions
* 1 s s - - - - - - - - - - - - - source accumulator (0-3)
* 1 - - d d - - - - - - - - - - - destination accumulator (0-3)
* 1 s s d d x x x - - - - - - - - accumulator function
* 1 s s d d 0 0 0 - - - - - - - - COM dstAC, srcAC
* 1 s s d d 0 0 1 - - - - - - - - NEG dstAC, srcAC
* 1 s s d d 0 1 0 - - - - - - - - MOV dstAC, srcAC
* 1 s s d d 0 1 1 - - - - - - - - INC dstAC, srcAC
* 1 s s d d 1 0 0 - - - - - - - - ADC dstAC, srcAC
* 1 s s d d 1 0 1 - - - - - - - - SUB dstAC, srcAC
* 1 s s d d 1 1 0 - - - - - - - - ADD dstAC, srcAC
* 1 s s d d 1 1 1 - - - - - - - - AND dstAC, srcAC
* 1 - - - - - - - x x - - - - - - shift operation
* 1 - - - - - - - 0 0 - - - - - - nothing
* 1 - - - - - - - 0 1 - - - - - - rotate left through carry
* 1 - - - - - - - 1 0 - - - - - - rotate right through carry
* 1 - - - - - - - 1 1 - - - - - - swap byte halves
* 1 - - - - - - - - - x x - - - - carry in mode
* 1 - - - - - - - - - 0 0 - - - - nothing
* 1 - - - - - - - - - 0 1 - - - - Z carry in is zero
* 1 - - - - - - - - - 1 0 - - - - O carry in is one
* 1 - - - - - - - - - 1 1 - - - - C carry in is complemented carry
* 1 - - - - - - - - - - - x - - - NL
* - - - - - - - - - - - - - x x x conditional execution
* - - - - - - - - - - - - - 0 0 0 NVR never skip
* - - - - - - - - - - - - - 0 0 1 SKP always skip
* - - - - - - - - - - - - - 0 1 0 SZC skip if carry result is zero
* - - - - - - - - - - - - - 0 1 1 SNC skip if carry result is non-zero
* - - - - - - - - - - - - - 1 0 0 SZR skip if 16 bit result is zero
* - - - - - - - - - - - - - 1 0 1 SNR skip if 16 bit result is non-zero
* - - - - - - - - - - - - - 1 1 0 SEZ skip if either result is zero
* - - - - - - - - - - - - - 1 1 1 SBN skip if both results are non-zero
*/
#define IR_ARITH(ir) X_RDBITS(ir,16, 0, 0)
#define IR_SrcAC(ir) X_RDBITS(ir,16, 1, 2)
#define IR_DstAC(ir) X_RDBITS(ir,16, 3, 4)
#define IR_AFunc(ir) X_RDBITS(ir,16, 5, 7)
#define IR_SH(ir) X_RDBITS(ir,16, 8, 9)
#define IR_CY(ir) X_RDBITS(ir,16,10,11)
#define IR_NL(ir) X_RDBITS(ir,16,12,12)
#define IR_SK(ir) X_RDBITS(ir,16,13,15)
#define IR_MFunc(ir) X_RDBITS(ir,16, 1, 2)
#define IR_JFunc(ir) X_RDBITS(ir,16, 3, 4)
#define IR_I(ir) X_RDBITS(ir,16, 5, 5)
#define IR_X(ir) X_RDBITS(ir,16, 6, 7)
#define IR_DISP(ir) X_RDBITS(ir,16, 8,15)
#define IR_AUGFUNC(ir) X_RDBITS(ir,16, 3, 7)
#define op_MFUNC_MASK 0060000 //!< instruction register memory function mask
#define op_MFUNC_JUMP 0000000 //!< jump functions value
#define op_JUMP_MASK 0014000 //!< jump functions mask
#define op_JMP 0000000 //!< jump
#define op_JSR 0004000 //!< jump to subroutine
#define op_ISZ 0010000 //!< increment and skip if zero
#define op_DSZ 0014000 //!< decrement and skip if zero
#define op_LDA 0020000 //!< load accu functions value
#define op_STA 0040000 //!< store accu functions value
#define op_AUGMENTED 0060000 //!< store accu functions value
#define op_AUGM_MASK 0077400 //!< mask covering all augmented functions
#define op_AUGM_NODISP 0061000 //!< augmented functions w/o displacement
#define op_AUGM_SUBFUNC 0000037 //!< mask for augmented subfunctions in DISP
#define op_CYCLE 0060000 //!< cycle AC0
#define op_NODISP 0061000 //!< NODISP: opcodes without displacement
#define op_DIR 0061000 //!< disable interrupts
#define op_EIR 0061001 //!< enable interrupts
#define op_BRI 0061002 //!< branch and return from interrupt
#define op_RCLK 0061003 //!< read clock to AC0, AC1
#define op_SIO 0061004 //!< start I/O
#define op_BLT 0061005 //!< block transfer
#define op_BLKS 0061006 //!< block set value
#define op_SIT 0061007 //!< start interval timer
#define op_JMPRAM 0061010 //!< jump to microcode RAM (actually ROM, too)
#define op_RDRAM 0061011 //!< read microcode RAM
#define op_WRTRAM 0061012 //!< write microcode RAM
#define op_DIRS 0061013 //!< disable interrupts, and skip, if already disabled
#define op_VERS 0061014 //!< get microcode version in AC0
#define op_DREAD 0061015 //!< double word read (Alto II)
#define op_DWRITE 0061016 //!< double word write (Alto II)
#define op_DEXCH 0061017 //!< double word exchange (Alto II)
#define op_MUL 0061020 //!< unsigned multiply
#define op_DIV 0061021 //!< unsigned divide
#define op_DIAGNOSE1 0061022 //!< write two different accus in fast succession
#define op_DIAGNOSE2 0061023 //!< write Hamming code and memory
#define op_BITBLT 0061024 //!< bit-aligned block transfer
#define op_XMLDA 0061025 //!< load accu AC0 from extended memory (Alto II/XM)
#define op_XMSTA 0061026 //!< store accu AC0 to extended memory (Alto II/XM)
#define op_JSRII 0064400 //!< jump to subroutine PC relative, doubly indirect
#define op_JSRIS 0065000 //!< jump to subroutine AC2 relative, doubly indirect
#define op_CONVERT 0067000 //!< convert bitmapped font to bitmap
#define op_ARITH_MASK 0103400 //!< mask for arithmetic functions
#define op_COM 0100000 //!< one's complement
#define op_NEG 0100400 //!< two's complement
#define op_MOV 0101000 //!< accu transfer
#define op_INC 0101400 //!< increment
#define op_ADC 0102000 //!< add one's complement
#define op_SUB 0102400 //!< subtract by adding two's complement
#define op_ADD 0103000 //!< add
#define op_AND 0103400 //!< logical and
#define ea_DIRECT 0000000 //!< effective address is direct
#define ea_INDIRECT 0002000 //!< effective address is indirect
#define ea_MASK 0001400 //!< mask for effective address modes
#define ea_PAGE0 0000000 //!< e is page 0 address
#define ea_PCREL 0000400 //!< e is PC + signed displacement
#define ea_AC2REL 0001000 //!< e is AC2 + signed displacement
#define ea_AC3REL 0001400 //!< e is AC3 + signed displacement
#define sh_MASK 0000300 //!< shift mode mask (do novel shifts)
#define sh_L 0000100 //!< rotate left through carry
#define sh_R 0000200 //!< rotate right through carry
#define sh_S 0000300 //!< swap byte halves
#define cy_MASK 0000060 //!< carry in mode mask
#define cy_Z 0000020 //!< carry in is zero
#define cy_O 0000040 //!< carry in is one
#define cy_C 0000060 //!< carry in is complemented carry
#define nl_MASK 0000010 //!< no-load mask
#define nl_NONE 0000010 //!< do not load DstAC nor carry
#define sk_MASK 0000007 //!< skip mask
#define sk_NVR 0000000 //!< never skip
#define sk_SKP 0000001 //!< always skip
#define sk_SZC 0000002 //!< skip if carry result is zero
#define sk_SNC 0000003 //!< skip if carry result is non-zero
#define sk_SZR 0000004 //!< skip if 16-bit result is zero
#define sk_SNR 0000005 //!< skip if 16-bit result is non-zero
#define sk_SEZ 0000006 //!< skip if either result is zero
#define sk_SBN 0000007 //!< skip if both results are non-zero
/**
* @brief register selection
*
* <PRE>
* From the schematics: 08_ALU, page 6 (PDF page 4)
*
* EMACT emulator task active
* F2[0-2]=111b <-ACSOURCE and F2_17
* F2[0-2]=101b DNS<- and ACDEST<-
*
* u49 (8 input NAND 74S30)
* ----------------------------------------------
* F2[0] & F2[2] & F2[1]' & IR[03]' & EMACT
*
* F2[0-2] IR[03] EMACT output u49pin8
* --------------------------------------
* 101 0 1 0
* all others 1
*
*
* u59 (8 input NAND 74S30)
* ----------------------------------------------
* F2[0] & F2[2] & F2[1] & IR[01]' & EMACT
*
* F2[0-2] IR[01] EMACT output u59pin8
* --------------------------------------
* 111 0 1 0
* all others 1
*
* u70d (2 input NOR 74S02 used as inverter)
* ---------------------------------------------
* RSEL3 -> RSEL3'
*
* u79b (3 input NAND 74S10)
* ---------------------------------------------
* u49pin8 u59pin8 RSEL3' output 6RA3
* -------------------------------------
* 1 1 1 0
* 0 x x 1
* x 0 x 1
* x x 0 1
*
*
* u60 (8 input NAND 74S30)
* ----------------------------------------------
* F2[0] & F2[2] & F2[1]' & IR[02]' & EMACT
*
* F2[0-2] IR[02] EMACT output u60pin8
* --------------------------------------
* 101 0 1 0
* all others 1
*
* u50 (8 input NAND 74S30)
* ----------------------------------------------
* F2[0] & F2[2] & F2[1] & IR[04]' & EMACT
*
* F2[0-2] IR[04] EMACT output u50pin8
* --------------------------------------
* 111 0 1 0
* all others 1
*
* u70c (2 input NOR 74S02 used as inverter)
* ---------------------------------------------
* RSEL4 -> RSEL4'
*
*
* u79c (3 input NAND 74S10)
* ---------------------------------------------
* u60pin8 u50pin8 RSEL4' output 8RA4
* -------------------------------------
* 1 1 1 0
* 0 x x 1
* x 0 x 1
* x x 0 1
*
* BUG?: schematics seem to have swapped IR(04)' and IR(02)' inputs for the
* RA4 decoding, because SrcAC is selected from IR[1-2]?
* </PRE>
*/
/**
* @brief bs_disp early: drive bus by IR[8-15], possibly sign extended
*
* The high order bits of IR cannot be read directly, but the
* displacement field of IR (8 low order bits) may be read with
* the <-DISP bus source. If the X field of the instruction is
* zero (i.e., it specifies page 0 addressing), then the DISP
* field of the instruction is put on BUS[8-15] and BUS[0-7]
* is zeroed. If the X field of the instruction is non-zero
* (i.e. it specifies PC-relative or base-register addressing)
* then the DISP field is sign-extended and put on the bus.
*
*/
void alto2_cpu_device::bs_early_emu_disp()
{
UINT16 r = IR_DISP(m_emu.ir);
if (IR_X(m_emu.ir)) {
r = ((signed char)r) & 0177777;
}
LOG((LOG_EMU,2, " <-DISP (%06o)\n", r));
m_bus &= r;
}
/**
* @brief f1_block early: block task
*
* The task request for the active task is cleared
*/
void alto2_cpu_device::f1_early_emu_block()
{
#if 0
CPU_CLR_TASK_WAKEUP(m_task);
LOG((LOG_EMU,2, " BLOCK %02o:%s\n", m_task, task_name(m_task)));
#elif 0
fatal(1, "Emulator task want's to BLOCK.\n" \
"%s-%04o: r:%02o af:%02o bs:%02o f1:%02o f2:%02o" \
" t:%o l:%o next:%05o next2:%05o cycle:%lld\n",
task_name(m_task), m_mpc,
m_rsel, m_daluf, m_dbs, m_df1, mdf2,
m_dloadt, m_dloatl, m_next, m_next2,
ntime() / CPU_MICROCYCLE_TIME);
#else
/* just ignore (?) */
#endif
}
/**
* @brief f1_load_rmr late: load the reset mode register
*/
void alto2_cpu_device::f1_late_emu_load_rmr()
{
LOG((LOG_EMU,2," RMR<-; BUS (%#o)\n", m_bus));
m_reset_mode = m_bus;
}
/**
* @brief f1_load_esrb late: load the extended S register bank from BUS[12-14]
*/
void alto2_cpu_device::f1_late_emu_load_esrb()
{
LOG((LOG_EMU,2," ESRB<-; BUS[12-14] (%#o)\n", m_bus));
m_s_reg_bank[m_task] = X_RDBITS(m_bus,16,12,14);
}
/**
* @brief f1_rsnf early: drive the bus from the Ethernet node ID
*
* TODO: move this to the Ethernet code? It's really a emulator
* specific function that is decoded by the Ethernet card.
*/
void alto2_cpu_device::f1_early_rsnf()
{
UINT16 r = 0177400 | m_ether_id;
LOG((LOG_EMU,2," <-RSNF; (%#o)\n", r));
m_bus &= r;
}
/**
* @brief f1_startf early: defines commands for for I/O hardware, including Ethernet
* <PRE>
* (SIO) Start I/O is included to facilitate I/O control, It places the contents of
* AC0 on the processor bus and executes the STARTF function (F1 = 17B). By convention,
* bits of AC0 must be "1" in order to signal devices. See Appendix C for a summary of
* assigned bits.
* Bit 0 100000B Standard Alto: Software boot feature
* Bit 14 000002B Standard Alto: Ethernet
* Bit 15 000001B Standard Alto: Ethernet
* If bit 0 of AC0 is 1, and if an Ethernet board is plugged into the Alto, the machine
* will boot, just as if the "boot button" were pressed (see sections 3.4, 8.4 and 9.2.2
* for discussions of bootstrapping).
*
* SIO also returns a result in AC0. If the Ethernet hardware is installed, the serial
* number and/or Ethernet host address of the machine (0-377B) is loaded into AC0[8-15].
* (On Alto I, the serial number and Ethernet host address are equivalent; on Alto II,
* the value loaded into AC0 is the Ethernet host address only.) If Ethernet hardware
* is missing, AC0[8-15] = 377B. Microcode installed after June 1976, which this manual
* describes, returns AC0[0] = 0. Microcode installed prior to June 1976 returns
* AC0[0] = 1; this is a quick way to acquire the approximate vintage of a machine's
* microcode.
* </PRE>
*
* TODO: move this to the Ethernet code? It's really a emulator
* specific function that is decoded by the Ethernet card.
*/
void alto2_cpu_device::f1_early_startf()
{
LOG((LOG_EMU,2," STARTF (BUS is %06o)\n", m_bus));
/* TODO: what do we do here? reset the CPU on bit 0? */
if (X_BIT(m_bus,16,0)) {
LOG((LOG_EMU,2,"**** Software boot feature\n"));
soft_reset();
} else {
LOG((LOG_EMU,2,"**** Ethernet start function\n"));
eth_startf();
}
}
/**
* @brief branch on odd bus
*/
void alto2_cpu_device::f2_late_busodd()
{
UINT16 r = m_bus & 1;
LOG((LOG_EMU,2," BUSODD; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r));
m_next2 |= r;
}
/**
* @brief f2_magic late: shift and use T[0] or T[15] for bit 15 or 0
*/
void alto2_cpu_device::f2_late_magic()
{
int XC;
switch (m_d_f1) {
case f1_l_lsh_1: // <-L MLSH 1
XC = (m_t >> 15) & 1;
m_shifter = (m_l << 1) | XC;
LOG((LOG_EMU,2," <-L MLSH 1 (shifer:%06o XC:%o)", m_shifter, XC));
break;
case f1_l_rsh_1: // <-L MRSH 1
XC = (m_t & 1) << 15;
m_shifter = (m_l >> 1) | XC;
LOG((LOG_EMU,2," <-L MRSH 1 (shifter:%06o XC:%o)", m_shifter, XC));
break;
case f1_l_lcy_8: // <-L LCY 8
m_shifter = (m_l >> 8) | (m_l << 8);
break;
default: // other
m_shifter = m_l;
break;
}
}
/**
* @brief do novel shifts: modify RESELECT with DstAC = (3 - IR[3-4])
*/
void alto2_cpu_device::f2_early_load_dns()
{
X_WRBITS(m_rsel, 5, 3, 4, IR_DstAC(m_emu.ir) ^ 3);
LOG((LOG_EMU,2," DNS<-; rsel := DstAC (%#o %s)\n", m_rsel, r_name(m_rsel)));
}
/**
* @brief do novel shifts
*
* <PRE>
* New emulator carry is selected by instruction register
* bits CY = IR[10-11]. R register and emulator carry are
* loaded only if NL = IR[12] is 0 (NL = no load).
* SKIP is set according to SK = IR[13-15].
*
* CARRY = !m_emu.cy
* exorB = IR11 ^ IR10
* ORA = !(exorB | CARRY)
* = (exorB | CARRY) ^ 1
* exorC = ORA ^ !IR11
* = ORA ^ IR11 ^ 1
* exorD = exorC ^ LALUC0
* XC = !(!(DNS & exorD) & !(MAGIC & OUTza))
* = (DNS & exorD) | (MAGIC & OUTza)
* = exorD, because this is DNS
* NEWCARRY = [XC, L(00), L(15), XC] for F1 = no shift, <-L RSH 1, <-L LSH 1, LCY 8
* SHZERO = shifter == 0
* DCARRY = !((!IR12 & NEWCARRY) | (IR12 & CARRY))
* = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1
* DSKIP = !((!NEWCARRY & IR14) | (SHZERO & IR13)) ^ !IR15
* = ((((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ 1) ^ (IR15 ^ 1)
* = (((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ IR15
* </PRE>
*/
void alto2_cpu_device::f2_late_load_dns()
{
UINT8 IR10 = X_BIT(m_emu.ir,16,10);
UINT8 IR11 = X_BIT(m_emu.ir,16,11);
UINT8 IR12 = X_BIT(m_emu.ir,16,12);
UINT8 IR13 = X_BIT(m_emu.ir,16,13);
UINT8 IR14 = X_BIT(m_emu.ir,16,14);
UINT8 IR15 = X_BIT(m_emu.ir,16,15);
UINT8 exorB = IR11 ^ IR10;
UINT8 CARRY = m_emu.cy ^ 1;
UINT8 ORA = (exorB | CARRY) ^ 1;
UINT8 exorC = ORA ^ (IR11 ^ 1);
UINT8 exorD = exorC ^ m_laluc0;
UINT8 XC = exorD;
UINT8 NEWCARRY;
UINT8 DCARRY;
UINT8 DSKIP;
UINT8 SHZERO;
switch (m_d_f1) {
case f1_l_rsh_1: // <-L RSH 1
NEWCARRY = m_l & 1;
m_shifter = ((m_l >> 1) | (XC << 15)) & 0177777;
LOG((LOG_EMU,2," DNS; <-L RSH 1 (shifter:%06o XC:%o NEWCARRY:%o)", m_shifter, XC, NEWCARRY));
break;
case f1_l_lsh_1: // <-L LSH 1
NEWCARRY = (m_l >> 15) & 1;
m_shifter = ((m_l << 1) | XC) & 0177777;
LOG((LOG_EMU,2," DNS; <-L LSH 1 (shifter:%06o XC:%o NEWCARRY:%o)", m_shifter, XC, NEWCARRY));
break;
case f1_l_lcy_8: // <-L LCY 8
NEWCARRY = XC;
m_shifter = (m_l >> 8) | (m_l << 8);
LOG((LOG_EMU,2," DNS; (shifter:%06o NEWCARRY:%o)", m_shifter, NEWCARRY));
break;
default: // other
NEWCARRY = XC;
m_shifter = m_l;
LOG((LOG_EMU,2," DNS; (shifter:%06o NEWCARRY:%o)", m_shifter, NEWCARRY));
break;
}
SHZERO = (m_shifter == 0);
DCARRY = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1;
DSKIP = (((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ IR15;
m_emu.cy = DCARRY; // DCARRY is latched as new m_emu.cy
m_emu.skip = DSKIP; // DSKIP is latched as new m_emu.skip
/* !(IR12 & DNS) -> WR' = 0 for the register file */
if (!IR12) {
m_r[m_rsel] = m_shifter;
}
}
/**
* @brief destiantion accu: modify RSELECT with DstAC = (3 - IR[3-4])
*/
void alto2_cpu_device::f2_early_acdest()
{
X_WRBITS(m_rsel, 5, 3, 4, IR_DstAC(m_emu.ir) ^ 3);
LOG((LOG_EMU,2," ACDEST<-; mux (rsel:%#o %s)\n", m_rsel, r_name(m_rsel)));
}
#if ALTO2_DEBUG
void alto2_cpu_device::bitblt_info()
{
static const char *type_name[4] = {"bitmap","complement","and gray","gray"};
static const char *oper_name[4] = {"replace","paint","invert","erase"};
int bbt = m_r[rsel_ac2];
int val = debug_read_mem(bbt);
LOG((LOG_EMU,3," BITBLT AC1:%06o AC2:%06o\n", m_r[rsel_ac1], m_r[rsel_ac2]));
LOG((LOG_EMU,3," function : %06o\n", val));
LOG((LOG_EMU,3," src extRAM: %o\n", X_BIT(val,16,10)));
LOG((LOG_EMU,3," dst extRAM: %o\n", X_BIT(val,16,11)));
LOG((LOG_EMU,3," src type : %o (%s)\n", X_RDBITS(val,16,12,13), type_name[X_RDBITS(val,16,12,13)]));
LOG((LOG_EMU,3," operation : %o (%s)\n", X_RDBITS(val,16,14,15), oper_name[X_RDBITS(val,16,14,15)]));
val = debug_read_mem(bbt+1);
LOG((LOG_EMU,3," unused AC2: %06o (%d)\n", val, val));
val = debug_read_mem(bbt+2);
LOG((LOG_EMU,3," DBCA : %06o (%d)\n", val, val));
val = debug_read_mem(bbt+3);
LOG((LOG_EMU,3," DBMR : %06o (%d words)\n", val, val));
val = debug_read_mem(bbt+4);
LOG((LOG_EMU,3," DLX : %06o (%d bits)\n", val, val));
val = debug_read_mem(bbt+5);
LOG((LOG_EMU,3," DTY : %06o (%d scanlines)\n", val, val));
val = debug_read_mem(bbt+6);
LOG((LOG_EMU,3," DW : %06o (%d bits)\n", val, val));
val = debug_read_mem(bbt+7);
LOG((LOG_EMU,3," DH : %06o (%d scanlines)\n", val, val));
val = debug_read_mem(bbt+8);
LOG((LOG_EMU,3," SBCA : %06o (%d)\n", val, val));
val = debug_read_mem(bbt+9);
LOG((LOG_EMU,3," SBMR : %06o (%d words)\n", val, val));
val = debug_read_mem(bbt+10);
LOG((LOG_EMU,3," SLX : %06o (%d bits)\n", val, val));
val = debug_read_mem(bbt+11);
LOG((LOG_EMU,3," STY : %06o (%d scanlines)\n", val, val));
LOG((LOG_EMU,3," GRAY0-3 : %06o %06o %06o %06o\n",
debug_read_mem(bbt+12), debug_read_mem(bbt+13),
debug_read_mem(bbt+14), debug_read_mem(bbt+15)));
}
#endif /* DEBUG */
/**
* @brief load instruction register IR and branch on IR[0,5-7]
*
* Loading the IR clears the skip latch.
*/
void alto2_cpu_device::f2_late_load_ir()
{
UINT16 r = (X_BIT(m_bus,16,0) << 3) | X_RDBITS(m_bus,16,5,7);
#if ALTO2_DEBUG
/* special logging of some opcodes */
switch (m_bus) {
case op_CYCLE:
LOG((LOG_EMU,3," CYCLE AC0:#o\n", m_r[rsel_ac0]));
break;
case op_CYCLE + 1: case op_CYCLE + 2: case op_CYCLE + 3: case op_CYCLE + 4:
case op_CYCLE + 5: case op_CYCLE + 6: case op_CYCLE + 7: case op_CYCLE + 8:
case op_CYCLE + 9: case op_CYCLE +10: case op_CYCLE +11: case op_CYCLE +12:
case op_CYCLE +13: case op_CYCLE +14: case op_CYCLE +15:
LOG((LOG_EMU,3," CYCLE %#o\n", m_bus - op_CYCLE));
break;
case op_BLT:
LOG((LOG_EMU,3," BLT dst:%#o src:%#o size:%#o\n",
(m_r[rsel_ac1] + m_r[rsel_ac3] + 1) & 0177777,
(m_r[rsel_ac0] + 1) & 017777, -m_r[rsel_ac3] & 0177777));
break;
case op_BLKS:
LOG((LOG_EMU,3," BLKS dst:%#o val:%#o size:%#o\n",
(m_r[rsel_ac1] + m_r[rsel_ac3] + 1) & 0177777,
m_r[rsel_ac0], -m_r[rsel_ac3] & 0177777));
break;
case op_DIAGNOSE1:
LOG((LOG_EMU,3," DIAGNOSE1 AC0:%06o AC1:%06o AC2:%06o AC3:%06o\n",
m_r[rsel_ac0], m_r[rsel_ac1],
m_r[rsel_ac2], m_r[rsel_ac3]));
break;
case op_DIAGNOSE2:
LOG((LOG_EMU,3," DIAGNOSE2 AC0:%06o AC1:%06o AC2:%06o AC3:%06o\n",
m_r[rsel_ac0], m_r[rsel_ac1],
m_r[rsel_ac2], m_r[rsel_ac3]));
break;
case op_BITBLT:
bitblt_info();
break;
case op_RDRAM:
LOG((LOG_EMU,3," RDRAM addr:%#o\n", m_r[rsel_ac1]));
break;
case op_WRTRAM:
LOG((LOG_EMU,3," WRTAM addr:%#o upper:%06o lower:%06o\n", m_r[rsel_ac1], m_r[rsel_ac0], m_r[rsel_ac3]));
break;
case op_JMPRAM:
LOG((LOG_EMU,3," JMPRAM addr:%#o\n", m_r[rsel_ac1]));
break;
case op_XMLDA:
LOG((LOG_EMU,3," XMLDA AC0 = [bank:%o AC1:#o]\n", m_bank_reg[m_task] & 3, m_r[rsel_ac1]));
break;
case op_XMSTA:
LOG((LOG_EMU,3," XMSTA [bank:%o AC1:#o] = AC0 (%#o)\n", m_bank_reg[m_task] & 3, m_r[rsel_ac1], m_r[rsel_ac0]));
break;
}
#endif
m_emu.ir = m_bus;
m_emu.skip = 0;
m_next2 |= r;
}
/**
* @brief branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]]
*/
void alto2_cpu_device::f2_late_idisp()
{
UINT16 r;
if (IR_ARITH(m_emu.ir)) {
/* 1xxxxxxxxxxxxxxx */
r = IR_SH(m_emu.ir) ^ 3; /* complement of SH */
LOG((LOG_EMU,2," IDISP<-; branch on SH^3 (%#o|%#o)\n", m_next2, r));
} else {
int addr = CTL2K_U3(f2_emu_idisp) + X_RDBITS(m_emu.ir,16,1,7);
/* 0???????xxxxxxxx */
r = m_ctl2k_u3[addr];
LOG((LOG_EMU,2," IDISP<-; IR (%#o) branch on PROM ctl2k_u3[%03o] (%#o|%#o)\n", m_emu.ir, addr, m_next2, r));
}
m_next2 |= r;
}
/**
* @brief source accu: modify RSELECT with SrcAC = (3 - IR[1-2])
*/
void alto2_cpu_device::f2_early_acsource()
{
X_WRBITS(m_rsel, 5, 3, 4, IR_SrcAC(m_emu.ir) ^ 3);
LOG((LOG_EMU,2," <-ACSOURCE; rsel := SrcAC (%#o %s)\n", m_rsel, r_name(m_rsel)));
}
/**
* @brief branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]]
*/
void alto2_cpu_device::f2_late_acsource()
{
UINT16 r;
if (IR_ARITH(m_emu.ir)) {
/* 1xxxxxxxxxxxxxxx */
r = IR_SH(m_emu.ir) ^ 3; /* complement of SH */
LOG((LOG_EMU,2," <-ACSOURCE; branch on SH^3 (%#o|%#o)\n", m_next2, r));
} else {
int addr = CTL2K_U3(f2_emu_acsource) + X_RDBITS(m_emu.ir,16,1,7);
/* 0???????xxxxxxxx */
r = m_ctl2k_u3[addr];
LOG((LOG_EMU,2," <-ACSOURCE; branch on PROM ctl2k_u3[%03o] (%#o|%#o)\n", addr, m_next2, r));
}
m_next2 |= r;
}
void alto2_cpu_device::init_emu(int task)
{
memset(&m_emu, 0, sizeof(m_emu));
save_item(NAME(m_emu.ir));
save_item(NAME(m_emu.skip));
save_item(NAME(m_emu.cy));
init_ram(task);
set_bs(task, bs_emu_read_sreg, &alto2_cpu_device::bs_early_read_sreg, 0);
set_bs(task, bs_emu_load_sreg, &alto2_cpu_device::bs_early_load_sreg, &alto2_cpu_device::bs_late_load_sreg);
set_bs(task, bs_disp, &alto2_cpu_device::bs_early_emu_disp, 0);
set_f1(task, f1_block, &alto2_cpu_device::f1_early_emu_block, 0); // catch the emulator task trying to block (wrong branch)
set_f1(task, f1_emu_swmode, 0, &alto2_cpu_device::f1_late_swmode);
set_f1(task, f1_emu_wrtram, 0, &alto2_cpu_device::f1_late_wrtram);
set_f1(task, f1_emu_rdram, 0, &alto2_cpu_device::f1_late_rdram);
set_f1(task, f1_emu_load_rmr, 0, &alto2_cpu_device::f1_late_emu_load_rmr);
set_f1(task, f1_task_14, 0, 0); // F1 014 is undefined (?)
set_f1(task, f1_emu_load_esrb, 0, &alto2_cpu_device::f1_late_emu_load_esrb);
set_f1(task, f1_emu_rsnf, &alto2_cpu_device::f1_early_rsnf, 0);
set_f1(task, f1_emu_startf, &alto2_cpu_device::f1_early_startf, 0);
set_f2(task, f2_emu_busodd, 0, &alto2_cpu_device::f2_late_busodd);
set_f2(task, f2_emu_magic, 0, &alto2_cpu_device::f2_late_magic);
set_f2(task, f2_emu_load_dns, &alto2_cpu_device::f2_early_load_dns, &alto2_cpu_device::f2_late_load_dns);
set_f2(task, f2_emu_acdest, &alto2_cpu_device::f2_early_acdest, 0);
set_f2(task, f2_emu_load_ir, 0, &alto2_cpu_device::f2_late_load_ir);
set_f2(task, f2_emu_idisp, 0, &alto2_cpu_device::f2_late_idisp);
set_f2(task, f2_emu_acsource, &alto2_cpu_device::f2_early_acsource, &alto2_cpu_device::f2_late_acsource);
}
void alto2_cpu_device::exit_emu()
{
// nothing to do yet
}
void alto2_cpu_device::reset_emu()
{
m_emu.ir = 0;
m_emu.skip = 0;
m_emu.cy = 0;
}

71
src/emu/cpu/alto2/a2emu.h Normal file
View File

@ -0,0 +1,71 @@
/*****************************************************************************
*
* Xerox AltoII emulator task (EMU)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2EMU_H_
#define _A2EMU_H_
//! BUS source for emulator task
enum {
bs_emu_read_sreg = bs_task_3, //!< bus source: read S register
bs_emu_load_sreg = bs_task_4 //!< bus source: load S register from BUS
};
//! F1 functions for emulator task
enum {
f1_emu_swmode = f1_task_10, //!< f1 (1000): switch mode; branch to ROM/RAM microcode
f1_emu_wrtram = f1_task_11, //!< f1 (1001): write microcode RAM cycle
f1_emu_rdram = f1_task_12, //!< f1 (1010): read microcode RAM cycle
f1_emu_load_rmr = f1_task_13, //!< f1 (1011): load reset mode register
//!< f1 (1100): undefined
f1_emu_load_esrb = f1_task_15, //!< f1 (1101): load extended S register bank
f1_emu_rsnf = f1_task_16, //!< f1 (1110): read serial number (Ethernet ID)
f1_emu_startf = f1_task_17 //!< f1 (1111): start I/O hardware (Ethernet)
};
//! F2 functions for emulator task
enum {
f2_emu_busodd = f2_task_10, //!< f2 (1000): branch on bus odd
f2_emu_magic = f2_task_11, //!< f2 (1001): magic shifter (MRSH 1: shifter[15]=T[0], MLSH 1: shifter[015])
f2_emu_load_dns = f2_task_12, //!< f2 (1010): do novel shift (RSH 1: shifter[15]=XC, LSH 1: shifer[0]=XC)
f2_emu_acdest = f2_task_13, //!< f2 (1011): destination accu
f2_emu_load_ir = f2_task_14, //!< f2 (1100): load instruction register and branch
f2_emu_idisp = f2_task_15, //!< f2 (1101): load instruction displacement and branch
f2_emu_acsource = f2_task_16 //!< f2 (1110): source accu
//!< f2 (1111): undefined
};
struct {
UINT16 ir; //!< emulator instruction register
UINT8 skip; //!< emulator skip
UINT8 cy; //!< emulator carry
} m_emu;
void bs_early_emu_disp(); //!< bus source: drive bus by IR[8-15], possibly sign extended
void f1_early_emu_block(); //!< F1 func: block task
void f1_late_emu_load_rmr(); //!< F1 func: load the reset mode register
void f1_late_emu_load_esrb(); //!< F1 func: load the extended S register bank from BUS[12-14]
void f1_early_rsnf(); //!< F1 func: drive the bus from the Ethernet node ID
void f1_early_startf(); //!< F1 func: defines commands for for I/O hardware, including Ethernet
void f2_late_busodd(); //!< F2 func: branch on odd bus
void f2_late_magic(); //!< F2 func: shift and use T
void f2_early_load_dns(); //!< F2 func: modify RESELECT with DstAC = (3 - IR[3-4])
void f2_late_load_dns(); //!< F2 func: do novel shifts
void f2_early_acdest(); //!< F2 func: modify RSELECT with DstAC = (3 - IR[3-4])
void bitblt_info(); //!< debug bitblt opcode
void f2_late_load_ir(); //!< F2 func: load instruction register IR and branch on IR[0,5-7]
void f2_late_idisp(); //!< F2 func: branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]]
void f2_early_acsource(); //!< F2 func: modify RSELECT with SrcAC = (3 - IR[1-2])
void f2_late_acsource(); //!< F2 func: branch on arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]]
void init_emu(int task = task_emu); //!< initialize the emulator task
void exit_emu(); //!< deinitialize the emulator task
void reset_emu(); //!< reset the emulator task
#endif // _A2EMU_H_
#endif // ALTO2_DEFINE_CONSTANTS

1382
src/emu/cpu/alto2/a2ether.c Normal file

File diff suppressed because it is too large Load Diff

118
src/emu/cpu/alto2/a2ether.h Normal file
View File

@ -0,0 +1,118 @@
/*****************************************************************************
*
* Xerox AltoII ethernet task (ETHER)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#define ALTO2_ETHER_FIFO_SIZE 16 //!< number of words in the ethernet FIFO
#define ALTO2_ETHER_PACKET_SIZE 0400 //!< size of a packet in words
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2ETHER_H_
#define _A2ETHER_H_
//! BUS source for ethernet task
enum {
bs_ether_eidfct = bs_task_3 //!< ethernet task: Ethernet input data function
};
//! F1 functions for ethernet task
enum {
f1_ether_eilfct = f1_task_13, //!< f1 (1011): ethernet input look function
f1_ether_epfct = f1_task_14, //!< f1 (1100): ethernet post function
f1_ether_ewfct = f1_task_15 //!< f1 (1101): ethernet countdown wakeup function
};
//! F2 functions for ethernet task
enum {
f2_ether_eodfct = f2_task_10, //!< f2 (1000): ethernet output data function
f2_ether_eosfct = f2_task_11, //!< f2 (1001): ethernet output start function
f2_ether_erbfct = f2_task_12, //!< f2 (1010): ethernet reset branch function
f2_ether_eefct = f2_task_13, //!< f2 (1011): ethernet end of transmission function
f2_ether_ebfct = f2_task_14, //!< f2 (1100): ethernet branch function
f2_ether_ecbfct = f2_task_15, //!< f2 (1101): ethernet countdown branch function
f2_ether_eisfct = f2_task_16 //!< f2 (1110): ethernet input start function
//!< f2 (1111): undefined
};
UINT8* m_ether_a41; //!< BPROM; P3601-1; 256x4; enet.a41 "PE1"
UINT8* m_ether_a42; //!< BPROM; P3601-1; 256x4; enet.a42 "PE2"
UINT8* m_ether_a49; //!< BPROM; P3601-1; 265x4 enet.a49 "AFIFO"
enum {
ether_a49_BE = (1 << 0), //!< buffer empty
ether_a49_BNE = (1 << 1), //!< buffer next empty
ether_a49_BNNE = (1 << 2), //!< buffer next next empty
ether_a49_BF = (1 << 3) //!< buffer full
};
struct {
UINT32 serin; //!< serial input shift registers 74164 #37 and #33
UINT16 fifo[ALTO2_ETHER_FIFO_SIZE]; //!< FIFO buffer
UINT16 fifo_rd; //!< FIFO input pointer
UINT16 fifo_wr; //!< FIFO output pointer
UINT16 status; //!< status word
UINT16 rx_crc; //!< receiver CRC
UINT16 tx_crc; //!< transmitter CRC
UINT32 rx_count; //!< received words count
UINT32 tx_count; //!< transmitted words count
UINT16* rx_packet; //!< buffer to collect received words
UINT16* tx_packet; //!< buffer to collect transmitted words
emu_timer* rx_timer; //!< receiver timer
emu_timer* tx_timer; //!< transmitter timer
jkff_t ff_10a; //!< JK flip-flop 10a IBUSY (Sheet 13)
jkff_t ff_10b; //!< JK flip-flop 10b OBUSY (Sheet 13)
jkff_t ff_21a; //!< JK flip-flop 21a OUTON (Sheet 19)
jkff_t ff_21b; //!< JK flip-flop 21b COLL (Sheet 19)
jkff_t ff_31a; //!< JK flip-flop 31a OUTGONE (Sheet 19)
jkff_t ff_31b; //!< JK flip-flop 31b OEOT (Sheet 19)
jkff_t ff_35a; //!< JK flip-flop 35a OCMD (Sheet 7)
jkff_t ff_35b; //!< JK flip-flop 35b ICMD (Sheet 7)
jkff_t ff_47a; //!< JK flip-flop 47a ISR14 (Sheet 15)
jkff_t ff_47b; //!< JK flip-flop 47b ISR15 (Sheet 15)
jkff_t ff_51a; //!< JK flip-flop 51a EWFCT latch (Sheet 19)
jkff_t ff_51b; //!< JK flip-flop 51b OCDW (Sheet 19)
jkff_t ff_52b; //!< JK flip-flop 52b OSLOAD (Sheet 17)
jkff_t ff_61a; //!< JK flip-flop 61a CRCGO (Sheet 21)
jkff_t ff_61b; //!< JK flip-flop 61b OUTRGO (Sheet 21)
jkff_t ff_62a; //!< JK flip-flop 62a OUTON (Sheet 21)
jkff_t ff_62b; //!< JK flip-flop 62b OUTGO (Sheet 21)
jkff_t ff_65a; //!< JK flip-flop 65a IDL (Sheet 10)
jkff_t ff_65b; //!< JK flip-flop 65b IO (Sheet 10)
jkff_t ff_69a; //!< JK flip-flop 69a IT (Sheet 14)
jkff_t ff_69b; //!< JK flip-flop 69b INON (Sheet 14)
jkff_t ff_70a; //!< JK flip-flop 70a IMID (Sheet 14)
jkff_t ff_70b; //!< JK flip-flop 70b ILOC (Sheet 14)
jkff_t ff_77a; //!< JK flip-flop 77a WR (Sheet 10)
jkff_t ff_77b; //!< JK flip-flop 77b WLF (Sheet 10)
int breath_of_life; //!< if non-zero, interval in seconds at which to broadcast the breath-of-life
} m_eth;
TIMER_CALLBACK_MEMBER( rx_breath_of_life ); //!< HACK: pull the next word from the breath-of-life in the fifo
TIMER_CALLBACK_MEMBER( tx_packet ); //!< transmit data from the FIFO to <nirvana for now>
void eth_wakeup(); //!< check for the various reasons to wakeup the Ethernet task
void eth_startf(); //!< start input or output depending on m_bus
void bs_early_eidfct(); //!< bus source: Ethernet input data function
void f1_early_eth_block(); //!< F1 func: block the Ether task
void f1_early_eilfct(); //!< F1 func: Ethernet input look function
void f1_early_epfct(); //!< F1 func: Ethernet post function
void f1_late_ewfct(); //!< F1 func: Ethernet countdown wakeup function
void f2_late_eodfct(); //!< F2 func: Ethernet output data function
void f2_late_eosfct(); //!< F2 func: Ethernet output start function
void f2_late_erbfct(); //!< F2 func: Ethernet reset branch function
void f2_late_eefct(); //!< F2 func: Ethernet end of transmission function
void f2_late_ebfct(); //!< F2 func: Ethernet branch function
void f2_late_ecbfct(); //!< F2 func: Ethernet countdown branch function
void f2_late_eisfct(); //!< F2 func: Ethernet input start function
void activate_eth(); //!< called by the CPU when the Ethernet task becomes active
void update_sysclk(int sysclk); //!< update all JK flip-flops for one cycle of SYSCLK
void update_rclk(int rclk); //!< update all JK flip-flops for one cycle of RCLK
void update_tclk(int tclk); //!< update all JK flip-flops for one cycle of TCLK
void init_ether(int task = task_ether); //!< initialize the ethernet task
void exit_ether(); //!< deinitialize the ethernet task
void reset_ether(); //!< reset the ethernet task
#endif // _A2ETHER_H_
#endif // ALTO2_DEFINE_CONSTANTS

424
src/emu/cpu/alto2/a2hw.c Normal file
View File

@ -0,0 +1,424 @@
/*****************************************************************************
*
* Xerox AltoII memory mapped I/O hardware
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
#include "a2roms.h"
/**
* @brief read printer paper ready bit
* Paper ready bit. 0 when the printer is ready for a paper scrolling operation.
*/
READ16_MEMBER ( alto2_cpu_device::pprdy_r ) { return X_RDBITS(m_hw.utilin,16,0,0); }
/**
* @brief read printer check bit
* Printer check bit bit.
* Should the printer find itself in an abnormal state, it sets this bit to 0
*/
READ16_MEMBER ( alto2_cpu_device::pcheck_r ) { return X_RDBITS(m_hw.utilin,16,1,1); }
/**
* @brief read unused bit 2
*/
READ16_MEMBER ( alto2_cpu_device::unused2_r ) { return X_RDBITS(m_hw.utilin,16,2,2); }
/**
* @brief read printer daisy ready bit
* Daisy ready bit. 0 when the printer is ready to print a character.
*/
READ16_MEMBER ( alto2_cpu_device::pchrdy_r ) { return X_RDBITS(m_hw.utilin,16,3,3); }
/**
* @brief read printer carriage ready bit
* Carriage ready bit. 0 when the printer is ready for horizontal positioning.
*/
READ16_MEMBER ( alto2_cpu_device::parrdy_r ) { return X_RDBITS(m_hw.utilin,16,4,4); }
/**
* @brief read printer ready bit
* Ready bit. Both this bit and the appropriate other ready bit (carriage,
* daisy, etc.) must be 0 before attempting any output operation.
*/
READ16_MEMBER ( alto2_cpu_device::pready_r ) { return X_RDBITS(m_hw.utilin,16,5,5); }
/**
* @brief memory configuration switch
*/
READ16_MEMBER ( alto2_cpu_device::memconfig_r ) { return X_RDBITS(m_hw.utilin,16,6,6); }
/**
* @brief get unused bit 7
*/
READ16_MEMBER ( alto2_cpu_device::unused7_r ) { return X_RDBITS(m_hw.utilin,16,7,7); }
/**
* @brief get key set key 0
*/
READ16_MEMBER ( alto2_cpu_device::keyset_key0_r ) { return X_RDBITS(m_hw.utilin,16,8,8); }
/**
* @brief get key set key 1
*/
READ16_MEMBER ( alto2_cpu_device::keyset_key1_r ) { return X_RDBITS(m_hw.utilin,16,9,9); }
/**
* @brief get key set key 2
*/
READ16_MEMBER ( alto2_cpu_device::keyset_key2_r ) { return X_RDBITS(m_hw.utilin,16,10,10); }
/**
* @brief get key set key 3
*/
READ16_MEMBER ( alto2_cpu_device::keyset_key3_r ) { return X_RDBITS(m_hw.utilin,16,11,11); }
/**
* @brief get key set key 4
*/
READ16_MEMBER ( alto2_cpu_device::keyset_key4_r ) { return X_RDBITS(m_hw.utilin,16,12,12); }
/**
* @brief get mouse red button bit
*/
READ16_MEMBER ( alto2_cpu_device::mouse_red_r ) { return X_RDBITS(m_hw.utilin,16,13,13); }
/**
* @brief get mouse blue button bit
*/
READ16_MEMBER ( alto2_cpu_device::mouse_blue_r ) { return X_RDBITS(m_hw.utilin,16,14,14); }
/**
* @brief get mouse yellow button bit
*/
READ16_MEMBER ( alto2_cpu_device::mouse_yellow_r ) { return X_RDBITS(m_hw.utilin,16,15,15); }
/**
* @brief write printer paper ready bit
*/
WRITE16_MEMBER( alto2_cpu_device::pprdy_w ) { X_WRBITS(m_hw.utilin,16,0,0,data); }
/**
* @brief write printer check bit
*/
WRITE16_MEMBER( alto2_cpu_device::pcheck_w ) { X_WRBITS(m_hw.utilin,16,1,1,data); }
/**
* @brief read unused bit 2
*/
WRITE16_MEMBER( alto2_cpu_device::unused2_w ) { X_WRBITS(m_hw.utilin,16,2,2,data); }
/**
* @brief write printer daisy ready bit
*/
WRITE16_MEMBER( alto2_cpu_device::pchrdy_w ) { X_WRBITS(m_hw.utilin,16,3,3,data); }
/**
* @brief write printer carriage ready bit
*/
WRITE16_MEMBER( alto2_cpu_device::parrdy_w ) { X_WRBITS(m_hw.utilin,16,4,4,data); }
/**
* @brief write printer ready bit
*/
WRITE16_MEMBER( alto2_cpu_device::pready_w ) { X_WRBITS(m_hw.utilin,16,5,5,data); }
/**
* @brief write memory configuration switch
*/
WRITE16_MEMBER( alto2_cpu_device::memconfig_w ) { X_WRBITS(m_hw.utilin,16,6,6,data); }
/**
* @brief write unused bit 7
*/
WRITE16_MEMBER( alto2_cpu_device::unused7_w ) { X_WRBITS(m_hw.utilin,16,7,7,data); }
/**
* @brief write key set key 0
*/
WRITE16_MEMBER( alto2_cpu_device::keyset_key0_w ) { X_WRBITS(m_hw.utilin,16,8,8,data); }
/**
* @brief write key set key 1
*/
WRITE16_MEMBER( alto2_cpu_device::keyset_key1_w ) { X_WRBITS(m_hw.utilin,16,9,9,data); }
/**
* @brief write key set key 2
*/
WRITE16_MEMBER( alto2_cpu_device::keyset_key2_w ) { X_WRBITS(m_hw.utilin,16,10,10,data); }
/**
* @brief write key set key 3
*/
WRITE16_MEMBER( alto2_cpu_device::keyset_key3_w ) { X_WRBITS(m_hw.utilin,16,11,11,data); }
/**
* @brief write key set key 4
*/
WRITE16_MEMBER( alto2_cpu_device::keyset_key4_w ) { X_WRBITS(m_hw.utilin,16,12,12,data); }
/**
* @brief write mouse red button bit
*/
WRITE16_MEMBER( alto2_cpu_device::mouse_red_w ) { X_WRBITS(m_hw.utilin,16,13,13,data); }
/**
* @brief write mouse blue button bit
*/
WRITE16_MEMBER( alto2_cpu_device::mouse_blue_w ) { X_WRBITS(m_hw.utilin,16,14,14,data); }
/**
* @brief write mouse yellow button bit
*/
WRITE16_MEMBER( alto2_cpu_device::mouse_yellow_w ) { X_WRBITS(m_hw.utilin,16,15,15,data); }
/**
* @brief write mouse buttons bits
*/
WRITE16_MEMBER( alto2_cpu_device::mouse_buttons_w ) { X_WRBITS(m_hw.utilin,16,13,15,data); }
/**
* @brief printer paper strobe bit
* Paper strobe bit. Toggling this bit causes a paper scrolling operation.
*/
static inline UINT16 GET_PPPSTR(UINT16 utilout) { return X_RDBITS(utilout,16,0,0); }
/**
* @brief printer retstore bit
* Restore bit. Toggling this bit resets the printer (including clearing
* the "check" condition if present) and moves the carriage to the
* left margin.
*/
static inline UINT16 GET_PREST(UINT16 utilout) { return X_RDBITS(utilout,16,1,1); }
/**
* @brief printer ribbon bit
* Ribbon bit. When this bit is 1 the ribbon is up (in printing
* position); when 0, it is down.
*/
static inline UINT16 GET_PRIB(UINT16 utilout) { return X_RDBITS(utilout,16,2,2); }
/**
* @brief printer daisy strobe bit
* Daisy strobe bit. Toggling this bit causes a character to be printed.
*/
static inline UINT16 GET_PCHSTR(UINT16 utilout) { return X_RDBITS(utilout,16,3,3); }
/**
* @brief printer carriage strobe bit
* Carriage strobe bit. Toggling this bit causes a horizontal position operation.
*/
static inline UINT16 GET_PCARSTR(UINT16 utilout) { return X_RDBITS(utilout,16,4,4); }
/**
* @brief printer data
* Argument to various output operations:
* 1. Printing characters. When the daisy bit is toggled bits 9-15 of this field
* are interpreted as an ASCII character code to be printed (it should be noted
* that all codes less than 040 print as lower case "w").
* 2. For paper and carriage operations the field is interpreted as a displacement
* (-1024 to +1023), in units of 1/48 inch for paper and 1/60 inch for carriage.
* Positive is down or to the right, negative up or to the left. The value is
* represented as sign-magnitude (i.e., bit 5 is 1 for negative numbers, 0 for
* positive; bits 6-15 are the absolute value of the number).
*/
static inline UINT16 GET_PDATA(UINT16 utilout) { return X_RDBITS(utilout,16,5,15); }
/**
* @brief read the UTILIN port
*
* @param addr memory mapped I/O address to be read
* @return current value on the UTILIN port
*/
READ16_MEMBER( alto2_cpu_device::utilin_r )
{
UINT16 data;
// FIXME: update the printer status
// printer_read();
data = m_hw.utilin;
if (!space.debugger_access()) {
LOG((LOG_HW,2," UTILIN rd %#o (%#o)\n", offset, data));
}
return data;
}
/**
* @brief read the XBUS port
*
* @param addr memory mapped I/O address to be read
* @return current value on the XBUS port latch
*/
READ16_MEMBER( alto2_cpu_device::xbus_r )
{
UINT16 data = m_hw.xbus[offset & 3];
if (!space.debugger_access()) {
LOG((LOG_HW,2," XBUS[%d] rd %#o (%#o)\n", offset & 3, offset, data));
}
return data;
}
/**
* @brief write the XBUS port
*
* The actual outputs are active-low.
*
* @param addr memory mapped I/O address to be read
* @param data value to write to the XBUS port latch
*/
WRITE16_MEMBER( alto2_cpu_device::xbus_w )
{
if (!space.debugger_access()) {
LOG((LOG_HW,2," XBUS[%d] wr %#o (%#o)\n", offset & 3, offset, data));
}
m_hw.xbus[offset&3] = data;
}
/**
* @brief read the UTILOUT port
*
* @param addr memory mapped I/O address to be read
* @return current value on the UTILOUT port latch
*/
READ16_MEMBER( alto2_cpu_device::utilout_r )
{
UINT16 data = m_hw.utilout ^ 0177777;
if (!space.debugger_access()) {
LOG((0,2," UTILOUT rd %#o (%#o)\n", offset, data));
}
return data;
}
/**
* @brief write the UTILOUT port
*
* The actual outputs are active-low.
*
* @param addr memory mapped I/O address to be read
* @param data value to write to the UTILOUT port latch
*/
WRITE16_MEMBER( alto2_cpu_device::utilout_w )
{
if (!space.debugger_access()) {
LOG((LOG_HW,2," UTILOUT wr %#o (%#o)\n", offset, data));
}
m_hw.utilout = data ^ 0177777;
// FIXME: write printer data
// printer_write();
}
/**
* <PRE>
* TODO: use madr.a65 and madr.a64 to determine the actual I/O address ranges
*
* madr.a65
* address line connected to
* -------------------------------
* A0 MAR[11]
* A1 KEYSEL
* A2 MAR[7-10] == 0
* A3 MAR[12]
* A4 MAR[13]
* A5 MAR[14]
* A6 MAR[15]
* A7 IOREF (MAR[0-6] == 1)
*
* output data connected to
* -------------------------------
* D0 IOSEL0
* D1 IOSEL1
* D2 IOSEL2
* D3 INTIO
*
* madr.a64
* address line connected to
* -------------------------------
* A0 STORE
* A1 MAR[11]
* A2 MAR[7-10] == 0
* A3 MAR[12]
* A4 MAR[13]
* A5 MAR[14]
* A6 MAR[15]
* A7 IOREF (MAR[0-6] == 1)
*
* output data connected to
* -------------------------------
* D0 & MISYSCLK -> SELP
* D1 ^ INTIO -> INTIOX
* " ^ 1 -> NERRSEL
* " & WRTCLK -> NRSTE
* D2 XREG'
* D3 & MISYSCLK -> LOADERC
* </PRE>
*/
static const prom_load_t pl_madr_a64 =
{
"madr.a64",
0,
"a66b0eda",
"4d9088f592caa3299e90966b17765be74e523144",
/* size */ 0400,
/* amap */ AMAP_DEFAULT,
/* axor */ 0,
/* dxor */ 017, // invert D0-D3
/* width */ 4,
/* shift */ 0,
/* dmap */ DMAP_DEFAULT,
/* dand */ ZERO,
/* type */ sizeof(UINT8)
};
static const prom_load_t pl_madr_a65 =
{
"madr.a65",
0,
"ba37febd",
"82e9db1cb65f451755295f0d179e6f8fe3349d4d",
/* size */ 0400,
/* amap */ AMAP_DEFAULT,
/* axor */ 0,
/* dxor */ 017, // invert D0-D3
/* width */ 4,
/* shift */ 0,
/* dmap */ DMAP_DEFAULT,
/* dand */ ZERO,
/* type */ sizeof(UINT8)
};
/**
* @brief clear all keys and install the mmio handler for KBDAD to KBDAD+3
*/
void alto2_cpu_device::init_hw()
{
memset(&m_hw, 0, sizeof(m_hw));
m_madr_a64 = prom_load(machine(), &pl_madr_a64, memregion("madr_a64")->base());
m_madr_a65 = prom_load(machine(), &pl_madr_a65, memregion("madr_a65")->base());
}
void alto2_cpu_device::exit_hw()
{
// nothing to do yet
}
void alto2_cpu_device::reset_hw()
{
m_hw.eia = 0;
m_hw.utilout = 0;
// open inputs on the XBUS (?)
m_hw.xbus[0] = 0177777;
m_hw.xbus[1] = 0177777;
m_hw.xbus[2] = 0177777;
m_hw.xbus[3] = 0177777;
// open inputs on UTILIN
m_hw.utilin = 0177777;
}

68
src/emu/cpu/alto2/a2hw.h Normal file
View File

@ -0,0 +1,68 @@
/*****************************************************************************
*
* Xerox AltoII memory mapped i/o stuff (HW)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2HW_H_
#define _A2HW_H_
//! miscellaneous hardware registers in the memory mapped I/O range
struct {
UINT16 eia; //!< the EIA port at 0177001
UINT16 utilout; //!< the UTILOUT port at 0177016 (active-low outputs)
UINT16 xbus[4]; //!< the XBUS port at 0177020 to 0177023
UINT16 utilin; //!< the UTILIN port at 0177030 to 0177033 (same value on all addresses)
} m_hw;
DECLARE_READ16_MEMBER ( pprdy_r ); //!< read UTILIN[0] printer paper ready bit
DECLARE_READ16_MEMBER ( pcheck_r ); //!< read UTILIN[1] printer check bit
DECLARE_READ16_MEMBER ( unused2_r ); //!< read UTILIN[2] unused bit
DECLARE_READ16_MEMBER ( pchrdy_r ); //!< read UTILIN[3] printer daisy ready bit
DECLARE_READ16_MEMBER ( parrdy_r ); //!< read UTILIN[4] printer carriage ready bit
DECLARE_READ16_MEMBER ( pready_r ); //!< read UTILIN[5] printer ready bit
DECLARE_READ16_MEMBER ( memconfig_r ); //!< read UTILIN[6] memory config switch
DECLARE_READ16_MEMBER ( unused7_r ); //!< read UTILIN[7] unused bit
DECLARE_READ16_MEMBER ( keyset_key0_r ); //!< read UTILIN[8] keyset key #0
DECLARE_READ16_MEMBER ( keyset_key1_r ); //!< read UTILIN[9] keyset key #1
DECLARE_READ16_MEMBER ( keyset_key2_r ); //!< read UTILIN[10] keyset key #2
DECLARE_READ16_MEMBER ( keyset_key3_r ); //!< read UTILIN[11] keyset key #3
DECLARE_READ16_MEMBER ( keyset_key4_r ); //!< read UTILIN[12] keyset key #4
DECLARE_READ16_MEMBER ( mouse_red_r ); //!< read UTILIN[13] mouse red button bit
DECLARE_READ16_MEMBER ( mouse_blue_r ); //!< read UTILIN[14] mouse blue button bit
DECLARE_READ16_MEMBER ( mouse_yellow_r ); //!< read UTILIN[15] mouse yellow button bit
DECLARE_WRITE16_MEMBER( pprdy_w ); //!< write UTILIN[0] printer paper ready bit
DECLARE_WRITE16_MEMBER( pcheck_w ); //!< write UTILIN[1] printer check bit
DECLARE_WRITE16_MEMBER( unused2_w ); //!< write UTILIN[2] unused bit
DECLARE_WRITE16_MEMBER( pchrdy_w ); //!< write UTILIN[3] printer daisy ready bit
DECLARE_WRITE16_MEMBER( parrdy_w ); //!< write UTILIN[4] carriage ready bit
DECLARE_WRITE16_MEMBER( pready_w ); //!< write UTILIN[5] printer ready bit
DECLARE_WRITE16_MEMBER( memconfig_w ); //!< write UTILIN[6] memory config switch
DECLARE_WRITE16_MEMBER( unused7_w ); //!< write UTILIN[7] unused bit
DECLARE_WRITE16_MEMBER( keyset_key0_w ); //!< write UTILIN[8] keyset key #0
DECLARE_WRITE16_MEMBER( keyset_key1_w ); //!< write UTILIN[9] keyset key #1
DECLARE_WRITE16_MEMBER( keyset_key2_w ); //!< write UTILIN[10] keyset key #2
DECLARE_WRITE16_MEMBER( keyset_key3_w ); //!< write UTILIN[11] keyset key #3
DECLARE_WRITE16_MEMBER( keyset_key4_w ); //!< write UTILIN[12] keyset key #4
DECLARE_WRITE16_MEMBER( mouse_red_w ); //!< write UTILIN[13] mouse red button bit
DECLARE_WRITE16_MEMBER( mouse_blue_w ); //!< write UTILIN[14] mouse blue button bit
DECLARE_WRITE16_MEMBER( mouse_yellow_w ); //!< write UTILIN[15] mouse yellow button bit
DECLARE_WRITE16_MEMBER( mouse_buttons_w ); //!< write UTILIN[13-15] mouse buttons bits
DECLARE_READ16_MEMBER ( utilin_r ); //!< read an UTILIN address
DECLARE_READ16_MEMBER ( utilout_r ); //!< read the UTILOUT address
DECLARE_WRITE16_MEMBER( utilout_w ); //!< write the UTILOUT address
DECLARE_READ16_MEMBER ( xbus_r ); //!< read an XBUS address
DECLARE_WRITE16_MEMBER( xbus_w ); //!< write an XBUS address (?)
void init_hw(); //!< initialize miscellaneous hardware
void exit_hw(); //!< deinitialize miscellaneous hardware
void reset_hw(); //!< reset miscellaneous hardware
#endif // _A2HW_H_
#endif // ALTO2_DEFINE_CONSTANTS

194
src/emu/cpu/alto2/a2jkff.h Normal file
View File

@ -0,0 +1,194 @@
/*****************************************************************************
*
* Xerox AltoII Dual J/K flip-flop 74109 emulation
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#define JKFF_DEBUG 0 //!< define 1 to debug the transitions
/**
* @brief enumeration of the inputs and outputs of a JK flip-flop type 74109
* <PRE>
* 74109
* Dual J-/K flip-flops with set and reset.
*
* +----------+ +-----------------------------+
* /1RST |1 +--+ 16| VCC | J |/K |CLK|/SET|/RST| Q |/Q |
* 1J |2 15| /2RST |---+---+---+----+----+---+---|
* /1K |3 14| 2J | X | X | X | 0 | 0 | 1 | 1 |
* 1CLK |4 74 13| /2K | X | X | X | 0 | 1 | 1 | 0 |
* /1SET |5 109 12| 2CLK | X | X | X | 1 | 0 | 0 | 1 |
* 1Q |6 11| /2SET | 0 | 0 | / | 1 | 1 | 0 | 1 |
* /1Q |7 10| 2Q | 0 | 1 | / | 1 | 1 | - | - |
* GND |8 9| /2Q | 1 | 0 | / | 1 | 1 |/Q | Q |
* +----------+ | 1 | 1 | / | 1 | 1 | 1 | 0 |
* | X | X |!/ | 1 | 1 | - | - |
* +-----------------------------+
*
* [This information is part of the GIICM]
* </PRE>
*/
typedef enum {
JKFF_0, //!< no inputs or outputs
JKFF_CLK = (1 << 0), //!< clock signal
JKFF_J = (1 << 1), //!< J input
JKFF_K = (1 << 2), //!< K' input
JKFF_S = (1 << 3), //!< S' input
JKFF_C = (1 << 4), //!< C' input
JKFF_Q = (1 << 5), //!< Q output
JKFF_Q0 = (1 << 6) //!< Q' output
} jkff_t;
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2JKFF_H_
#define _A2JKFF_H_
#if JKFF_DEBUG
/**
* @brief simulate a 74109 J-K flip-flop with set and reset inputs
*
* @param s0 is the previous state of the FF's in- and outputs
* @param s1 is the next state
* @return returns the next state and probably modified Q output
*/
static inline jkff_t update_jkff(UINT8 s0, UINT8 s1, const char* jkff_name)
{
switch (s1 & (JKFF_C | JKFF_S))
{
case JKFF_C | JKFF_S: /* C' is 1, and S' is 1 */
if (((s0 ^ s1) & s1) & JKFF_CLK) {
/* rising edge of the clock */
switch (s1 & (JKFF_J | JKFF_K))
{
case 0:
/* both J and K' are 0: set Q to 0, Q' to 1 */
s1 = (s1 & ~JKFF_Q) | JKFF_Q0;
if (s0 & JKFF_Q) {
LOG((LOG_DISK,9,"\t\t%s J:0 K':0 -> Q:0\n", jkff_name));
}
break;
case JKFF_J:
/* J is 1, and K' is 0: toggle Q */
if (s0 & JKFF_Q)
s1 = (s1 & ~JKFF_Q) | JKFF_Q0;
else
s1 = (s1 | JKFF_Q) & ~JKFF_Q0;
LOG((LOG_DISK,9,"\t\t%s J:0 K':1 flip-flop Q:%d\n", jkff_name, (s1 & JKFF_Q) ? 1 : 0));
break;
case JKFF_K:
if ((s0 ^ s1) & JKFF_Q) {
LOG((LOG_DISK,9,"\t\t%s J:0 K':1 keep Q:%d\n", jkff_name, (s1 & JKFF_Q) ? 1 : 0));
}
/* J is 0, and K' is 1: keep Q as is */
if (s0 & JKFF_Q)
s1 = (s1 | JKFF_Q) & ~JKFF_Q0;
else
s1 = (s1 & ~JKFF_Q) | JKFF_Q0;
break;
case JKFF_J | JKFF_K:
/* both J and K' are 1: set Q to 1 */
s1 = (s1 | JKFF_Q) & ~JKFF_Q0;
if (!(s0 & JKFF_Q)) {
LOG((LOG_DISK,9,"\t\t%s J:1 K':1 -> Q:1\n", jkff_name));
}
break;
}
} else {
/* keep Q */
s1 = (s1 & ~JKFF_Q) | (s0 & JKFF_Q);
}
break;
case JKFF_S:
/* S' is 1, C' is 0: set Q to 0, Q' to 1 */
s1 = (s1 & ~JKFF_Q) | JKFF_Q0;
if (s0 & JKFF_Q) {
LOG((LOG_DISK,9,"\t\t%s C':0 -> Q:0\n", jkff_name));
}
break;
case JKFF_C:
/* S' is 0, C' is 1: set Q to 1, Q' to 0 */
s1 = (s1 | JKFF_Q) & ~JKFF_Q0;
if (!(s0 & JKFF_Q)) {
LOG((LOG_DISK,9,"\t\t%s S':0 -> Q:1\n", jkff_name));
}
break;
case 0:
default:
/* unstable state (what to do?) */
s1 = s1 | JKFF_Q | JKFF_Q0;
LOG((LOG_DISK,9,"\t\t%s C':0 S':0 -> Q:1 and Q':1 <unstable>\n", jkff_name));
break;
}
return static_cast<jkff_t>(s1);
}
#else // JKFF_DEBUG
/**
* @brief simulate a 74109 J-K flip-flop with set and reset inputs
*
* @param s0 is the previous state of the FF's in- and outputs
* @param s1 is the next state
* @return returns the next state and probably modified Q output
*/
static inline jkff_t update_jkff(UINT8 s0, UINT8 s1, const char*)
{
switch (s1 & (JKFF_C | JKFF_S))
{
case JKFF_C | JKFF_S: /* C' is 1, and S' is 1 */
if (((s0 ^ s1) & s1) & JKFF_CLK) {
/* rising edge of the clock */
switch (s1 & (JKFF_J | JKFF_K))
{
case 0:
/* both J and K' are 0: set Q to 0, Q' to 1 */
s1 = (s1 & ~JKFF_Q) | JKFF_Q0;
break;
case JKFF_J:
/* J is 1, and K' is 0: toggle Q */
if (s0 & JKFF_Q)
s1 = (s1 & ~JKFF_Q) | JKFF_Q0;
else
s1 = (s1 | JKFF_Q) & ~JKFF_Q0;
break;
case JKFF_K:
/* J is 0, and K' is 1: keep Q as is */
if (s0 & JKFF_Q)
s1 = (s1 | JKFF_Q) & ~JKFF_Q0;
else
s1 = (s1 & ~JKFF_Q) | JKFF_Q0;
break;
case JKFF_J | JKFF_K:
/* both J and K' are 1: set Q to 1 */
s1 = (s1 | JKFF_Q) & ~JKFF_Q0;
break;
}
} else {
/* keep Q */
s1 = (s1 & ~JKFF_Q) | (s0 & JKFF_Q);
}
break;
case JKFF_S:
/* S' is 1, C' is 0: set Q to 0, Q' to 1 */
s1 = (s1 & ~JKFF_Q) | JKFF_Q0;
break;
case JKFF_C:
/* S' is 0, C' is 1: set Q to 1, Q' to 0 */
s1 = (s1 | JKFF_Q) & ~JKFF_Q0;
break;
case 0:
default:
/* unstable state (what to do?) */
s1 = s1 | JKFF_Q | JKFF_Q0;
break;
}
return static_cast<jkff_t>(s1);
}
#endif // JKFF_DEBUG
#endif // _A2JKFF_H_
#endif // ALTO2_DEFINE_CONSTANTS

65
src/emu/cpu/alto2/a2kbd.c Normal file
View File

@ -0,0 +1,65 @@
/*****************************************************************************
*
* Xerox AltoII memory mapped I/O keyboard
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
/**
* @brief read the keyboard address matrix
*
* @param addr memory mapped I/O address to be read
* @return keyboard matrix value for address modulo 4
*/
READ16_MEMBER( alto2_cpu_device::kbd_ad_r )
{
UINT16 data = 0177777;
switch (offset & 3) {
case 0:
data = machine().root_device().ioport("ROW0")->read();
break;
case 1:
data = machine().root_device().ioport("ROW1")->read();
break;
case 2:
data = machine().root_device().ioport("ROW2")->read();
break;
case 3:
data = machine().root_device().ioport("ROW3")->read();
break;
}
m_kbd.matrix[offset & 03] = data;
if (!space.debugger_access()) {
LOG((LOG_KBD,2," read KBDAD+%o (%#o)\n", offset & 3, data));
}
if (0 == (offset & 3) && (m_kbd.bootkey != 0177777)) {
if (!space.debugger_access()) {
LOG((0,2," boot keys (%#o & %#o)\n", data, m_kbd.bootkey));
}
data &= m_kbd.bootkey;
m_kbd.bootkey = 0177777;
}
return data;
}
void alto2_cpu_device::init_kbd(UINT16 bootkey)
{
m_kbd.bootkey = bootkey;
}
void alto2_cpu_device::exit_kbd()
{
// nothing to do yet
}
void alto2_cpu_device::reset_kbd()
{
m_kbd.matrix[0] = 0177777;
m_kbd.matrix[1] = 0177777;
m_kbd.matrix[2] = 0177777;
m_kbd.matrix[3] = 0177777;
}

111
src/emu/cpu/alto2/a2kbd.h Normal file
View File

@ -0,0 +1,111 @@
/*****************************************************************************
*
* Xerox AltoII keyboard hardware (KBD)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
//! make an Xerox AltoII key bit mask
#define MAKE_KEY(a,b) (1 << (b))
#define A2_KEY_5 MAKE_KEY(0,017) //!< normal: 5 shifted: %
#define A2_KEY_4 MAKE_KEY(0,016) //!< normal: 4 shifted: $
#define A2_KEY_6 MAKE_KEY(0,015) //!< normal: 6 shifted: ~
#define A2_KEY_E MAKE_KEY(0,014) //!< normal: e shifted: E
#define A2_KEY_7 MAKE_KEY(0,013) //!< normal: 7 shifted: &
#define A2_KEY_D MAKE_KEY(0,012) //!< normal: d shifted: D
#define A2_KEY_U MAKE_KEY(0,011) //!< normal: u shifted: U
#define A2_KEY_V MAKE_KEY(0,010) //!< normal: v shifted: V
#define A2_KEY_0 MAKE_KEY(0,007) //!< normal: 0 shifted: )
#define A2_KEY_K MAKE_KEY(0,006) //!< normal: k shifted: K
#define A2_KEY_MINUS MAKE_KEY(0,005) //!< normal: - shifted: _
#define A2_KEY_P MAKE_KEY(0,004) //!< normal: p shifted: P
#define A2_KEY_SLASH MAKE_KEY(0,003) //!< normal: / shifted: ?
#define A2_KEY_BACKSLASH MAKE_KEY(0,002) //!< normal: \ shifted: |
#define A2_KEY_LF MAKE_KEY(0,001) //!< normal: LF
#define A2_KEY_BS MAKE_KEY(0,000) //!< normal: BS
#define A2_KEY_3 MAKE_KEY(1,017) //!< normal: 3 shifted: #
#define A2_KEY_2 MAKE_KEY(1,016) //!< normal: 2 shifted: @
#define A2_KEY_W MAKE_KEY(1,015) //!< normal: w shifted: W
#define A2_KEY_Q MAKE_KEY(1,014) //!< normal: q shifted: Q
#define A2_KEY_S MAKE_KEY(1,013) //!< normal: s shifted: S
#define A2_KEY_A MAKE_KEY(1,012) //!< normal: a shifted: A
#define A2_KEY_9 MAKE_KEY(1,011) //!< normal: 9 shifted: (
#define A2_KEY_I MAKE_KEY(1,010) //!< normal: i shifted: I
#define A2_KEY_X MAKE_KEY(1,007) //!< normal: x shifted: X
#define A2_KEY_O MAKE_KEY(1,006) //!< normal: o shifted: O
#define A2_KEY_L MAKE_KEY(1,005) //!< normal: l shifted: L
#define A2_KEY_COMMA MAKE_KEY(1,004) //!< normal: , shifted: <
#define A2_KEY_QUOTE MAKE_KEY(1,003) //!< normal: ' shifted: "
#define A2_KEY_RBRACKET MAKE_KEY(1,002) //!< normal: ] shifted: }
#define A2_KEY_BLANK_MID MAKE_KEY(1,001) //!< middle blank key
#define A2_KEY_BLANK_TOP MAKE_KEY(1,000) //!< top blank key
#define A2_KEY_1 MAKE_KEY(2,017) //!< normal: 1 shifted: !
#define A2_KEY_ESCAPE MAKE_KEY(2,016) //!< normal: ESC shifted: ?
#define A2_KEY_TAB MAKE_KEY(2,015) //!< normal: TAB shifted: ?
#define A2_KEY_F MAKE_KEY(2,014) //!< normal: f shifted: F
#define A2_KEY_CTRL MAKE_KEY(2,013) //!< CTRL
#define A2_KEY_C MAKE_KEY(2,012) //!< normal: c shifted: C
#define A2_KEY_J MAKE_KEY(2,011) //!< normal: j shifted: J
#define A2_KEY_B MAKE_KEY(2,010) //!< normal: b shifted: B
#define A2_KEY_Z MAKE_KEY(2,007) //!< normal: z shifted: Z
#define A2_KEY_LSHIFT MAKE_KEY(2,006) //!< LSHIFT
#define A2_KEY_PERIOD MAKE_KEY(2,005) //!< normal: . shifted: >
#define A2_KEY_SEMICOLON MAKE_KEY(2,004) //!< normal: ; shifted: :
#define A2_KEY_RETURN MAKE_KEY(2,003) //!< RETURN
#define A2_KEY_LEFTARROW MAKE_KEY(2,002) //!< normal: <- shifted: ^ (caret?)
#define A2_KEY_DEL MAKE_KEY(2,001) //!< normal: DEL
#define A2_KEY_MSW_2_17 MAKE_KEY(2,000) //!< unused on Microswitch KDB
#define A2_KEY_R MAKE_KEY(3,017) //!< normal: r shifted: R
#define A2_KEY_T MAKE_KEY(3,016) //!< normal: t shifted: T
#define A2_KEY_G MAKE_KEY(3,015) //!< normal: g shifted: G
#define A2_KEY_Y MAKE_KEY(3,014) //!< normal: y shifted: Y
#define A2_KEY_H MAKE_KEY(3,013) //!< normal: h shifted: H
#define A2_KEY_8 MAKE_KEY(3,012) //!< normal: 8 shifted: *
#define A2_KEY_N MAKE_KEY(3,011) //!< normal: n shifted: N
#define A2_KEY_M MAKE_KEY(3,010) //!< normal: m shifted: M
#define A2_KEY_LOCK MAKE_KEY(3,007) //!< LOCK
#define A2_KEY_SPACE MAKE_KEY(3,006) //!< SPACE
#define A2_KEY_LBRACKET MAKE_KEY(3,005) //!< normal: [ shifted: {
#define A2_KEY_EQUALS MAKE_KEY(3,004) //!< normal: = shifted: +
#define A2_KEY_RSHIFT MAKE_KEY(3,003) //!< RSHIFT
#define A2_KEY_BLANK_BOT MAKE_KEY(3,002) //!< bottom blank key
#define A2_KEY_MSW_3_16 MAKE_KEY(3,001) //!< unused on Microswitch KDB
#define A2_KEY_MSW_3_17 MAKE_KEY(3,000) //!< unused on Microswitch KDB
#define A2_KEY_FR2 MAKE_KEY(0,002) //!< ADL right function key 2
#define A2_KEY_FL2 MAKE_KEY(0,001) //!< ADL left function key 1
#define A2_KEY_FR4 MAKE_KEY(1,001) //!< ADL right funtion key 4
#define A2_KEY_BW MAKE_KEY(1,000) //!< ADL BW (?)
#define A2_KEY_FR3 MAKE_KEY(2,002) //!< ADL right function key 3
#define A2_KEY_FL1 MAKE_KEY(2,001) //!< ADL left function key 1
#define A2_KEY_FL3 MAKE_KEY(2,000) //!< ADL left function key 3
#define A2_KEY_FR1 MAKE_KEY(3,002) //!< ADL right function key 4
#define A2_KEY_FL4 MAKE_KEY(3,001) //!< ADL left function key 4
#define A2_KEY_FR5 MAKE_KEY(3,000) //!< ADL right function key 5
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2KBD_H_
#define _A2KBD_H_
struct {
UINT16 bootkey; //!< boot key - key code pressed before power on
UINT16 matrix[4]; //!< a bit map of the keys pressed (ioports ROW0 ... ROW3)
} m_kbd;
DECLARE_READ16_MEMBER( kbd_ad_r ); //!< read the keyboard matrix
void init_kbd(UINT16 bootkey = 0177777); //!< initialize the keyboard hardware, optinally set the boot key
void exit_kbd(); //!< deinitialize the keyboard hardware
void reset_kbd(); //!< reset the keyboard hardware
#endif // _A2KBD_H_
#endif // ALTO2_DEFINE_CONSTANTS

View File

@ -0,0 +1,56 @@
/*****************************************************************************
*
* Xerox AltoII disk sector task
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
//! f1_ksec_block early: block the disk sector task
void alto2_cpu_device::f1_early_ksec_block()
{
LOG((LOG_KSEC,2," BLOCK %s\n", task_name(m_task)));
disk_block(m_task);
}
//! disk sector task slot initialization
void alto2_cpu_device::init_ksec(int task)
{
set_bs(task, bs_ksec_read_kstat, &alto2_cpu_device::bs_early_read_kstat, 0);
set_bs(task, bs_ksec_read_kdata, &alto2_cpu_device::bs_early_read_kdata, 0);
set_f1(task, f1_block, &alto2_cpu_device::f1_early_ksec_block, 0);
set_f1(task, f1_task_10, 0, 0);
set_f1(task, f1_ksec_strobe, 0, &alto2_cpu_device::f1_late_strobe);
set_f1(task, f1_ksec_load_kstat, 0, &alto2_cpu_device::f1_late_load_kstat);
set_f1(task, f1_ksec_increcno, 0, &alto2_cpu_device::f1_late_increcno);
set_f1(task, f1_ksec_clrstat, 0, &alto2_cpu_device::f1_late_clrstat);
set_f1(task, f1_ksec_load_kcom, 0, &alto2_cpu_device::f1_late_load_kcom);
set_f1(task, f1_ksec_load_kadr, 0, &alto2_cpu_device::f1_late_load_kadr);
set_f1(task, f1_ksec_load_kdata, 0, &alto2_cpu_device::f1_late_load_kdata);
set_f2(task, f2_ksec_init, 0, &alto2_cpu_device::f2_late_init);
set_f2(task, f2_ksec_rwc, 0, &alto2_cpu_device::f2_late_rwc);
set_f2(task, f2_ksec_recno, 0, &alto2_cpu_device::f2_late_recno);
set_f2(task, f2_ksec_xfrdat, 0, &alto2_cpu_device::f2_late_xfrdat);
set_f2(task, f2_ksec_swrnrdy, 0, &alto2_cpu_device::f2_late_swrnrdy);
set_f2(task, f2_ksec_nfer, 0, &alto2_cpu_device::f2_late_nfer);
set_f2(task, f2_ksec_strobon, 0, &alto2_cpu_device::f2_late_strobon);
set_f2(task, f2_task_17, 0, 0);
m_task_wakeup |= 1 << task;
}
void alto2_cpu_device::exit_ksec()
{
// nothing to do yet
}
void alto2_cpu_device::reset_ksec()
{
// nothing to do yet
}

View File

@ -0,0 +1,50 @@
/*****************************************************************************
*
* Xerox AltoII disk sector task (KSEC)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2KSEC_H_
#define _A2KSEC_H_
//! BUS source for disk sector task
enum {
bs_ksec_read_kstat = bs_task_3, //!< bus source: read disk status register
bs_ksec_read_kdata = bs_task_4 //!< bus source: read disk data register
};
//! F1 functions for disk sector task
enum {
//!< f1 10: undefined
f1_ksec_strobe = f1_task_11, //!< f1 11: strobe
f1_ksec_load_kstat = f1_task_12, //!< f1 12: load kstat register
f1_ksec_increcno = f1_task_13, //!< f1 13: increment record number
f1_ksec_clrstat = f1_task_14, //!< f1 14: clear status register
f1_ksec_load_kcom = f1_task_15, //!< f1 15: load kcom register
f1_ksec_load_kadr = f1_task_16, //!< f1 16: load kadr register
f1_ksec_load_kdata = f1_task_17 //!< f1 17: load kdata register
};
//! F2 functions for disk sector task
enum {
f2_ksec_init = f2_task_10, //!< f2 10: branches NEXT[5-9] on WDTASKACT && WDINIT
f2_ksec_rwc = f2_task_11, //!< f2 11: branches NEXT[8-9] on READ/WRITE/CHECK for record
f2_ksec_recno = f2_task_12, //!< f2 12: branches NEXT[8-9] on RECNO[0-1]
f2_ksec_xfrdat = f2_task_13, //!< f2 13: branches NEXT[9] on !SEEKONLY
f2_ksec_swrnrdy = f2_task_14, //!< f2 14: branches NEXT[9] on !SWRDY
f2_ksec_nfer = f2_task_15, //!< f2 15: branches NEXT[9] on !KFER
f2_ksec_strobon = f2_task_16, //!< f2 16: branches NEXT[9] on STROBE
//!< f2 17: undefined
};
void f1_early_ksec_block(void); //!< block ksec task
void init_ksec(int task = task_ksec); //!< initialize the disk sector task
void exit_ksec(); //!< deinitialize the disk sector task
void reset_ksec(); //!< reset the disk sector task
#endif // _A2KSEC_H_
#endif // ALTO2_DEFINE_CONSTANTS

54
src/emu/cpu/alto2/a2kwd.c Normal file
View File

@ -0,0 +1,54 @@
/*****************************************************************************
*
* Xerox AltoII disk word task
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
//! f1_kwd_block early: block the disk word task
void alto2_cpu_device::f1_early_kwd_block()
{
LOG((LOG_KWD,2," BLOCK %s\n", task_name(m_task)));
disk_block(m_task);
}
//! disk word task slot initialization
void alto2_cpu_device::init_kwd(int task)
{
set_bs(task, bs_kwd_read_kstat, &alto2_cpu_device::bs_early_read_kstat, 0);
set_bs(task, bs_kwd_read_kdata, &alto2_cpu_device::bs_early_read_kdata, 0);
set_f1(task, f1_block, &alto2_cpu_device::f1_early_kwd_block, 0);
set_f1(task, f1_task_10, 0, 0);
set_f1(task, f1_kwd_strobe, 0, &alto2_cpu_device::f1_late_strobe);
set_f1(task, f1_kwd_load_kstat, 0, &alto2_cpu_device::f1_late_load_kstat);
set_f1(task, f1_kwd_increcno, 0, &alto2_cpu_device::f1_late_increcno);
set_f1(task, f1_kwd_clrstat, 0, &alto2_cpu_device::f1_late_clrstat);
set_f1(task, f1_kwd_load_kcom, 0, &alto2_cpu_device::f1_late_load_kcom);
set_f1(task, f1_kwd_load_kadr, 0, &alto2_cpu_device::f1_late_load_kadr);
set_f1(task, f1_kwd_load_kdata, 0, &alto2_cpu_device::f1_late_load_kdata);
set_f2(task, f2_kwd_init, 0, &alto2_cpu_device::f2_late_init);
set_f2(task, f2_kwd_rwc, 0, &alto2_cpu_device::f2_late_rwc);
set_f2(task, f2_kwd_recno, 0, &alto2_cpu_device::f2_late_recno);
set_f2(task, f2_kwd_xfrdat, 0, &alto2_cpu_device::f2_late_xfrdat);
set_f2(task, f2_kwd_swrnrdy, 0, &alto2_cpu_device::f2_late_swrnrdy);
set_f2(task, f2_kwd_nfer, 0, &alto2_cpu_device::f2_late_nfer);
set_f2(task, f2_kwd_strobon, 0, &alto2_cpu_device::f2_late_strobon);
set_f2(task, f2_task_17, 0, 0);
}
void alto2_cpu_device::exit_kwd()
{
// nothing to do yet
}
void alto2_cpu_device::reset_kwd()
{
// nothing to do yet
}

51
src/emu/cpu/alto2/a2kwd.h Normal file
View File

@ -0,0 +1,51 @@
/*****************************************************************************
*
* Xerox AltoII disk word task (KWD)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2KWD_H_
#define _A2KWD_H_
//! BUS source for disk word task
enum {
bs_kwd_read_kstat = bs_task_3, //!< bus source: read disk status register
bs_kwd_read_kdata = bs_task_4 //!< bus source: read disk data register
};
//! F1 functions for disk word task
enum {
//!< f1 10: undefined
f1_kwd_strobe = f1_task_11, //!< f1 11: strobe
f1_kwd_load_kstat = f1_task_12, //!< f1 12: load kstat register
f1_kwd_increcno = f1_task_13, //!< f1 13: increment record number
f1_kwd_clrstat = f1_task_14, //!< f1 14: clear status register
f1_kwd_load_kcom = f1_task_15, //!< f1 15: load kcom register
f1_kwd_load_kadr = f1_task_16, //!< f1 16: load kadr register
f1_kwd_load_kdata = f1_task_17, //!< f1 17: load kdata register
};
//! F2 functions for disk word task
enum {
f2_kwd_init = f2_task_10, //!< f2 10: branches NEXT[5-9] on WDTASKACT && WDINIT
f2_kwd_rwc = f2_task_11, //!< f2 11: branches NEXT[8-9] on READ/WRITE/CHECK for record
f2_kwd_recno = f2_task_12, //!< f2 12: branches NEXT[8-9] on RECNO[0-1]
f2_kwd_xfrdat = f2_task_13, //!< f2 13: branches NEXT[9] on !SEEKONLY
f2_kwd_swrnrdy = f2_task_14, //!< f2 14: branches NEXT[9] on !SWRDY
f2_kwd_nfer = f2_task_15, //!< f2 15: branches NEXT[9] on !KFER
f2_kwd_strobon = f2_task_16, //!< f2 16: branches NEXT[9] on STROBE
//!< f2 17: undefined
};
void f1_early_kwd_block(); //!< F1 func: disable the disk word task
void init_kwd(int task = task_kwd); //!< initialize the disk word task
void exit_kwd(); //!< deinitialize the disk word task
void reset_kwd(); //!< reset the disk word task
#endif // _A2KWD_H_
#endif // ALTO2_DEFINE_CONSTANTS

879
src/emu/cpu/alto2/a2mem.c Normal file
View File

@ -0,0 +1,879 @@
/*****************************************************************************
*
* Xerox AltoII memory interface
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
#define PUT_EVEN(dword,word) X_WRBITS(dword,32, 0,15,word)
#define GET_EVEN(dword) X_RDBITS(dword,32, 0,15)
#define PUT_ODD(dword,word) X_WRBITS(dword,32,16,31,word)
#define GET_ODD(dword) X_RDBITS(dword,32,16,31)
#define GET_MESR_HAMMING(mesr) X_RDBITS(mesr,16,0,5)
#define PUT_MESR_HAMMING(mesr,val) X_WRBITS(mesr,16,0,5,val)
#define GET_MESR_PERR(mesr) X_RDBITS(mesr,16,6,6)
#define PUT_MESR_PERR(mesr,val) X_WRBITS(mesr,16,6,6,val)
#define GET_MESR_PARITY(mesr) X_RDBITS(mesr,16,7,7)
#define PUT_MESR_PARITY(mesr,val) X_WRBITS(mesr,16,7,7,val)
#define GET_MESR_SYNDROME(mesr) X_RDBITS(mesr,16,8,13)
#define PUT_MESR_SYNDROME(mesr,val) X_WRBITS(mesr,16,8,13,val)
#define GET_MESR_BANK(mesr) X_RDBITS(mesr,16,14,15)
#define PUT_MESR_BANK(mesr,val) X_WRBITS(mesr,16,14,15,val)
#define GET_MECR_SPARE1(mecr,val) X_RDBITS(mecr,16,0,3)
#define PUT_MECR_SPARE1(mecr,val) X_WRBITS(mecr,16,0,3,val)
#define GET_MECR_TEST_CODE(mecr) X_RDBITS(mecr,16,4,10)
#define PUT_MECR_TEST_CODE(mecr,val) X_WRBITS(mecr,16,4,10,val)
#define GET_MECR_TEST_MODE(mecr) X_RDBITS(mecr,16,11,11)
#define PUT_MECR_TEST_MODE(mecr,val) X_WRBITS(mecr,16,11,11,val)
#define GET_MECR_INT_SBERR(mecr) X_RDBITS(mecr,16,12,12)
#define PUT_MECR_INT_SBERR(mecr,val) X_WRBITS(mecr,16,12,12,val)
#define GET_MECR_INT_DBERR(mecr) X_RDBITS(mecr,16,13,13)
#define PUT_MECR_INT_DBERR(mecr,val) X_WRBITS(mecr,16,13,13,val)
#define GET_MECR_ERRCORR(mecr) X_RDBITS(mecr,16,14,14)
#define PUT_MECR_ERRCORR(mecr,val) X_WRBITS(mecr,16,14,14,val)
#define GET_MECR_SPARE2(mecr) X_RDBITS(mecr,16,15,15)
#define PUT_MECR_SPARE2(mecr,val) X_WRBITS(mecr,16,15,15,val)
/**
* <PRE>
* AltoII Memory
*
* Address mapping
*
* The mapping of addresses to memory chips can be altered by the setting of
* the "memory configuration switch". This switch is located at the top of the
* backplane of the AltoII. If the switch is in the alternate position, the
* first and second 32K portions of memory are exchanged.
*
* The AltoII memory system is organized around 32-bit doublewords. Stored
* along with each doubleword is 6 bits of Hamming code and a Parity bit for
* a total of 39 bits:
*
* bits 0-15 even data word
* bits 16-31 odd data word
* bits 32-37 Hamming code
* bit 38 Parity bit
*
* Things are further complicated by the fact that two types of memory chips
* are used: 16K chips in machines with extended memory and 4K chips for all
* others.
*
* The bits in a 1-word deep slice of memory are called a group. A group
* contains 4K oder 16K doublewords, depending on the chip type. The bits of
* a group on a single board are called a subgroup. Thus a subgroup contains
* 10 of the 40 bits in a group. There are 8 subgroups on a memory board.
* Subgroups are numbered from the high 3 bits of the address; for 4K chips
* this means MAR[0-2]; for 16K chips (i.e., an Alto with extended memory)
* this means BANK,MAR[0]:
*
* Subgroup Chip Positions
* 7 81-90
* 6 71-80
* 5 61-70
* 4 51-60
* 3 41-50
* 2 31-40
* 1 21-30
* 0 11-20
*
* The location of the bits in group 0 is:
*
* CARD 1 CARD2 CARD3 CARD4
* 32 24 16 08 00 33 25 17 09 01 34 26 18 10 02 35 27 19 11 03
* 36 28 20 12 04 37 29 21 13 05 38 30 22 14 06 xx 31 23 25 07
*
* Chips 15, 25, 35, 45, 65, 75 and 85 on board 4 aren't used. If you are out
* of replacement memory chips, you can use one of these, but then the board
* with the missing chips will only work in Slot 4.
*
* o WORD = 16 BITS
* o ACCESS -> 2 WORDS AT A TIME
* o -> 32 BITS + 6 BITS EC + PARITY + SPARE = 40 BITS
* o 10 BITS/MODULE 80 DRAMS/MODULE
* o 4 MODULES/ALTO 320 DRAMS/ALTO
*
* ADDRESS A0-6, WE, CAS'
* | TO ALL DEVICES
* v
* +-----------------------------------------+
* | ^ 8 DEVICES (32K OR 128K FOR XM) |
* | | | CARD 1
* /| v <------------ DATA OUT ----------> |
* / | 0 1 2 3 4 5 6 7 8 9 |
* / +-----------------------------------------+
* | H4 H0 28 24 20 16 12 8 4 0
* |
* | +-----------------------------------------+
* | /| | CARD 2
* | / +-----------------------------------------+
* RAS H5 H1 29 25 21 17 13 9 5 1
* 0-7
* | \ +-----------------------------------------+
* | \| | CARD 3
* | +-----------------------------------------+
* | P H2 30 26 22 18 14 10 6 2
* \
* \ +-----------------------------------------+
* \| | CARD 4
* +-----------------------------------------+
* X H3 31 27 23 19 15 11 7 3
*
* [ ODD WORD ] [ EVEN WORD ]
*
* <HR>
*
* 32K x 10 STORAGE MODULE
*
* Table I
*
* +-------+-------+-------+---------------+-------+
* |CIRCUIT| INPUT | SIGNAL| INVERTER | |
* | NO. | PINS | NAME | DEF?? ??? |RESIST.|
* +-------+-------+-------+---------------+-------+
* | | 71 | RAS0 | A1 1 -> 2 | ?? R2 |
* | 1 +-------+-------+---------------+-------+
* | | 110 | CS0 | A1 3 -> 4 | ?? R3 |
* +-------+-------+-------+---------------+-------+
* | | 79 | RAS1 | A2 1 -> 2 | ?? R4 |
* | 2 +-------+-------+---------------+-------+
* | | 110 | CS1 | A2 3 -> 4 | ?? R5 |
* +-------+-------+-------+---------------+-------+
* | | 90 | RAS2 | A3 1 -> 2 | ?? R7 |
* | 3 +-------+-------+---------------+-------+
* | | 110 | CS2 | A3 3 -> 4 | ?? R8 |
* +-------+-------+-------+---------------+-------+
* | | 86 | RAS3 | A3 11 -> 10 | ?? R9 |
* | 4 +-------+-------+---------------+-------+
* | | 110 | CS3 | A4 11 -> 10 | ?? R7 |
* +-------+-------+-------+---------------+-------+
* | | 102 | RAS4 | A4 1 -> 2 | ?? R4 |
* | 5 +-------+-------+---------------+-------+
* | | 110 | CS4 | A3 13 -> 12 | ?? R5 |
* +-------+-------+-------+---------------+-------+
* | | 106 | RAS5 | A5 11 -> 10 | ?? R3 |
* | 6 +-------+-------+---------------+-------+
* | | 110 | CS5 | A5 3 -> 4 | ?? R2 |
* +-------+-------+-------+---------------+-------+
* | | 111 | RAS6 | A5 1 -> 2 | ?? R8 |
* | 7 +-------+-------+---------------+-------+
* | | 110 | CS6 | A5 13 -> 12 | ?? R9 |
* +-------+-------+-------+---------------+-------+
* | | 99 | RAS7 | A4 13 -> 12 | ?? R5 |
* | 8 +-------+-------+---------------+-------+
* | | 110 | CS7 | A4 3 -> 4 | ?? R5 |
* +-------+-------+-------+---------------+-------+
*
* Table II
*
* MEMORY CHIP REFERENCE DESIGNATOR
*
* CIRCUIT NO.
* ROW NO. 1 2 3 4 5 6 7 8
* +-------+-------+-------+-------+-------+-------+-------+-------+-------+
* | 1 | 15 20 | 25 30 | 35 40 | 45 50 | 55 60 | 65 70 | 75 80 | 85 90 |
* +-------+-------+-------+-------+-------+-------+-------+-------+-------+
* | 2 | 14 19 | 24 29 | 34 39 | 44 49 | 54 59 | 64 69 | 64 79 | 84 89 |
* +-------+-------+-------+-------+-------+-------+-------+-------+-------+
* | 3 | 13 18 | 23 28 | 33 38 | 43 48 | 53 58 | 63 68 | 73 78 | 83 88 |
* +-------+-------+-------+-------+-------+-------+-------+-------+-------+
* | 4 | 12 17 | 22 27 | 32 37 | 42 47 | 52 57 | 62 67 | 72 77 | 82 87 |
* +-------+-------+-------+-------+-------+-------+-------+-------+-------+
* | 5 | 11 16 | 21 26 | 31 36 | 41 46 | 52 56 | 61 66 | 71 76 | 81 86 |
* +-------+-------+-------+-------+-------+-------+-------+-------+-------+
*
*
* The Hamming code generator:
*
* WDxx is write data bit xx.
* H(x) is Hammming code bit x.
* HC(x) is generated Hamming code bit x.
* HC(x/y) is an intermediate value.
* HC(x)A and HC(x)B are also intermediate values.
*
* Chips used are:
* 74S280 9-bit parity generator (A-I inputs, even and odd outputs)
* 74S135 EX-OR/EX-NOR gates (5 inputs, 2 outputs)
* 74S86 EX-OR gates (2 inputs, 1 output)
*
* chip A B C D E F G H I even odd
* ---------------------------------------------------------------------------------
* a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A
* a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD28 HC(0B1) ---
* a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A ---
* a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A
* a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B ---
*
* H(0) ^ HC(0)A ^ HC(0B1) -> HC(0)
* H(1) ^ HC(1)A ^ HC(0B1) -> HC(1)
* HC(2)A ^ HC(2)B ^ H(2) -> HC(2)
* H(0) ^ H(1) ^ H(2) -> H(0/2)
*
* chip A B C D E F G H I even odd
* ---------------------------------------------------------------------------------
* a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A
* a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA
* a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A
* a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB
*
* HC(3)A ^ HC(3/4) -> HC(3)
* HC(4)A ^ HC(3/4) -> HC(4)
*
* WD00 ^ WD01 -> XX01
*
* chip A B C D E F G H I even odd
* ---------------------------------------------------------------------------------
* a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 RP PERR ---
* a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA
* a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB ---
*
* PCA ^ PCB -> PC
*
* Whoa ;-)
* </PRE>
*/
#if USE_HAMMING_CHECK
#define WD(x) (1ul<<(31-x))
/* a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A */
#define A75 (WD( 1)|WD( 4)|WD( 8)|WD(11)|WD(15)|WD(19)|WD(23)|WD(26)|WD(30))
/* a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD29 HC(0B1) --- */
#define A76 (WD( 0)|WD( 3)|WD( 6)|WD(10)|WD(13)|WD(17)|WD(21)|WD(25)|WD(28))
/* a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- */
#define A86 (WD( 2)|WD( 5)|WD( 9)|WD(12)|WD(16)|WD(20)|WD(24)|WD(27)|WD(31))
/* a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A */
#define A64 (WD( 1)|WD( 2)|WD( 3)|WD( 7)|WD( 8)|WD( 9)|WD(10)|WD(14)|WD(15))
/* a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- */
#define A85 (WD(16)|WD(17)|WD(22)|WD(23)|WD(24)|WD(25)|WD(29)|WD(30)|WD(31))
/* a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A */
#define A66 (WD( 4)|WD( 5)|WD( 6)|WD( 7)|WD( 8)|WD( 9)|WD(10))
/* a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA */
#define A84 (WD(18)|WD(19)|WD(20)|WD(21)|WD(22)|WD(23)|WD(24)|WD(25))
/* a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A */
#define A63 (WD(11)|WD(12)|WD(13)|WD(14)|WD(15)|WD(16)|WD(17))
/* a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB */
#define A87 (WD(26)|WD(27)|WD(28)|WD(29)|WD(30)|WD(31))
/* a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 P PERR --- */
#define A54 (WD( 2)|WD( 3))
/* a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA */
#define A65 (WD( 0)|WD( 1)|WD( 2)|WD( 4)|WD( 5)|WD( 7)|WD(10)|WD(11)|WD(12))
/* a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- */
#define A74 (WD(14)|WD(17)|WD(18)|WD(21)|WD(23)|WD(24)|WD(26)|WD(27)|WD(29))
#define H0(hpb) X_BIT(hpb,8,0) //!< get Hamming code bit 0 from hpb data (really bit 32)
#define H1(hpb) X_BIT(hpb,8,1) //!< get Hamming code bit 1 from hpb data (really bit 33)
#define H2(hpb) X_BIT(hpb,8,2) //!< get Hamming code bit 2 from hpb data (really bit 34)
#define H3(hpb) X_BIT(hpb,8,3) //!< get Hamming code bit 3 from hpb data (really bit 35)
#define H4(hpb) X_BIT(hpb,8,4) //!< get Hamming code bit 4 from hpb data (really bit 36)
#define H5(hpb) X_BIT(hpb,8,5) //!< get Hamming code bit 5 from hpb data (really bit 37)
#define RH(hpb) X_RDBITS(hpb,8,0,5) //!< get Hamming code from hpb data (bits 32 to 37)
#define RP(hpb) X_BIT(hpb,8,6) //!< get parity bit from hpb data (really bit 38)
/** @brief return even parity of a (masked) 32 bit value */
static __inline UINT8 parity_even(UINT32 val)
{
val -= ((val >> 1) & 0x55555555);
val = (((val >> 2) & 0x33333333) + (val & 0x33333333));
val = (((val >> 4) + val) & 0x0f0f0f0f);
val += (val >> 8);
val += (val >> 16);
return (val & 1);
}
/** @brief return odd parity of a (masked) 32 bit value */
#define parity_odd(val) (parity_even(val)^1)
/**
* @brief lookup table to convert a Hamming syndrome into a bit number to correct
*/
static const int hamming_lut[64] = {
-1, -1, -1, 0, -1, 1, 2, 3, /* A69: HR(5):0 HR(4):0 HR(3):0 */
-1, 4, 5, 6, 7, 8, 9, 10, /* A79: HR(5):0 HR(4):0 HR(3):1 */
-1, 11, 12, 13, 14, 15, 16, 17, /* A67: HR(5):0 HR(4):1 HR(3):0 */
-1, -1, -1, -1, -1, 1, -1, -1, /* non chip selected */
-1, 26, 27, 28, 29, 30, 31, -1, /* A68: HR(5):1 HR(4):0 HR(3):0 */
-1, -1, -1, -1, -1, 1, -1, -1, /* non chip selected */
18, 19, 20, 21, 22, 23, 24, 25, /* A78: HR(5):1 HR(4):1 HR(3):0 */
-1, -1, -1, -1, -1, 1, -1, -1 /* non chip selected */
};
/**
* @brief read or write a memory double-word and caluclate its Hamming code
*
* Hamming code generation according to the schematics described above.
* It's certainly overkill to do this on a modern PC, but I think we'll
* need it for perfect emulation anyways (Hamming code hardware checking).
*
* @param write non-zero if this is a memory write (don't check for error)
* @param dw_addr the double-word address
* @param dw_data the double-word data to write
* @return dw_data
*/
UINT32 alto2_cpu_device::hamming_code(int write, UINT32 dw_addr, UINT32 dw_data)
{
register UINT8 hpb = write ? 0 : m_mem.hpb[dw_addr];
register UINT8 hc_0_a;
register UINT8 hc_0b1;
register UINT8 hc_1_a;
register UINT8 hc_2_a;
register UINT8 hc_2_b;
register UINT8 hc_0;
register UINT8 hc_1;
register UINT8 hc_2;
register UINT8 h_0_2;
register UINT8 hc_3_a;
register UINT8 hc_3_4;
register UINT8 hcpa;
register UINT8 hc_4_a;
register UINT8 hc_3;
register UINT8 hc_4;
register UINT8 hc_5;
register UINT8 hcpb;
register UINT8 perr;
register UINT8 pca;
register UINT8 pcb;
register UINT8 pc;
register int syndrome;
/* a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A */
hc_0_a = parity_odd (dw_data & A75);
/* a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD29 HC(0B1) --- */
hc_0b1 = parity_even(dw_data & A76);
/* a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- */
hc_1_a = parity_even(dw_data & A86);
/* a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A */
hc_2_a = parity_odd (dw_data & A64);
/* a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- */
hc_2_b = parity_even(dw_data & A85);
hc_0 = H0(hpb) ^ hc_0_a ^ hc_0b1;
hc_1 = H1(hpb) ^ hc_1_a ^ hc_0b1;
hc_2 = hc_2_a ^ hc_2_b ^ H2(hpb);
h_0_2 = H0(hpb) ^ H1(hpb) ^ H2(hpb);
/* a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A */
hc_3_a = parity_odd ((dw_data & A66) ^ H3(hpb));
/* a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA */
hcpa = parity_odd (dw_data & A84);
hc_3_4 = hcpa ^ 1;
/* a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A */
hc_4_a = parity_odd ((dw_data & A63) ^ H4(hpb));
/* a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB */
hcpb = parity_odd ((dw_data & A87) ^ H5(hpb));
hc_3 = hc_3_a ^ hc_3_4;
hc_4 = hc_4_a ^ hc_3_4;
hc_5 = hcpb ^ 1;
syndrome = (hc_0<<5)|(hc_1<<4)|(hc_2<<3)|(hc_3<<2)|(hc_4<<1)|(hc_5);
/*
* Note: Here I XOR all the non dw_data inputs into bit 0,
* which has the same effect as spreading them over some bits
* and then counting them... I hope ;-)
*/
/* a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 P PERR --- */
perr = parity_even(
hc_3_a ^
hc_4_a ^
hcpa ^
hcpb ^
h_0_2 ^
(X_RDBITS(dw_data,32,0,0) ^ X_RDBITS(dw_data,32,1,1)) ^
(dw_data & A54) ^
RP(hpb) ^
1);
/* a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA */
pca = parity_odd (dw_data & A65);
/* a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- */
pcb = parity_even(dw_data & A74);
pc = pca ^ pcb;
if (write) {
/* update the hamming code and parity bit store */
m_mem.hpb[dw_addr] = (syndrome << 2) | (pc << 1);
return dw_data;
}
/**
* <PRE>
* A22 (74H30) 8-input NAND to check for error
* input signal
* -------------------------
* 1 POK = PERR'
* 4 NER(08) = HC(0)'
* 3 NER(09) = HC(1)'
* 2 NER(10) = HC(2)'
* 6 NER(11) = HC(3)'
* 5 NER(12) = HC(4)'
* 12 NER(13) = HC(5)'
* 11 1 (VPUL3)
*
* output signal
* -------------------------
* 8 ERROR
*
* Remembering De Morgan this can be simplified:
* ERROR is 0, whenever all of PERR and HC(0) to HC(5) are 0.
* Or the other way round: any of perr or syndrome non-zero means ERROR=1.
* </PRE>
*/
if (perr || syndrome) {
/* latch data on the first error */
if (!m_mem.error) {
m_mem.error = true;
PUT_MESR_HAMMING(m_mem.mesr, RH(hpb));
PUT_MESR_PERR(m_mem.mesr, perr);
PUT_MESR_PARITY(m_mem.mesr, RP(hpb));
PUT_MESR_SYNDROME(m_mem.mesr, syndrome);
PUT_MESR_BANK(m_mem.mesr, (dw_addr >> 15));
/* latch memory address register */
m_mem.mear = m_mem.mar & 0177777;
LOG((LOG_MEM,5," memory error at dword addr:%07o data:%011o check:%03o\n", dw_addr * 2, dw_data, hpb));
LOG((LOG_MEM,6," MEAR: %06o\n", m_mem.mear));
LOG((LOG_MEM,6," MESR: %06o\n", m_mem.mesr ^ 0177777));
LOG((LOG_MEM,7," Hamming code read : %#o\n", GET_MESR_HAMMING(m_mem.mesr)));
LOG((LOG_MEM,7," Parity error : %o\n", GET_MESR_PERR(m_mem.mesr)));
LOG((LOG_MEM,7," Memory parity bit : %o\n", GET_MESR_PARITY(m_mem.mesr)));
LOG((LOG_MEM,7," Hamming syndrome : %#o (bit #%d)\n", GET_MESR_SYNDROME(m_mem.mesr), hamming_lut[GET_MESR_SYNDROME(m_mem.mesr)]));
LOG((LOG_MEM,7," Memory bank : %#o\n", GET_MESR_BANK(m_mem.mesr)));
LOG((LOG_MEM,6," MECR: %06o\n", m_mem.mecr ^ 0177777));
LOG((LOG_MEM,7," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(m_mem.mecr)));
LOG((LOG_MEM,7," Test mode : %s\n", GET_MECR_TEST_MODE(m_mem.mecr) ? "on" : "off"));
LOG((LOG_MEM,7," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(m_mem.mecr) ? "on" : "off"));
LOG((LOG_MEM,7," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(m_mem.mecr) ? "on" : "off"));
LOG((LOG_MEM,7," Error correction : %s\n", GET_MECR_ERRCORR(m_mem.mecr) ? "off" : "on"));
}
if (-1 == hamming_lut[syndrome]) {
/* double-bit error: wake task_part, if we're told so */
if (GET_MECR_INT_DBERR(m_mem.mecr))
m_task_wakeup |= 1 << task_part;
} else {
/* single-bit error: wake task_part, if we're told so */
if (GET_MECR_INT_SBERR(m_mem.mecr))
m_task_wakeup |= 1 << task_part;
/* should we correct the single bit error ? */
if (0 == GET_MECR_ERRCORR(m_mem.mecr)) {
LOG((LOG_MEM,0," correct bit #%d addr:%07o data:%011o check:%03o\n", hamming_lut[syndrome], dw_addr * 2, dw_data, hpb));
dw_data ^= 1ul << hamming_lut[syndrome];
}
}
}
return dw_data;
}
#endif /* USE_HAMMING_CHECK */
/**
* @brief memory error address register read
*
* This register is a 'shadow MAR'; it holds the address of the
* first error since the error status was last reset. If no error
* has occured, MEAR reports the address of the most recent
* memory access. Note that MEAR is set whenever an error of
* _any kind_ (single-bit or double-bit) is detected.
*/
READ16_MEMBER( alto2_cpu_device::mear_r )
{
int data = m_mem.error ? m_mem.mear : m_mem.mar;
if (!space.debugger_access()) {
LOG((LOG_MEM,2," MEAR read %07o\n", data));
}
return data;
}
/**
* @brief memory error status register read
*
* This register reports specifics of the first error that
* occured since MESR was last reset. Storing anything into
* this register resets the error logic and enables it to
* detect a new error. Bits are "low true", i.e. if the bit
* is 0, the conidition is true.
* <PRE>
* MESR[0-5] Hamming code reported from error
* MESR[6] Parity error
* MESR[7] Memory parity bit
* MESR[8-13] Syndrome bits
* MESR[14-15] Bank number in which error occured
* </PRE>
*/
READ16_MEMBER( alto2_cpu_device::mesr_r )
{
UINT16 data = m_mem.mesr ^ 0177777;
if (!space.debugger_access()) {
LOG((LOG_MEM,2," MESR read %07o\n", data));
LOG((LOG_MEM,6," Hamming code read : %#o\n", GET_MESR_HAMMING(data)));
LOG((LOG_MEM,6," Parity error : %o\n", GET_MESR_PERR(data)));
LOG((LOG_MEM,6," Memory parity bit : %o\n", GET_MESR_PARITY(data)));
#if USE_HAMMING_CHECK
LOG((LOG_MEM,6," Hamming syndrome : %#o (bit #%d)\n", GET_MESR_SYNDROME(data), hamming_lut[GET_MESR_SYNDROME(data)]));
#else
LOG((LOG_MEM,6," Hamming syndrome : %#o\n", GET_MESR_SYNDROME(data)));
#endif
LOG((LOG_MEM,6," Memory bank : %#o\n", GET_MESR_BANK(data)));
}
return data;
}
WRITE16_MEMBER( alto2_cpu_device::mesr_w )
{
if (!space.debugger_access()) {
LOG((LOG_MEM,2," MESR write %07o (clear MESR; was %07o)\n", data, m_mem.mesr));
}
m_mem.mesr = 0; // set all bits to 0
m_mem.error = 0; // reset the error flag
m_task_wakeup &= ~(1 << task_part); // clear the task wakeup for the parity error task
}
/**
* @brief memory error control register write
*
* Storing into this register is the means for controlling
* the memory error logic. This register is set to all ones
* (disable all interrupts) when the alto is bootstrapped
* and when the parity error task first detects an error.
* When an error has occured, MEAR and MESR should be read
* before setting MECR. Bits are "low true", i.e. a 0 bit
* enables the condition.
*
* <PRE>
* MECR[0-3] Spare
* MECR[4-10] Test hamming code (used only for special diagnostics)
* MECR[11] Test mode (used only for special diagnostics)
* MECR[12] Cause interrupt on single-bit errors if zero
* MECR[13] Cause interrupt on double-bit errors if zero
* MECR[14] Do not use error correction if zero
* MECR[15] Spare
* </PRE>
*/
WRITE16_MEMBER( alto2_cpu_device::mecr_w )
{
m_mem.mecr = data ^ 0177777;
X_WRBITS(m_mem.mecr,16, 0, 3,0);
X_WRBITS(m_mem.mecr,16,15,15,0);
if (!space.debugger_access()) {
LOG((LOG_MEM,2," MECR write %07o\n", data));
LOG((LOG_MEM,6," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(m_mem.mecr)));
LOG((LOG_MEM,6," Test mode : %s\n", GET_MECR_TEST_MODE(m_mem.mecr) ? "on" : "off"));
LOG((LOG_MEM,6," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(m_mem.mecr) ? "on" : "off"));
LOG((LOG_MEM,6," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(m_mem.mecr) ? "on" : "off"));
LOG((LOG_MEM,6," Error correction : %s\n", GET_MECR_ERRCORR(m_mem.mecr) ? "off" : "on"));
}
}
/**
* @brief memory error control register read
*/
READ16_MEMBER( alto2_cpu_device::mecr_r )
{
UINT16 data = m_mem.mecr ^ 0177777;
/* set all spare bits */
if (!space.debugger_access()) {
LOG((LOG_MEM,2," MECR read %07o\n", data));
LOG((LOG_MEM,6," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(data)));
LOG((LOG_MEM,6," Test mode : %s\n", GET_MECR_TEST_MODE(data) ? "on" : "off"));
LOG((LOG_MEM,6," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(data) ? "on" : "off"));
LOG((LOG_MEM,6," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(data) ? "on" : "off"));
LOG((LOG_MEM,6," Error correction : %s\n", GET_MECR_ERRCORR(data) ? "off" : "on"));
}
return data;
}
//! read i/o space RAM
READ16_MEMBER ( alto2_cpu_device::ioram_r )
{
offs_t dword_addr = offset / 2;
return static_cast<UINT16>(offset & 1 ? GET_ODD(m_mem.ram[dword_addr]) : GET_EVEN(m_mem.ram[dword_addr]));
}
//! write i/o space RAM
WRITE16_MEMBER( alto2_cpu_device::ioram_w )
{
offs_t dword_addr = offset / 2;
if (offset & 1)
PUT_ODD(m_mem.ram[dword_addr], data);
else
PUT_EVEN(m_mem.ram[dword_addr], data);
}
/**
* @brief load the memory address register with some value
*
* @param rsel selected register (to detect refresh cycles)
* @param addr memory address
*/
void alto2_cpu_device::load_mar(UINT8 rsel, UINT32 addr)
{
if (rsel == 037) {
/*
* starting a memory refresh cycle
* currently we don't do anything special
*/
LOG((LOG_MEM,5, " MAR<-; refresh cycle @ %#o\n", addr));
m_mem.mar = addr;
m_mem.access = ALTO2_MEM_REFRESH;
m_mem.cycle = cycle();
return;
}
m_mem.mar = addr;
if (addr < m_mem.size) {
LOG((LOG_MEM,2, " MAR<-; mar = %#o\n", addr));
m_mem.access = ALTO2_MEM_RAM;
// fetch the memory double-word to the read/write latches
m_mem.rmdd = m_mem.wmdd = m_mem.ram[m_mem.mar/2];
// keep track of the current CPU cycle
m_mem.cycle = cycle();
} else {
m_mem.access = ALTO2_MEM_INVALID;
m_mem.rmdd = m_mem.wmdd = ~0;
}
}
/**
* @brief read memory or memory mapped I/O from the address in mar to md
*
* @result returns value from memory (RAM or MMIO)
*/
UINT16 alto2_cpu_device::read_mem()
{
UINT32 base_addr;
if (ALTO2_MEM_NONE == m_mem.access) {
LOG((LOG_MEM,0," fatal: mem read with no preceding address\n"));
return 0177777;
}
if (cycle() > m_mem.cycle + 4) {
LOG((LOG_MEM,0," fatal: mem read (MAR %#o) too late (+%lld cyc)\n", m_mem.mar, cycle() - m_mem.cycle));
m_mem.access = ALTO2_MEM_NONE;
return 0177777;
}
base_addr = m_mem.mar & 0177777;
if (base_addr >= ALTO2_IO_PAGE_BASE && m_mem.mar < ALTO2_RAM_SIZE) {
m_mem.md = m_iomem->read_word(m_iomem->address_to_byte(base_addr));
LOG((LOG_MEM,6," MD = MMIO[%#o] (%#o)\n", base_addr, m_mem.md));
m_mem.access = ALTO2_MEM_NONE;
#if ALTO2_DEBUG
watch_read(m_mem.mar, m_mem.md);
#endif
return m_mem.md;
}
#if USE_HAMMING_CHECK
/* check for errors on the first access */
if (!(m_mem.access & ALTO2_MEM_ODD))
m_mem.rmdd = hamming_code(0, m_mem.mar/2, m_mem.rmdd);
#endif
m_mem.md = (m_mem.mar & ALTO2_MEM_ODD) ? GET_ODD(m_mem.rmdd) : GET_EVEN(m_mem.rmdd);
LOG((LOG_MEM,6," MD = RAM[%#o] (%#o)\n", m_mem.mar, m_mem.md));
#if ALTO2_DEBUG
watch_read(m_mem.mar, m_mem.md);
#endif
if (m_mem.access & ALTO2_MEM_ODD) {
// after reading the odd word, reset the access flag
m_mem.access = ALTO2_MEM_NONE;
} else {
// after reading the even word word, toggle access flag (and address) to the odd word
m_mem.mar ^= ALTO2_MEM_ODD;
m_mem.access ^= ALTO2_MEM_ODD;
// extend the read succeeds window by one cycle
m_mem.cycle++;
}
return m_mem.md;
}
/**
* @brief write memory or memory mapped I/O from md to the address in mar
*
* @param data data to write to RAM or MMIO
*/
void alto2_cpu_device::write_mem(UINT16 data)
{
int base_addr;
m_mem.md = data & 0177777;
if (ALTO2_MEM_NONE == m_mem.access) {
LOG((LOG_MEM,0," fatal: mem write with no preceding address\n"));
return;
}
if (cycle() > m_mem.cycle + 4) {
LOG((LOG_MEM,0," fatal: mem write (MAR %#o, data %#o) too late (+%lld cyc)\n", m_mem.mar, data, cycle() - m_mem.cycle));
m_mem.access = ALTO2_MEM_NONE;
return;
}
base_addr = m_mem.mar & 0177777;
if (base_addr >= ALTO2_IO_PAGE_BASE && m_mem.mar < ALTO2_RAM_SIZE) {
m_iomem->write_word(m_iomem->address_to_byte(base_addr), m_mem.md);
LOG((LOG_MEM,6, " MMIO[%#o] = MD (%#o)\n", base_addr, m_mem.md));
m_mem.access = ALTO2_MEM_NONE;
#if ALTO2_DEBUG
watch_write(m_mem.mar, m_mem.md);
#endif
return;
}
LOG((LOG_MEM,6, " RAM[%#o] = MD (%#o)\n", m_mem.mar, m_mem.md));
if (m_mem.mar & ALTO2_MEM_ODD)
PUT_ODD(m_mem.wmdd, m_mem.md);
else
PUT_EVEN(m_mem.wmdd, m_mem.md);
#if USE_HAMMING_CHECK
if (m_mem.access & ALTO2_MEM_RAM)
m_mem.ram[m_mem.mar/2] = hamming_code(1, m_mem.mar/2, m_mem.wmdd);
#else
if (m_mem.access & ALTO2_MEM_RAM)
m_mem.ram[m_mem.mar/2] = m_mem.wmdd;
#endif
#if ALTO2_DEBUG
watch_write(m_mem.mar, m_mem.md);
#endif
// Toggle the odd/even word access flag
// NB: don't reset mem.access to permit double word exchange
m_mem.mar ^= ALTO2_MEM_ODD;
m_mem.access ^= ALTO2_MEM_ODD;
// extend the write succeeds window by one cycle
m_mem.cycle++;
}
/**
* @brief debugger interface to read memory
*
* @param addr address to read
* @return memory contents at address (16 bits)
*/
UINT16 alto2_cpu_device::debug_read_mem(UINT32 addr)
{
space(AS_2).set_debugger_access(true);
int base_addr = addr & 0177777;
int data = 0177777;
if (base_addr >= ALTO2_IO_PAGE_BASE && addr < ALTO2_RAM_SIZE) {
data = m_iomem->read_word(m_iomem->address_to_byte(base_addr));
} else {
data = (addr & ALTO2_MEM_ODD) ? GET_ODD(m_mem.ram[addr/2]) : GET_EVEN(m_mem.ram[addr/2]);
}
space(AS_2).set_debugger_access(false);
return data;
}
/**
* @brief debugger interface to write memory
*
* @param addr address to write
* @param data data to write (16 bits used)
*/
void alto2_cpu_device::debug_write_mem(UINT32 addr, UINT16 data)
{
space(AS_2).set_debugger_access(true);
int base_addr = addr & 0177777;
if (base_addr >= ALTO2_IO_PAGE_BASE && addr < ALTO2_RAM_SIZE) {
m_iomem->write_word(m_iomem->address_to_byte(base_addr), data);
} else if (addr & ALTO2_MEM_ODD) {
PUT_ODD(m_mem.ram[addr/2], data);
} else {
PUT_EVEN(m_mem.ram[addr/2], data);
}
space(AS_2).set_debugger_access(false);
}
/**
* @brief initialize the memory system
*
* Zeroes the memory context, including RAM and installs dummy
* handlers for the memory mapped I/O area.
* Sets handlers for access to the memory error address, status,
* and control registers at 0177024 to 0177026.
*/
void alto2_cpu_device::init_memory()
{
memset(&m_mem, 0, sizeof(m_mem));
save_item(NAME(m_mem.mar));
save_item(NAME(m_mem.rmdd));
save_item(NAME(m_mem.wmdd));
save_item(NAME(m_mem.md));
save_item(NAME(m_mem.cycle));
save_item(NAME(m_mem.access));
save_item(NAME(m_mem.error));
save_item(NAME(m_mem.mear));
save_item(NAME(m_mem.mecr));
}
void alto2_cpu_device::exit_memory()
{
// no need for this since it free on exit by itself
// if (m_mem.ram) {
// auto_free(machine(), m_mem.ram);
// m_mem.ram = 0;
// }
// if (m_mem.hpb) {
// auto_free(machine(), m_mem.hpb);
// m_mem.hpb = 0;
// }
}
void alto2_cpu_device::reset_memory()
{
if (m_mem.ram) {
auto_free(machine(), m_mem.ram);
m_mem.ram = 0;
}
if (m_mem.hpb) {
auto_free(machine(), m_mem.hpb);
m_mem.hpb = 0;
}
// allocate 64K or 128K words of main memory
ioport_port* config = ioport(":CONFIG");
// config should be valid, unless the driver doesn't define it
if (config)
m_mem.size = config->read() & 1 ? ALTO2_RAM_SIZE : 2 * ALTO2_RAM_SIZE;
else
m_mem.size = ALTO2_RAM_SIZE;
logerror("Main memory %u KiB\n", static_cast<UINT32>(sizeof(UINT16) * m_mem.size / 1024));
m_mem.ram = auto_alloc_array_clear(machine(), UINT32, sizeof(UINT16) * m_mem.size);
m_mem.hpb = auto_alloc_array_clear(machine(), UINT8, sizeof(UINT16) * m_mem.size);
#if USE_HAMMING_CHECK
// Initialize the hamming codes and parity bit
for (UINT32 addr = 0; addr < ALTO2_IO_PAGE_BASE; addr++) {
hamming_code(1, addr, 0);
hamming_code(1, 0200000 + addr, 0);
}
#endif
m_mem.mar = 0;
m_mem.rmdd = 0;
m_mem.wmdd = 0;
m_mem.md = 0;
m_mem.cycle = 0;
m_mem.access = 0;
m_mem.error = false;
m_mem.mear = 0;
m_mem.mesr = 0;
m_mem.mecr = 0;
}

140
src/emu/cpu/alto2/a2mem.h Normal file
View File

@ -0,0 +1,140 @@
/*****************************************************************************
*
* Xerox AltoII memory block (MEM)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#define ALTO2_RAM_SIZE 0200000 //!< size of main memory in words
#define ALTO2_IO_PAGE_BASE 0177000 //!< base address of the memory mapped io range
#define ALTO2_IO_PAGE_SIZE 0001000 //!< size of the memory mapped io range
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2MEM_H_
#define _A2MEM_H_
//! memory access mode
enum {
ALTO2_MEM_NONE,
ALTO2_MEM_ODD = (1 << 0),
ALTO2_MEM_RAM = (1 << 1),
ALTO2_MEM_REFRESH = (1 << 2),
ALTO2_MEM_INVALID = (1 << 3)
};
struct {
UINT32 size; //!< main memory size (64K or 128K)
UINT32* ram; //!< main memory organized as double-words
UINT8* hpb; //!< Hamming Code bits (6) and Parity bits (1) per double word
UINT32 mar; //!< memory address register
UINT32 rmdd; //!< read memory data double-word
UINT32 wmdd; //!< write memory data double-word
UINT16 md; //!< memory data register
UINT64 cycle; //!< cycle when the memory address register was loaded
/**
* @brief memory access under the way if non-zero
* 0: no memory access (MEM_NONE)
* 1: invalid
* 2: memory access even word (MEM_RAM)
* 3: memory access odd word (MEM_RAM | MEM_ODD)
*/
int access;
bool error; //!< non-zero after a memory error was detected
UINT32 mear; //!< memory error address register
UINT16 mesr; //!< memory error status register
UINT16 mecr; //!< memory error control register
} m_mem;
/**
* @brief check if memory address register load is yet possible
* suspend if accessing RAM and previous MAR<- was less than 5 cycles ago
*
* 1. MAR<- ANY
* 2. REQUIRED
* 3. MD<- whatever
* 4. SUSPEND
* 5. SUSPEND
* 6. MAR<- ANY
*
* @return false, if memory address can be loaded
*/
inline bool check_mem_load_mar_stall(UINT8 rsel) {
if (ALTO2_MEM_NONE == m_mem.access)
return false;
return cycle() < m_mem.cycle+5;
}
/**
* @brief check if memory read is yet possible
* MAR<- = cycle #1, earliest read at cycle #5, i.e. + 4
*
* 1. MAR<- ANY
* 2. REQUIRED
* 3. SUSPEND
* 4. SUSPEND
* 5. whereever <-MD
*
* @return false, if memory can be read without wait cycle
*/
inline bool check_mem_read_stall() {
if (ALTO2_MEM_NONE == m_mem.access)
return false;
return cycle() < m_mem.cycle+4;
}
/**
* @brief check if memory write is yet possible
* MAR<- = cycle #1, earliest write at cycle #3, i.e. + 2
*
* 1. MAR<- ANY
* 2. REQUIRED
* 3. OPTIONAL
* 4. MD<- whatever
*
* @return false, if memory can be written without wait cycle
*/
inline bool check_mem_write_stall() {
if (ALTO2_MEM_NONE == m_mem.access)
return false;
return cycle() < m_mem.cycle+2;
}
DECLARE_READ16_MEMBER ( mear_r ); //!< memory error address register read
DECLARE_READ16_MEMBER ( mesr_r ); //!< memory error status register read
DECLARE_WRITE16_MEMBER( mesr_w ); //!< memory error status register write (clear)
DECLARE_READ16_MEMBER ( mecr_r ); //!< memory error control register read
DECLARE_WRITE16_MEMBER( mecr_w ); //!< memory error control register write
//! read or write a memory double-word and caluclate its Hamming code
UINT32 hamming_code(int write, UINT32 dw_addr, UINT32 dw_data);
//! load the memory address register with some value
void load_mar(UINT8 rsel, UINT32 addr);
//! read memory or memory mapped I/O from the address in mar to md
UINT16 read_mem();
//! write memory or memory mapped I/O from md to the address in mar
void write_mem(UINT16 data);
//! debugger interface to read memory
UINT16 debug_read_mem(UINT32 addr);
//! debugger interface to write memory
void debug_write_mem(UINT32 addr, UINT16 data);
#if ALTO2_DEBUG
void watch_write(UINT32 addr, UINT32 data);
void watch_read(UINT32 addr, UINT32 data);
#endif
void init_memory(); //!< initialize the memory system
void exit_memory(); //!< deinitialize the memory system
void reset_memory(); //!< reset the memory system
#endif // _A2MEM_H_
#endif // ALTO2_DEFINE_CONSTANTS

273
src/emu/cpu/alto2/a2mouse.c Normal file
View File

@ -0,0 +1,273 @@
/*****************************************************************************
*
* Xerox AltoII mouse interface
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
#include "a2roms.h"
#define MOUSE_DIRTY_HACK 0
enum {
MX1 = (1<<0), //!< MX1 signal is bit 0 (latch bit 1)
LMX1 = (1<<1),
MX2 = (1<<2), //!< MX2 signal is bit 2 (latch bit 3)
LMX2 = (1<<3),
MY1 = (1<<4), //!< MY1 signal is bit 4 (latch bit 5)
LMY1 = (1<<5),
MY2 = (1<<6), //!< MY2 signal is bit 6 (latch bit 7)
LMY2 = (1<<7),
MACTIVE = (MX1|MX2|MY1|MY2), //!< mask for the active bits
MLATCH = (LMX1|LMX2|LMY1|LMY2) //!< mask for the latched bits
};
/**
* <PRE>
* The mouse inputs from the shutters are connected to a quad
* 2/3 input RS flip flop (SN74279).
*
* 74279
* +---+--+---+
* | +--+ |
* R1 -|1 16|- Vcc
* | |
* S1a -|2 15|- S4
* | |
* S1b -|3 14|- R4
* | |
* Q1 -|4 13|- Q4
* | |
* R2 -|5 12|- S3a
* | |
* S2 -|6 11|- S3b
* | |
* Q2 -|7 10|- R3
* | |
* GND -|8 9|- Q3
* | |
* +----------+
*
* The 'Y' Encoder signals are connected to IC1:
* shutter pin(s) R/S output
* ------------------------------------
* 0 2,3 S1a,b Q1 MX2 -> 1
* 1 1 R1 Q1 MX2 -> 0
* 2 5 R2 Q2 MX1 -> 0
* 3 6 S2 Q2 MX1 -> 1
*
* The 'X' Encoder signals are connected to IC2:
* shutter pin(s) R/S output
* ------------------------------------
* 0 2,3 S1a,b Q1 MY2 -> 1
* 1 1 R1 Q1 MY2 -> 0
* 2 5 R2 Q2 MY1 -> 0
* 3 6 S2 Q2 MY1 -> 1
*
*
* The pulse train generated by a left or up rotation is:
*
* +---+ +---+ +---+
* MX1/MY1 | | | | | |
* ---+ +---+ +---+ +---
*
* +---+ +---+ +---+ +-
* MX2/MY2 | | | | | | |
* -+ +---+ +---+ +---+
*
*
* The pulse train generated by a right or down rotation is:
*
* +---+ +---+ +---+ +-
* MX1/MY1 | | | | | | |
* -+ +---+ +---+ +---+
*
* +---+ +---+ +---+
* MX2/MY2 | | | | | |
* ---+ +---+ +---+ +---
*
* In order to simulate the shutter sequence for the mouse motions
* we have to generate a sequence of pulses on MX1/MX2 and MY1/MY2
* that have their phases shifted by 90 degree.
* </PRE>
*/
#define MOVEX(x) ((((x) < 0) ? MY2 : ((x) > 0) ? MY1 : 0))
#define MOVEY(y) ((((y) < 0) ? MX2 : ((y) > 0) ? MX1 : 0))
#define SIGN(a) ((a) < 0 ? -1 : (a) > 0 ? 1 : 0)
/**
* @brief return the mouse motion flags
*
* Advance the mouse x and y coordinates to the dx and dy
* coordinates by either toggling MX2 or MX1 first for a
* y movement, or MY2 or MY1 for x movement.
* There are four read phases counted by m_mouse.phase
*
* @return lookup value from madr_a32
*/
UINT16 alto2_cpu_device::mouse_read()
{
UINT16 data;
m_mouse.latch = (m_mouse.latch << 1) & MLATCH;
data = m_madr_a32[m_mouse.latch];
switch (m_mouse.phase) {
case 0:
m_mouse.latch |= MOVEX(m_mouse.dx - m_mouse.x);
m_mouse.latch |= MOVEY(m_mouse.dy - m_mouse.y);
break;
case 1:
m_mouse.latch |= MACTIVE;
m_mouse.x -= SIGN(m_mouse.x - m_mouse.dx);
m_mouse.y -= SIGN(m_mouse.y - m_mouse.dy);
break;
case 2:
m_mouse.latch ^= MOVEX(m_mouse.dx - m_mouse.x);
m_mouse.latch ^= MOVEY(m_mouse.dy - m_mouse.y);
break;
default:
m_mouse.latch &= ~MACTIVE;
m_mouse.x -= SIGN(m_mouse.x - m_mouse.dx);
m_mouse.y -= SIGN(m_mouse.y - m_mouse.dy);
}
m_mouse.phase = (m_mouse.phase + 1) % 4;
return data;
}
/**
* @brief register a mouse motion in x direction
* @param ioport_field reference to the field
* @param param pointer passed in PORT_CHANGED_MEMBER last parameter
* @param oldval the old ioport_value
* @param newval the new ioport_value
*/
INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_motion_x )
{
// set new destination (absolute) mouse x coordinate
INT32 x = m_mouse.dx + newval - oldval;
x = x < 0 ? 0 : x > 605 ? 605 : x;
m_mouse.dx = x;
#if MOUSE_DIRTY_HACK
/* XXX: dirty, dirty, hack */
#if USE_HAMMING_CHECK
m_mem.ram[0424/2] = hamming_code(1, 0424 / 2, (m_mouse.dx << 16) | m_mouse.dy);
#else
m_mem.ram[0424/2] = (m_mouse.dx << 16) | m_mouse.dy;
#endif
#endif
}
/**
* @brief register a mouse motion in y direction
* @param ioport_field reference to the field
* @param param pointer passed in PORT_CHANGED_MEMBER last parameter
* @param oldval the old ioport_value
* @param newval the new ioport_value
*/
INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_motion_y )
{
// set new destination (absolute) mouse y coordinate
INT32 y = m_mouse.dy + newval - oldval;
y = y < 0 ? 0 : y > 807 ? 807 : y;
m_mouse.dy = y;
#if MOUSE_DIRTY_HACK
/* XXX: dirty, dirty, hack */
#if USE_HAMMING_CHECK
m_mem.ram[0424/2] = hamming_code(1, 0424 / 2, (m_mouse.dx << 16) | m_mouse.dy);
#else
m_mem.ram[0424/2] = (m_mouse.dx << 16) | m_mouse.dy;
#endif
#endif
}
/**
* @brief register a mouse button change
*
* convert button bit to UTILIN[13-15]
*
* @param ioport_field reference to the field
* @param param pointer passed in PORT_CHANGED_MEMBER last parameter
* @param oldval the old ioport_value
* @param newval the new ioport_value
*/
INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_button_0 )
{
X_WRBITS(m_hw.utilin,16,13,13,newval);
}
INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_button_1 )
{
X_WRBITS(m_hw.utilin,16,14,14,newval);
}
INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_button_2 )
{
X_WRBITS(m_hw.utilin,16,15,15,newval);
}
static const prom_load_t pl_madr_a32 =
{
"madr.a32",
0,
"a0e3b4a7",
"24e50afdeb637a6a8588f8d3a3493c9188b8da2c",
/* size */ 0400,
/* amap */ AMAP_DEFAULT,
/* axor */ 0,
/* dxor */ 017, // invert D0-D3
/* width */ 4,
/* shift */ 0,
/* dmap */ DMAP_REVERSE_0_3, // reverse D0-D3 to D3-D0
/* dand */ ZERO,
/* type */ sizeof(UINT8)
};
/**
* @brief initialize the mouse context to useful values
*
* From the Alto Hardware Manual:
* <PRE>
* The mouse is a hand-held pointing device which contains two encoders
* which digitize its position as it is rolled over a table-top. It also
* has three buttons which may be read as the three low order bits of
* memory location UTILIN (0177030), iin the manner of the keyboard.
* The bit/button correspondence in UTILIN are (depressed keys
* correspond to 0's in memory):
*
* UTILIN[13] TOP or LEFT button (RED)
* UTILIN[14] BOTTOM or RIGHT button (BLUE)
* UTILIN[15] MIDDLE button (YELLOW)
*
* The mouse coordinates are maintained by the MRT microcode in locations
* MOUSELOC(0424)=X and MOUSELOC+1(0425)=Y in page one of the Alto memory.
* These coordinates are relative, i.e., the hardware only increments and
* decrements them. The resolution of the mouse is approximately 100 points
* per inch.
* </PRE>
*/
void alto2_cpu_device::init_mouse()
{
memset(&m_mouse, 0, sizeof(m_mouse));
m_madr_a32 = prom_load(machine(), &pl_madr_a32, memregion("madr_a32")->base());
}
void alto2_cpu_device::exit_mouse()
{
// nothing to do yet
}
void alto2_cpu_device::reset_mouse()
{
m_mouse.x = 0;
m_mouse.y = 0;
m_mouse.dx = 0;
m_mouse.dy = 0;
m_mouse.latch = 0;
m_mouse.phase = 0;
}

View File

@ -0,0 +1,73 @@
/*****************************************************************************
*
* Xerox AltoII mouse hardware (MOUSE)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2MOUSE_H_
#define _A2MOUSE_H_
/**
* @brief PROM madr.a32 contains a lookup table to translate mouse motions
*
* <PRE>
* The 4 mouse motion signals MX1, MX2, MY1, and MY2 are connected
* to a 256x4 PROM's (3601, SN74387) address lines A0, A2, A4, and A6.
* The previous (latched) state of the 4 signals is connected to the
* address lines A1, A3, A5, and A7.
*
* SN74387
* +---+--+---+
* | +--+ |
* MY2 A6 -|1 16|- Vcc
* | |
* LMY1 A5 -|2 15|- A7 LMY2
* | |
* MY1 A4 -|3 14|- FE1' 0
* | |
* LMX2 A3 -|4 13|- FE2' 0
* | |
* MX1 A0 -|5 12|- D0 BUS[12]
* | |
* LMX1 A1 -|6 11|- D1 BUS[13]
* | |
* MX2 A2 -|7 10|- D2 BUS[14]
* | |
* GND -|8 9|- D3 BUS[15]
* | |
* +----------+
*
* A motion to the west will first toggle MX2, then MX1.
* sequence: 04 -> 0d -> 0b -> 02
* A motion to the east will first toggle MX1, then MX2.
* sequence: 01 -> 07 -> 0e -> 08
*
* A motion to the north will first toggle MY2, then MY1.
* sequence: 40 -> d0 -> b0 -> 20
* A motion to the south will first toggle MY1, then MY2.
* sequence: 10 -> 70 -> e0 -> 80
* </PRE>
*/
UINT8* m_madr_a32;
//! mouse context
struct {
int x; //!< current X coordinate
int y; //!< current Y coordinate
int dx; //!< destination X coordinate (real mouse X)
int dy; //!< destination Y coordinate (real mouse Y)
UINT8 latch; //!< current latch value
UINT8 phase; //!< current read latch phase
} m_mouse;
UINT16 mouse_read(); //!< return the mouse motion flags
void init_mouse(); //!< initialize the mouse context
void exit_mouse(); //!< deinitialize the mouse context
void reset_mouse(); //!< reset the mouse context
#endif // _A2MOUSE_H_
#endif // ALTO2_DEFINE_CONSTANTS

47
src/emu/cpu/alto2/a2mrt.c Normal file
View File

@ -0,0 +1,47 @@
/*****************************************************************************
*
* Xerox AltoII memory refresh task
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
//! f1_mrt_block early: block the display word task
void alto2_cpu_device::f1_early_mrt_block()
{
/* clear the wakeup for the memory refresh task */
m_task_wakeup &= ~(1 << m_task);
LOG((LOG_MRT,2," BLOCK %s\n", task_name(m_task)));
}
//! called by the CPU when MRT becomes active
void alto2_cpu_device::activate_mrt()
{
m_task_wakeup &= ~(1 << m_task);
if (m_ewfct)
{
// The Ether task wants a wakeup, too
m_task_wakeup |= 1 << task_ether;
}
}
//! memory refresh task slots initialization
void alto2_cpu_device::init_mrt(int task)
{
set_f1(task, f1_block, &alto2_cpu_device::f1_early_mrt_block, 0);
/* auto block */
m_active_callback[task] = &alto2_cpu_device::activate_mrt;
}
void alto2_cpu_device::exit_mrt()
{
// nothing to do yet
}
void alto2_cpu_device::reset_mrt()
{
// nothing to do yet
}

21
src/emu/cpu/alto2/a2mrt.h Normal file
View File

@ -0,0 +1,21 @@
/*****************************************************************************
*
* Xerox AltoII memory refresh task (MRT)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2MRT_H_
#define _A2MRT_H_
void f1_early_mrt_block(); //!< F1 func: block the display word task
void activate_mrt(); //!< called by the CPU when MRT becomes active
void init_mrt(int task = task_mrt); //!< initialize the memory refresh task
void exit_mrt(); //!< deinitialize the memory refresh task
void reset_mrt(); //!< reset the memory refresh task
#endif // _A2MRT_H_
#endif // ALTO2_DEFINE_CONSTANTS

View File

@ -0,0 +1,32 @@
/*****************************************************************************
*
* Xerox AltoII parity task
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
//! called by the CPU when the parity task becomes active
void alto2_cpu_device::activate_part()
{
m_task_wakeup &= ~(1 << m_task);
}
//! parity task slots initialization
void alto2_cpu_device::init_part(int task)
{
m_active_callback[task] = &alto2_cpu_device::activate_part;
}
void alto2_cpu_device::exit_part()
{
// nothing to do yet
}
void alto2_cpu_device::reset_part()
{
// nothing to do yet
}

View File

@ -0,0 +1,20 @@
/*****************************************************************************
*
* Xerox AltoII parity task (PART)
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2PART_H_
#define _A2PART_H_
void activate_part();
void init_part(int task = task_part); //!< initialize the parity task
void exit_part(); //!< deinitialize the parity task
void reset_part(); //!< reset the parity task
#endif // _A2PART_H_
#endif // ALTO2_DEFINE_CONSTANTS

440
src/emu/cpu/alto2/a2ram.c Normal file
View File

@ -0,0 +1,440 @@
/*****************************************************************************
*
* Xerox AltoII RAM related functions
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
#define DEBUG_WRTRAM 0 //!< define to 1 to printf disassembled CRAM writes
//! direct read access to the microcode CRAM
#define RD_CRAM(addr) (*reinterpret_cast<UINT32 *>(m_ucode_cram + addr * 4))
//! direct write access to the microcode CRAM
#define WR_CRAM(addr,data) do { \
*reinterpret_cast<UINT32 *>(m_ucode_cram + addr * 4) = data; \
} while (0)
/**
* @brief read the microcode ROM/RAM halfword
*
* Note: HALFSEL is selecting the even (0) or odd (1) half of the
* microcode RAM 32-bit word. Here's how the demultiplexers (74298)
* u8, u18, u28 and u38 select the bits:
*
* SN74298
* +---+-+---+
* | +-+ |
* B2 -|1 16|- Vcc
* | |
* A2 -|2 15|- QA
* | |
* A1 -|3 14|- QB
* | |
* B1 -|4 13|- QC
* | |
* C2 -|5 12|- QD
* | |
* D2 -|6 11|- CLK
* | |
* D1 -|7 10|- SEL
* | |
* GND -|8 9|- C1
* | |
* +---------+
*
* chip out pin BUS in pin HSEL=0 in pin HSEL=1
* --------------------------------------------------------------
* u8 QA 15 0 A1 3 DRSEL(0)' A2 2 DF2(0)
* u8 QB 14 1 B1 4 DRSEL(1)' B2 1 DF2(1)'
* u8 QC 13 2 C1 9 DRSEL(2)' C2 5 DF2(2)'
* u8 QD 12 3 D1 7 DRSEL(3)' D2 6 DF2(3)'
*
* u18 QA 15 4 A1 3 DRSEL(4)' A2 2 LOADT'
* u18 QB 14 5 B1 4 DALUF(0)' B2 1 LOADL
* u18 QC 13 6 C1 9 DALUF(1)' C2 5 NEXT(00)'
* u18 QD 12 7 D1 7 DALUF(2)' D2 6 NEXT(01)'
*
* u28 QA 15 8 A1 3 DALUF(3)' A2 2 NEXT(02)'
* u28 QB 14 9 B1 4 DBS(0)' B2 1 NEXT(03)'
* u28 QC 13 10 C1 9 DBS(1)' C2 5 NEXT(04)'
* u28 QD 12 11 D1 7 DBS(2)' D2 6 NEXT(05)'
*
* u38 QA 15 12 A1 3 DF1(0) A2 2 NEXT(06)'
* u38 QB 14 13 B1 4 DF1(1)' B2 1 NEXT(07)'
* u38 QC 13 14 C1 9 DF1(2)' C2 5 NEXT(08)'
* u38 QD 12 15 D1 7 DF1(3)' D2 6 NEXT(09)'
*
* The HALFSEL signal to the demultiplexers is the inverted bit BUS(5):
* BUS(5)=1, HALFSEL=0, A1,B1,C1,D1 inputs, upper half of the 32-bit word
* BUS(5)=0, HALFSEL=1, A2,B2,C2,D2 inputs, lower half of the 32-bit word
*/
void alto2_cpu_device::rdram()
{
UINT32 addr, value;
UINT32 bank = GET_CRAM_BANKSEL(m_cram_addr);
UINT32 wordaddr = GET_CRAM_WORDADDR(m_cram_addr);
if (GET_CRAM_RAMROM(m_cram_addr)) {
/* read CROM 0 at current mpc */
addr = m_mpc & ALTO2_UCODE_PAGE_MASK;
LOG((LOG_CPU,0," rdram: ROM [%05o] ", addr));
} else {
/* read CRAM[bank] */
addr = bank * ALTO2_UCODE_PAGE_SIZE + wordaddr;
LOG((LOG_CPU,0," rdram: RAM%d [%04o] ", bank, wordaddr));
}
m_rdram_flag = false;
if (ALTO2_UCODE_RAM_BASE + addr >= ALTO2_UCODE_SIZE) {
value = 0177777; /* ??? */
LOG((LOG_CPU,0,"invalid address (%06o)\n", addr));
return;
}
value = RD_CRAM(addr) ^ ALTO2_UCODE_INVERTED;
if (GET_CRAM_HALFSEL(m_cram_addr)) {
value = value >> 16;
LOG((LOG_CPU,0,"upper:%06o\n", value & 0177777));
} else {
LOG((LOG_CPU,0,"lower:%06o\n", value & 0177777));
}
m_bus &= value;
}
/**
* @brief write the microcode RAM from M register and ALU
*
* Note: M is a latch (MYL, i.e. memory L) on the CRAM board that latches
* the ALU whenever LOADL and GOODTASK are met. GOODTASK is the Emulator
* task and something I have not yet found out about: TASKA' and TASKB'.
*
* There's also an undumped PROM u21 which is addressed by GOODTASK and
* 7 other signals...
*/
void alto2_cpu_device::wrtram()
{
UINT32 bank = GET_CRAM_BANKSEL(m_cram_addr);
UINT32 wordaddr = GET_CRAM_WORDADDR(m_cram_addr);
UINT32 value = ((m_m << 16) | m_alu) ^ ALTO2_UCODE_INVERTED;
UINT32 addr = bank * ALTO2_UCODE_PAGE_SIZE + wordaddr; // write RAM 0,1,2
LOG((LOG_CPU,0," wrtram: RAM%d [%04o] upper:%06o lower:%06o", bank, wordaddr, m_m, m_alu));
#if DEBUG_WRTRAM
char buff[128];
UINT8 oprom[4];
oprom[0] = m_m / 256;
oprom[1] = m_m % 256;
oprom[2] = m_m / 256;
oprom[3] = m_m % 256;
disasm_disassemble(buff, addr, oprom, oprom, 0);
printf("WR CRAM_BANKSEL=%d RAM%d [%04o] upper:%06o lower:%06o *** %s\n",
GET_CRAM_BANKSEL(m_cram_addr), bank, wordaddr, m_m, m_alu, buff);
#endif
m_wrtram_flag = false;
if (ALTO2_UCODE_RAM_BASE + addr >= ALTO2_UCODE_SIZE) {
LOG((LOG_CPU,0," invalid address %06o\n", addr));
return;
}
LOG((LOG_CPU,0,"\n"));
WR_CRAM(addr, value);
}
/**
* @brief bs_read_sreg early: drive bus by S register or M (MYL), if rsel is = 0
*
* Note: RSEL == 0 can't be read, because it is decoded as
* access to the M register (MYL latch access, LREF' in the schematics)
*/
void alto2_cpu_device::bs_early_read_sreg()
{
UINT16 r;
if (m_d_rsel) {
UINT8 bank = m_s_reg_bank[m_task];
r = m_s[bank][m_d_rsel];
LOG((LOG_RAM,2," <-S%02o; bus &= S[%o][%02o] (%#o)\n", m_d_rsel, bank, m_d_rsel, r));
} else {
r = m_m;
LOG((LOG_RAM,2," <-S%02o; bus &= M (%#o)\n", m_d_rsel, r));
}
m_bus &= r;
}
/**
* @brief bs_load_sreg early: load S register puts garbage on the bus
*/
void alto2_cpu_device::bs_early_load_sreg()
{
int r = 0; /* ??? */
LOG((LOG_RAM,2," S%02o<- BUS &= garbage (%#o)\n", m_d_rsel, r));
m_bus &= r;
}
/**
* @brief bs_load_sreg late: load S register from M
*/
void alto2_cpu_device::bs_late_load_sreg()
{
UINT8 bank = m_s_reg_bank[m_task];
m_s[bank][m_d_rsel] = m_m;
LOG((LOG_RAM,2," S%02o<- S[%o][%02o] := %#o\n", m_d_rsel, bank, m_d_rsel, m_m));
}
/**
* @brief branch to ROM page
*/
void alto2_cpu_device::branch_ROM(const char *from, int page)
{
(void)from;
m_next2 = (m_next2 & ALTO2_UCODE_PAGE_MASK) + page * ALTO2_UCODE_PAGE_SIZE;
LOG((LOG_RAM,2," SWMODE: branch from %s to ROM%d (%#o)\n", from, page, m_next2));
}
/**
* @brief branch to RAM page
*/
void alto2_cpu_device::branch_RAM(const char *from, int page)
{
(void)from;
m_next2 = (m_next2 & ALTO2_UCODE_PAGE_MASK) + ALTO2_UCODE_RAM_BASE + page * ALTO2_UCODE_PAGE_SIZE;
LOG((LOG_RAM,2," SWMODE: branch from %s to RAM%d\n", from, page, m_next2));
}
/**
* @brief f1_swmode early: switch to micro program counter BUS[6-15] in other bank
*
* Note: Jumping to uninitialized CRAM
*
* When jumping to uninitialized RAM, which, because of the inverted bits of the
* microcode words F1(0), F2(0) and LOADL, it is then read as F1=010 (SWMODE),
* F2=010 (BUSODD) and LOADL=1, loading the M register (MYL latch), too.
* This causes control to go back to the Emulator task at 0, because the
* NEXT[0-9] of uninitialized RAM is 0.
*
*/
void alto2_cpu_device::f1_late_swmode()
{
/* currently executing in what page? */
UINT16 current = m_mpc / ALTO2_UCODE_PAGE_SIZE;
#if (ALTO2_UCODE_ROM_PAGES == 1 && ALTO2_UCODE_RAM_PAGES == 1)
switch (current) {
case 0:
branch_RAM("ROM0", 0);
break;
case 1:
branch_ROM("RAM0", 0);
break;
default:
fatal(1, "Impossible current mpc %d\n", current);
}
#endif
#if (ALTO2_UCODE_ROM_PAGES == 2 && ALTO2_UCODE_RAM_PAGES == 1)
UINT16 next = X_RDBITS(m_next2,10,1,1);
switch (current) {
case 0: /* ROM0 to RAM0 or ROM1 */
switch (next) {
case 0:
branch_RAM("ROM0", 0);
break;
case 1:
branch_ROM("ROM0", 1);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
case 1: /* ROM1 to ROM0 or RAM0 */
switch (next) {
case 0:
branch_ROM("ROM1", 0);
break;
case 1:
branch_RAM("ROM1", 0);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
case 2: /* RAM0 to ROM0 or ROM1 */
switch (next) {
case 0:
branch_ROM("RAM0", 0);
break;
case 1:
branch_ROM("RAM0", 1);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
default:
fatal(1, "Impossible current mpc %d\n", current);
}
#endif
#if (ALTO2_UCODE_ROM_PAGES == 1 && ALTO2_UCODE_RAM_PAGES == 3)
UINT16 next = X_RDBITS(m_next2,10,1,2);
switch (current) {
case 0: /* ROM0 to RAM0, RAM2, RAM1, RAM0 */
switch (next) {
case 0:
branch_RAM("ROM0", 0);
break;
case 1:
branch_RAM("ROM0", 2);
break;
case 2:
branch_RAM("ROM0", 1);
break;
case 3:
branch_RAM("ROM0", 0);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
case 1: /* RAM0 to ROM0, RAM2, RAM1, RAM1 */
switch (next) {
case 0:
branch_ROM("RAM0", 0);
break;
case 1:
branch_RAM("RAM0", 2);
break;
case 2:
branch_RAM("RAM0", 1);
break;
case 3:
branch_RAM("RAM0", 1);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
case 2: /* RAM1 to ROM0, RAM2, RAM0, RAM0 */
switch (next) {
case 0:
branch_ROM("RAM1", 0);
break;
case 1:
branch_RAM("RAM1", 2);
break;
case 2:
branch_RAM("RAM1", 0);
break;
case 3:
branch_RAM("RAM1", 0);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
case 3: /* RAM2 to ROM0, RAM1, RAM0, RAM0 */
switch (next) {
case 0:
branch_ROM("RAM2", 0);
break;
case 1:
branch_RAM("RAM2", 1);
break;
case 2:
branch_RAM("RAM2", 0);
break;
case 3:
branch_RAM("RAM2", 0);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
default:
fatal(1, "Impossible current mpc %d\n", current);
}
#else
fatal(1, "Impossible control ROM/RAM combination %d/%d\n", ALTO2_UCODE_ROM_PAGES, ALTO2_UCODE_RAM_PAGES);
#endif
}
/**
* @brief f1_wrtram late: start WRTRAM cycle
*/
void alto2_cpu_device::f1_late_wrtram()
{
m_wrtram_flag = true;
LOG((LOG_RAM,2," WRTRAM\n"));
}
/**
* @brief f1_rdram late: start RDRAM cycle
*/
void alto2_cpu_device::f1_late_rdram()
{
m_rdram_flag = true;
LOG((LOG_RAM,2," RDRAM\n"));
}
#if (ALTO2_UCODE_RAM_PAGES == 3)
/**
* @brief f1_load_rmr late: load the reset mode register
*
* F1=013 corresponds to RMR<- in the emulator. In Altos with the 3K
* RAM option, F1=013 performs RMR<- in all RAM-related tasks, including
* the emulator.
*/
void alto2_cpu_device::f1_late_load_rmr()
{
LOG((LOG_RAM,2," RMR<-; BUS (%#o)\n", m_bus));
m_reset_mode = m_bus;
}
#else // ALTO2_UCODE_RAM_PAGES != 3
/**
* @brief f1_load_srb late: load the S register bank from BUS[12-14]
*/
void alto2_cpu_device::f1_late_load_srb()
{
m_s_reg_bank[m_task] = X_RDBITS(m_bus,16,12,14) % ALTO2_SREG_BANKS;
LOG((LOG_RAM,2," SRB<-; srb[%d] := %#o\n", m_task, m_s_reg_bank[m_task]));
}
#endif
/**
* @brief RAM related task slots initialization
*/
void alto2_cpu_device::init_ram(int task)
{
m_ram_related[task] = true;
set_bs(task, bs_ram_read_slocation, &alto2_cpu_device::bs_early_read_sreg, 0);
set_bs(task, bs_ram_load_slocation, &alto2_cpu_device::bs_early_load_sreg, &alto2_cpu_device::bs_late_load_sreg);
set_f1(task, f1_ram_swmode, 0, &alto2_cpu_device::f1_late_swmode);
set_f1(task, f1_ram_wrtram, 0, &alto2_cpu_device::f1_late_wrtram);
set_f1(task, f1_ram_rdram, 0, &alto2_cpu_device::f1_late_rdram);
#if (ALTO2_UCODE_RAM_PAGES == 3)
set_f1(task, f1_ram_load_rmr, 0, &alto2_cpu_device::f1_late_load_rmr);
#else // ALTO2_UCODE_RAM_PAGES != 3
set_f1(task, f1_ram_load_srb, 0, &alto2_cpu_device::f1_late_load_srb);
#endif
}
void alto2_cpu_device::exit_ram()
{
// nothing to do yet
}
void alto2_cpu_device::reset_ram()
{
m_rdram_flag = false;
m_wrtram_flag = false;
m_m = 0;
memset(m_s, 0, sizeof(m_s));
}

80
src/emu/cpu/alto2/a2ram.h Normal file
View File

@ -0,0 +1,80 @@
/*****************************************************************************
*
* Xerox AltoII RAM related tasks
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#if (ALTO2_CRAM_CONFIG==1)
#define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages
#define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages
#elif (ALTO2_CRAM_CONFIG==2)
#define ALTO2_UCODE_ROM_PAGES 2 //!< number of microcode ROM pages
#define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages
#elif (ALTO2_CRAM_CONFIG==3)
#define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages
#define ALTO2_UCODE_RAM_PAGES 3 //!< number of microcode RAM pages
#else
#error "Undefined CROM/CRAM configuration"
#endif
/**
* \brief number of S register banks
* This depends on the number of RAM pages
* 8 pages in 3K CRAM configuration
* 1 page in 1K CRAM configurations
*/
#if (ALTO2_UCODE_RAM_PAGES == 3)
#define ALTO2_SREG_BANKS 8
#else
#define ALTO2_SREG_BANKS 1
#endif
#define ALTO2_UCODE_PAGE_SIZE 02000 //!< number of words of microcode
#define ALTO2_UCODE_PAGE_MASK (ALTO2_UCODE_PAGE_SIZE-1) //!< mask for microcode ROM/RAM address
#define ALTO2_UCODE_SIZE ((ALTO2_UCODE_ROM_PAGES + ALTO2_UCODE_RAM_PAGES) * ALTO2_UCODE_PAGE_SIZE) //!< total number of words of microcode
#define ALTO2_UCODE_RAM_BASE (ALTO2_UCODE_ROM_PAGES * ALTO2_UCODE_PAGE_SIZE) //!< base offset for the RAM page(s)
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2RAM_H_
#define _A2RAM_H_
//! BUS source for RAM related tasks
enum {
bs_ram_read_slocation= bs_task_3, //!< ram related: read S register
bs_ram_load_slocation= bs_task_4 //!< ram related: load S register
};
//!< F1 functions for RAM related tasks
enum {
f1_ram_swmode = f1_task_10, //!< f1 10: switch mode to CROM/CRAM in same page
f1_ram_wrtram = f1_task_11, //!< f1 11: start WRTRAM cycle
f1_ram_rdram = f1_task_12, //!< f1 12: start RDRAM cycle
#if (ALTO2_UCODE_RAM_PAGES == 3)
f1_ram_load_rmr = f1_task_13, //!< f1 13: load the reset mode register
#else // ALTO2_UCODE_RAM_PAGES != 3
f1_ram_load_srb = f1_task_13 //!< f1 14: load the S register bank from BUS[12-14]
#endif
};
void bs_early_read_sreg(); //!< bus source: drive bus by S register or M (MYL), if rsel is = 0
void bs_early_load_sreg(); //!< bus source: load S register puts garbage on the bus
void bs_late_load_sreg(); //!< bus source: load S register from M
void branch_ROM(const char *from, int page); //!< branch to ROM page
void branch_RAM(const char *from, int page); //!< branch to RAM page
void f1_late_swmode(); //!< F1 func: switch to micro program counter BUS[6-15] in other bank
void f1_late_wrtram(); //!< F1 func: start WRTRAM cycle
void f1_late_rdram(); //!< F1 func: start RDRAM cycle
#if (ALTO2_UCODE_RAM_PAGES == 3)
void f1_late_load_rmr(); //!< F1 func: load the reset mode register
#else // ALTO2_UCODE_RAM_PAGES != 3
void f1_late_load_srb(); //!< F1 func: load the S register bank from BUS[12-14]
#endif
void init_ram(int task); //!< called by RAM related tasks
void exit_ram(); //!< deinitialize the RAM related tasks
void reset_ram(); //!< reset the RAM related tasks
#endif // A2RAM_H
#endif // ALTO2_DEFINE_CONSTANTS

198
src/emu/cpu/alto2/a2roms.c Normal file
View File

@ -0,0 +1,198 @@
/*****************************************************************************
*
* Xerox AltoII PROM loading and decoding
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#include "alto2cpu.h"
#include "a2roms.h"
#define DEBUG_PROM_LOAD 0 //!< define to 1 to dump PROMs after loading
/**
* @brief return number of 1 bits in a 32 bit value
*
* 32-bit recursive reduction using SWAR,
* but first step is mapping 2-bit values
* into sum of 2 1-bit values in sneaky way.
*/
static UINT32 ones_u32(UINT32 val)
{
val -= ((val >> 1) & 0x55555555);
val = (((val >> 2) & 0x33333333) + (val & 0x33333333));
val = (((val >> 4) + val) & 0x0f0f0f0f);
val += (val >> 8);
val += (val >> 16);
return (val & 0x0000003f);
}
/**
* @brief return the log2 of an integer value
*/
static UINT32 log2_u32(UINT32 val)
{
val |= (val >> 1);
val |= (val >> 2);
val |= (val >> 4);
val |= (val >> 8);
val |= (val >> 16);
return ones_u32(val >> 1);
}
/**
* @brief map a number of data or address lines using a lookup table
*
* @param map pointer to an array of values, or NULL for default
* @param lines number of data or address lines
* @param val value to map
* @result returns the remapped value, or just val, if map was NULL
*/
static UINT32 map_lines(const UINT8 *map, int lines, UINT32 val)
{
if (NULL == map)
return val;
UINT32 res = 0;
for (int i = 0; i < lines; i++)
if (val & (1 << i))
res |= 1 << map[i];
return res;
}
/**
* @brief write to a ROM base + address of type 'type', ANDing with and, ORing with or
*
* @param base ROM base address in memory
* @param type one of 1 for UINT8, 2 for UINT16, 4 for UINT32
* @param addr address offset into base
* @param dand value to AND to contents before XORing
* @param dxor value to XOR before writing back
*/
static void write_type_and_xor(void *base, int type, UINT32 addr, UINT32 dand, UINT32 dxor)
{
switch (type) {
case sizeof(UINT8):
{
UINT8 *base8 = reinterpret_cast<UINT8 *>(base);
base8[addr] = (base8[addr] & dand) ^ dxor;
}
break;
case sizeof(UINT16):
{
UINT16 *base16 = reinterpret_cast<UINT16 *>(base);
base16[addr] = (base16[addr] & dand) ^ dxor;
}
break;
case sizeof(UINT32):
{
UINT32 *base32 = reinterpret_cast<UINT32 *>(base);
base32[addr] = (base32[addr] & dand) ^ dxor;
}
break;
default:
fatalerror("write_type_and_xor() invalid type size (%d) in ROM definitions\n", type);
}
}
/**
* @brief load a PROM from a (list of) source region(s) shifting, swapping and inverting address and data bits
* @param prom PROM loading definition
* @param src source ROM region where to load data from
* @param pages number of pages of definitions
* @param segments number of segments in one page of the result
* @return pointer to the newly allocated memory filled with source bits
*/
UINT8* prom_load(running_machine& machine, const prom_load_t* prom, const UINT8* src, int pages, int segments)
{
void* array = 0;
size_t type = prom->type;
size_t size = prom->size;
#if DEBUG_PROM_LOAD
UINT8 width = prom->width;
#endif
switch (type) {
case sizeof(UINT8):
array = auto_alloc_array(machine, UINT8, pages * size);
break;
case sizeof(UINT16):
array = auto_alloc_array(machine, UINT16, pages * size);
break;
case sizeof(UINT32):
array = auto_alloc_array(machine, UINT32, pages * size);
break;
}
UINT8* dst = reinterpret_cast<UINT8*>(array);
for (int page = 0; page < pages; page++)
{
for (int segment = 0; segment < segments; segment++, prom++)
{
for (UINT32 src_addr = 0; src_addr < prom->size; src_addr++)
{
// map destination address lines
UINT32 dst_addr = map_lines(prom->amap, log2_u32(prom->size) + 1, src_addr);
// fetch data bits
UINT32 data = src[src_addr ^ prom->axor] ^ prom->dxor;
// mask width bits
data = data & ((1 << prom->width) - 1);
// map destination data lines
data = map_lines(prom->dmap, prom->width, data);
// shift to destination position
data = data << prom->shift;
// and destination width dand then xor data
write_type_and_xor(dst, prom->type, dst_addr, prom->dand, data);
}
src += prom->size;
}
dst += prom->type * prom->size;
}
#if DEBUG_PROM_LOAD
switch (type) {
case sizeof(UINT8):
{
UINT8* data = reinterpret_cast<UINT8*>(array);
for (int addr = 0; addr < pages*size; addr++) {
if (0 == (addr % 16))
printf("%04x:", addr);
if (width <= 4)
printf(" %x", data[addr]);
else
printf(" %02x", data[addr]);
if (15 == (addr % 16))
printf("\n");
}
}
break;
case sizeof(UINT16):
{
UINT16* data = reinterpret_cast<UINT16*>(array);
for (int addr = 0; addr < pages*size; addr++) {
if (0 == (addr % 8))
printf("%04x:", addr);
printf(" %04x", data[addr]);
if (7 == (addr % 8))
printf("\n");
}
}
break;
case sizeof(UINT32):
{
UINT32* data = reinterpret_cast<UINT32*>(array);
for (int addr = 0; addr < pages*size; addr++) {
if (0 == (addr % 4))
printf("%04x:", addr);
printf(" %08x", data[addr]);
if (3 == (addr % 4))
printf("\n");
}
}
break;
}
#endif
return reinterpret_cast<UINT8 *>(array);
}

View File

@ -0,0 +1,45 @@
/*****************************************************************************
*
* Xerox AltoII RAM PROM loading and decoding
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifndef _CPU_A2ROMS_H_
#define _CPU_A2ROMS_H_
#include "emu.h"
/**
* @brief structure to define a ROM's or PROM's loading options
*/
typedef struct {
const char *name; //!< default filename of the ROM image
const char *altname; //!< alternate filename of the ROM image
const char *crc32; //!< CRC32 hash of the file
const char *sha1; //!< SHA1 hash of the file
size_t size; //!< size of the file, and elements in destination memory
const UINT8 amap[16]; //!< address bit mapping
UINT32 axor; //!< address XOR mask (applied to source address)
UINT32 dxor; //!< data XOR mask (applied before shifting and mapping)
UINT8 width; //!< width in bits
UINT8 shift; //!< left shift in bits
const UINT8 dmap[16]; //!< data bit mapping
UINT32 dand; //!< ANDing destination with this value, before XORing the data
size_t type; //!< type of the destination, i.e. sizeof(type)
} prom_load_t;
#define ZERO 0
#define KEEP ~0
#define AMAP_DEFAULT {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
#define AMAP_CONST_PROM {3,2,1,4,5,6,7,0,}
#define AMAP_REVERSE_0_7 {7,6,5,4,3,2,1,0,}
#define DMAP_DEFAULT {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
#define DMAP_REVERSE_0_3 {3,2,1,0,}
extern UINT8* prom_load(running_machine& machine, const prom_load_t* prom, const UINT8* src, int pages = 1, int segments = 1);
#endif // _CPU_A2ROMS_H_

2814
src/emu/cpu/alto2/alto2cpu.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,948 @@
/*****************************************************************************
*
* Xerox AltoII CPU core interface
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
*
*****************************************************************************/
#ifndef _CPU_ALTO2_H_
#define _CPU_ALTO2_H
#define ALTO2_TAG "alto2"
#include "emu.h"
#include "debugger.h"
#include "machine/diablo_hd.h"
/**
* \brief AltoII register names
*/
enum {
// micro code task, micro program counter, next and next2
A2_TASK, A2_MPC, A2_NEXT, A2_NEXT2,
// BUS, ALU, temp, latch, memory latch and carry flags
A2_BUS, A2_T, A2_ALU, A2_ALUC0, A2_L, A2_SHIFTER, A2_LALUC0, A2_M,
A2_R, // 32 R registers
A2_AC3 = A2_R, A2_AC2, A2_AC1, A2_AC0, A2_R04, A2_R05, A2_PC, A2_R07,
A2_R10, A2_R11, A2_R12, A2_R13, A2_R14, A2_R15, A2_R16, A2_R17,
A2_R20, A2_R21, A2_R22, A2_R23, A2_R24, A2_R25, A2_R26, A2_R27,
A2_R30, A2_R31, A2_R32, A2_R33, A2_R34, A2_R35, A2_R36, A2_R37,
A2_S, // 32 S registers
A2_S00 = A2_S, A2_S01, A2_S02, A2_S03, A2_S04, A2_S05, A2_S06, A2_S07,
A2_S10, A2_S11, A2_S12, A2_S13, A2_S14, A2_S15, A2_S16, A2_S17,
A2_S20, A2_S21, A2_S22, A2_S23, A2_S24, A2_S25, A2_S26, A2_S27,
A2_S30, A2_S31, A2_S32, A2_S33, A2_S34, A2_S35, A2_S36, A2_S37,
// DISK controller registers
A2_DRIVE, A2_KADDR, A2_KADR, A2_KSTAT, A2_KCOM, A2_KRECNO,
A2_SHIFTIN, A2_SHIFTOUT, A2_DATAIN, A2_DATAOUT, A2_KRWC,
A2_KFER, A2_WDTSKENA, A2_WDINIT0, A2_WDINIT, A2_STROBE,
A2_BITCLK, A2_DATIN, A2_BITCNT, A2_CARRY, A2_SECLATE,
A2_SEEKOK, A2_OKTORUN, A2_READY
};
#ifndef ALTO2_DEBUG
#define ALTO2_DEBUG 1 //!< define to 1 to enable logerror() output
#endif
#ifndef ALTO2_CRAM_CONFIG
#define ALTO2_CRAM_CONFIG 2 //!< use default CROM/CRAM configuration 2
#endif
#define ALTO2_FAKE_STATUS_H 12 //!< number of extra scanlines to display some status info
#define USE_PRIO_F9318 0 //!< define to 1 to use the F9318 priority encoder code
#define USE_ALU_74181 1 //!< define to 1 to use the SN74181 ALU code
#define USE_BITCLK_TIMER 0 //!< define to 1 to use a very high rate timer for the disk bit clock
#define USE_HAMMING_CHECK 1 //!< define to 1 to use the Hamming code and Parity check in a2mem
#define ALTO2_TASKS 16 //!< 16 task slots
#define ALTO2_REGS 32 //!< 32 16-bit words in the R register file
#define ALTO2_ALUF 16 //!< 16 ALU functions (74181)
#define ALTO2_BUSSRC 8 //!< 8 bus sources
#define ALTO2_F1MAX 16 //!< 16 F1 functions
#define ALTO2_F2MAX 16 //!< 16 F2 functions
#define ALTO2_UCYCLE 169542 //!< time in pico seconds for a CPU micro cycle: 29.4912MHz/5 -> 5.898240Hz ~= 169.542ns/clock
#define ALTO2_CONST_SIZE 256 //!< number words in the constant ROM
//! inverted bits in the micro instruction 32 bit word
#define ALTO2_UCODE_INVERTED ((1 << 10) | (1 << 15) | (1 << 19))
/********************************************************************************
* Bit field primitives
* These are some macros to make it easier to access variable by the bit-
* reversed notation that the Xerox Alto documents use all over the place.
* Bit number 0 is the most significant there,
* and bit number (width - 1) is the least significant.
* The X_ is for Xerox and to avoid collisions with MAME generic macros.
********************************************************************************/
//! get the left shift required to access bit %to in a word of %width bits
#define X_BITSHIFT(width,to) ((width) - 1 - (to))
//! build a least significant bit mask for bits %from to %to (inclusive)
#define X_BITMASK(from,to) ((1ul << ((to) + 1 - (from))) - 1)
//! get a single bit number %bit value from %reg, a word of %width bits
#define X_BIT(reg,width,bit) (((reg) >> X_BITSHIFT(width,bit)) & 1)
//! get a bit field from %reg, a word of %width bits, starting at bit %from until bit %to
#define X_RDBITS(reg,width,from,to) (((reg) >> X_BITSHIFT(width,to)) & X_BITMASK(from,to))
//! put a value %val into %reg, a word of %width bits, starting at bit %from until bit %to
#define X_WRBITS(reg,width,from,to,val) do { \
UINT32 mask = X_BITMASK(from,to) << X_BITSHIFT(width,to); \
reg = ((reg) & ~mask) | (((val) << X_BITSHIFT(width,to)) & mask); \
} while (0)
#if ALTO2_DEBUG
enum LOG_TYPE_ENUM {
LOG_0,
LOG_CPU = (1 << 0),
LOG_EMU = (1 << 1),
LOG_T01 = (1 << 2),
LOG_T02 = (1 << 3),
LOG_T03 = (1 << 4),
LOG_KSEC = (1 << 5),
LOG_T05 = (1 << 6),
LOG_T06 = (1 << 7),
LOG_ETH = (1 << 8),
LOG_MRT = (1 << 9),
LOG_DWT = (1 << 10),
LOG_CURT = (1 << 11),
LOG_DHT = (1 << 12),
LOG_DVT = (1 << 13),
LOG_PART = (1 << 14),
LOG_KWD = (1 << 15),
LOG_T17 = (1 << 16),
LOG_MEM = (1 << 17),
LOG_RAM = (1 << 18),
LOG_DRIVE = (1 << 19),
LOG_DISK = (1 << 20),
LOG_DISPL = (1 << 21),
LOG_MOUSE = (1 << 22),
LOG_HW = (1 << 23),
LOG_KBD = (1 << 24),
LOG_ALL = ((1 << 25) - 1)
};
extern int m_log_types;
extern int m_log_level;
extern bool m_log_newline;
void logprintf(int type, int level, const char* format, ...);
# define LOG(x) logprintf x
#else
# define LOG(x)
#endif
//*******************************************
// define constants from the sub-devices
//*******************************************
#define ALTO2_DEFINE_CONSTANTS 1
#include "a2jkff.h"
#include "a2ram.h"
#include "a2hw.h"
#include "a2kbd.h"
#include "a2mouse.h"
#include "a2disk.h"
#include "a2disp.h"
#include "a2mem.h"
#include "a2emu.h"
#include "a2ksec.h"
#include "a2ether.h"
#include "a2mrt.h"
#include "a2dwt.h"
#include "a2curt.h"
#include "a2dht.h"
#include "a2dvt.h"
#include "a2part.h"
#include "a2dwt.h"
#include "a2kwd.h"
#undef ALTO2_DEFINE_CONSTANTS
class alto2_cpu_device : public cpu_device
{
public:
// construction/destruction
alto2_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
~alto2_cpu_device();
//! driver interface to set diablo_hd_device
void set_diablo(int unit, diablo_hd_device* ptr);
//! call in for the next sector callback
void next_sector(int unit);
//! update the screen bitmap
UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
//! screen VBLANK handler
void screen_eof(screen_device &screen, bool state);
DECLARE_ADDRESS_MAP( ucode_map, 32 );
DECLARE_ADDRESS_MAP( const_map, 16 );
DECLARE_ADDRESS_MAP( iomem_map, 16 );
//! register a mouse motion in x direction
DECLARE_INPUT_CHANGED_MEMBER( mouse_motion_x );
//! register a mouse motion in y direction
DECLARE_INPUT_CHANGED_MEMBER( mouse_motion_y );
//! register a mouse button change
DECLARE_INPUT_CHANGED_MEMBER( mouse_button_0 );
DECLARE_INPUT_CHANGED_MEMBER( mouse_button_1 );
DECLARE_INPUT_CHANGED_MEMBER( mouse_button_2 );
protected:
//! device-level override for start
virtual void device_start();
//! device-level override for reset
virtual void device_reset();
//! device-level override for post reset
void interface_post_reset();
//! device_execute_interface overrides
virtual UINT32 execute_min_cycles() const { return 1; }
virtual UINT32 execute_max_cycles() const { return 1; }
virtual UINT32 execute_input_lines() const { return 1; }
virtual void execute_run();
virtual void execute_set_input(int inputnum, int state);
//! device_memory_interface overrides
virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
//! device (P)ROMs
virtual const rom_entry *device_rom_region() const;
//! device_state_interface overrides
void state_string_export(const device_state_entry &entry, astring &string);
//! device_disasm_interface overrides
virtual UINT32 disasm_min_opcode_bytes() const { return 4; }
virtual UINT32 disasm_max_opcode_bytes() const { return 4; }
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
private:
void fatal(int level, const char *format, ...);
address_space_config m_ucode_config;
address_space_config m_const_config;
address_space_config m_iomem_config;
address_space* m_iomem;
UINT8* m_ucode_crom;
UINT8* m_ucode_cram;
UINT8* m_const_data;
//! read microcode CROM
DECLARE_READ32_MEMBER ( crom_r );
//! read microcode CRAM
DECLARE_READ32_MEMBER ( cram_r );
//! write microcode CRAM
DECLARE_WRITE32_MEMBER( cram_w );
//! read constants PROM
DECLARE_READ16_MEMBER ( const_r );
//! read i/o space RAM
DECLARE_READ16_MEMBER ( ioram_r );
//!< write i/o space RAM
DECLARE_WRITE16_MEMBER( ioram_w );
//!< read memory mapped i/o
DECLARE_READ16_MEMBER ( mmio_r );
//!< write memory mapped i/o
DECLARE_WRITE16_MEMBER( mmio_w );
int m_icount;
typedef void (alto2_cpu_device::*a2func)();
//! task numbers
enum {
task_emu, //!< emulator task
task_1, //!< unused
task_2, //!< unused
task_3, //!< unused
task_ksec, //!< disk sector task
task_5, //!< unused
task_6, //!< unused
task_ether, //!< ethernet task
task_mrt, //!< memory refresh task
task_dwt, //!< display word task
task_curt, //!< cursor task
task_dht, //!< display horizontal task
task_dvt, //!< display vertical task
task_part, //!< parity task
task_kwd, //!< disk word task
task_17 //!< unused task slot 017
};
//! register select values accessing R (Note: register numbers are octal)
enum {
rsel_ac3, //!< AC3 used by emulator as accu 3. Also used by Mesa emulator to keep bytecode to execute after breakpoint
rsel_ac2, //!< AC2 used by emulator as accu 2. Also used by Mesa emulator as x register for xfer
rsel_ac1, //!< AC1 used by emulator as accu 1. Also used by Mesa emulator as r-temporary for return indices and values
rsel_ac0, //!< AC0 used by emulator as accu 0. Also used by Mesa emulator as new field bits for WF and friends
rsel_r04, //!< NWW state of the interrupt system
rsel_r05, //!< SAD. Also used by Mesa emulator as scratch R-register for counting
rsel_pc, //!< PC used by emulator as program counter
rsel_r07, //!< XREG. Also used by Mesa emulator as task hole, i.e. pigeonhole for saving things across tasks.
rsel_r10, //!< XH. Also used by Mesa emulator as instruction byte register
rsel_r11, //!< CLOCKTEMP - used in the MRT
rsel_r12, //!< ECNTR remaining words in buffer - ETHERNET
rsel_r13, //!< EPNTR points BEFORE next word in buffer - ETHERNET
rsel_r14,
rsel_r15, //!< MPC. Used by the Mesa emulator as program counter
rsel_r16, //!< STKP. Used by the Mesa emulator as stack pointer [0-10] 0 empty, 10 full
rsel_r17, //!< XTSreg. Used by the Mesa emulator to xfer trap state
rsel_r20, //!< CURX. Holds cursor X; used by the cursor task
rsel_r21, //!< CURDATA. Holds the cursor data; used by the cursor task
rsel_r22, //!< CBA. Holds the address of the currently active DCB+1
rsel_r23, //!< AECL. Holds the address of the end of the current scanline's bitmap
rsel_r24, //!< SLC. Holds the number of scanlines remaining in currently active DCB
rsel_r25, //!< MTEMP. Holds the temporary cell
rsel_r26, //!< HTAB. Holds the number of tab words remaining on current scanline
rsel_r27, //!< YPOS
rsel_r30, //!< DWA. Holds the address of the bit map doubleword currently being fetched for transmission to the hardware buffer.
rsel_r31, //!< KWDCT. Used by the disk tasks as word counter
rsel_r32, //!< CKSUMR. Used by the disk tasks as checksum register (and *amble counter?)
rsel_r33, //!< KNMAR. Used by the disk tasks as transfer memory address register
rsel_r34, //!< DCBR. Used by the disk tasks to keep the current device control block
rsel_r35, //!< TEMP. Used by the Mesa emulator, and also by BITBLT
rsel_r36, //!< TEMP2. Used by the Mesa emulator, and also by BITBLT
rsel_r37 //!< CLOCKREG. Low order bits of the real time clock
};
//! ALU function numbers
enum {
/**
* \brief 00: ALU <- BUS
* PROM data for S3-0,M,C,T: 1111/1/0/0
* function F=A
* T source is ALU
*/
aluf_bus__alut,
/**
* \brief 01: ALU <- T
* PROM data for S3-0,M,C,T: 1010/1/0/0
* function F=B
* T source is BUS
*/
aluf_treg,
/**
* \brief 02: ALU <- BUS | T
* PROM data for S3-0,M,C,T: 1110/1/0/1
* function F=A|B
* T source is ALU
*/
aluf_bus_or_t__alut,
/**
* \brief 03: ALU <- BUS & T
* PROM data for S3-0,M,C,T: 1011/1/0/0
* function F=A&B
* T source is BUS
*/
aluf_bus_and_t,
/**
* \brief 04: ALU <- BUS ^ T
* PROM data for S3-0,M,C,T: 0110/1/0/0
* function F=A^B
* T source is BUS
*/
aluf_bus_xor_t,
/**
* \brief 05: ALU <- BUS + 1
* PROM data for S3-0,M,C,T: 0000/0/0/1
* function F=A+1
* T source is ALU
*/
aluf_bus_plus_1__alut,
/**
* \brief 06: ALU <- BUS - 1
* PROM data for S3-0,M,C,T: 1111/0/1/1
* function F=A-1
* T source is ALU
*/
aluf_bus_minus_1__alut,
/**
* \brief 07: ALU <- BUS + T
* PROM data for S3-0,M,C,T: 1001/0/1/0
* function F=A+B
* T source is BUS
*/
aluf_bus_plus_t,
/**
* \brief 10: ALU <- BUS - T
* PROM data for S3-0,M,C,T: 0110/0/0/0
* function F=A-B
* T source is BUS
*/
aluf_bus_minus_t,
/**
* \brief 11: ALU <- BUS - T - 1
* PROM data for S3-0,M,C,T: 0110/0/1/0
* function F=A-B-1
* T source is BUS
*/
aluf_bus_minus_t_minus_1,
/**
* \brief 12: ALU <- BUS + T + 1
* PROM data for S3-0,M,C: 1001/0/0
* function F=A+B+1
* T source is ALU
*/
aluf_bus_plus_t_plus_1__alut,
/**
* \brief 13: ALU <- BUS + SKIP
* PROM data for S3-0,M,C,T: 0000/0/SKIP/1
* function F=A (SKIP=1) or F=A+1 (SKIP=0)
* T source is ALU
*/
aluf_bus_plus_skip__alut,
/**
* \brief 14: ALU <- BUS & T
* PROM data for S3-0,M,C,T: 1011/1/0/1
* function F=A&B
* T source is ALU
*/
aluf_bus_and_t__alut,
/**
* \brief 15: ALU <- BUS & ~T
* PROM data for S3-0,M,C,T: 0111/1/0/0
* function F=A&~B
* T source is BUS
*/
aluf_bus_and_not_t,
/**
* \brief 16: ALU <- BUS
* PROM data for S3-0,M,C,T: 1111/1/0/1
* function F=A
* T source is ALU
*/
aluf_undef_16,
/**
* \brief 17: ALU <- BUS
* PROM data for S3-0,M,C,T: 1111/1/0/1
* function F=A
* T source is ALU
*/
aluf_undef_17
};
//! BUS source selection numbers
enum {
bs_read_r, //!< BUS source is R register
bs_load_r, //!< load R register from BUS
bs_no_source, //!< BUS is open (0177777)
bs_task_3, //!< BUS source is task specific
bs_task_4, //!< BUS source is task specific
bs_read_md, //!< BUS source is memory data
bs_mouse, //!< BUS source is mouse data
bs_disp //!< BUS source displacement (emulator task)
};
//! Function 1 numbers
enum {
f1_nop, //!< f1 00 no operation
f1_load_mar, //!< f1 01 load memory address register
f1_task, //!< f1 02 task switch
f1_block, //!< f1 03 task block
f1_l_lsh_1, //!< f1 04 left shift L once
f1_l_rsh_1, //!< f1 05 right shift L once
f1_l_lcy_8, //!< f1 06 cycle L 8 times
f1_const, //!< f1 07 constant from PROM
f1_task_10, //!< f1 10 task specific
f1_task_11, //!< f1 11 task specific
f1_task_12, //!< f1 12 task specific
f1_task_13, //!< f1 13 task specific
f1_task_14, //!< f1 14 task specific
f1_task_15, //!< f1 15 task specific
f1_task_16, //!< f1 16 task specific
f1_task_17 //!< f1 17 task specific
};
//! Function 2 numbers
enum {
f2_nop, //!< f2 00 no operation
f2_bus_eq_zero, //!< f2 01 branch on bus equals 0
f2_shifter_lt_zero, //!< f2 02 branch on shifter less than 0
f2_shifter_eq_zero, //!< f2 03 branch on shifter equals 0
f2_bus, //!< f2 04 branch on BUS[6-15]
f2_alucy, //!< f2 05 branch on (latched) ALU carry
f2_load_md, //!< f2 06 load memory data
f2_const, //!< f2 07 constant from PROM
f2_task_10, //!< f2 10 task specific
f2_task_11, //!< f2 11 task specific
f2_task_12, //!< f2 12 task specific
f2_task_13, //!< f2 13 task specific
f2_task_14, //!< f2 14 task specific
f2_task_15, //!< f2 15 task specific
f2_task_16, //!< f2 16 task specific
f2_task_17 //!< f2 17 task specific
};
//! enumeration of the micro code word bits
//! Note: The Alto documents enumerate bits from left (MSB = 0) to right (LSB = 31)
enum {
DRSEL0, DRSEL1, DRSEL2, DRSEL3, DRSEL4,
DALUF0, DALUF1, DALUF2, DALUF3,
DBS0, DBS1, DBS2,
DF1_0, DF1_1, DF1_2, DF1_3,
DF2_0, DF2_1, DF2_2, DF2_3,
DLOADT,
DLOADL,
NEXT0, NEXT1, NEXT2, NEXT3, NEXT4, NEXT5, NEXT6, NEXT7, NEXT8, NEXT9
};
//! get the normally accessed bank number from a bank register
static inline UINT16 GET_BANK_NORMAL(UINT16 breg) { return X_RDBITS(breg,16,12,13); }
//! get the extended bank number (accessed via XMAR) from a bank register
static inline UINT16 GET_BANK_EXTENDED(UINT16 breg) { return X_RDBITS(breg,16,14,15); }
//! get an ignored bit field from a control RAM address
static inline UINT16 GET_CRAM_IGNORE(UINT16 addr) { return X_RDBITS(addr,16,0,1); }
//! get the bank select bit field from a control RAM address
static inline UINT16 GET_CRAM_BANKSEL(UINT16 addr) { return X_RDBITS(addr,16,2,3); }
//! get the ROM/RAM flag from a control RAM address
static inline UINT16 GET_CRAM_RAMROM(UINT16 addr) { return X_RDBITS(addr,16,4,4); }
//! get the half select flag from a control RAM address
static inline UINT16 GET_CRAM_HALFSEL(UINT16 addr) { return X_RDBITS(addr,16,5,5); }
//! get the word address bit field from a control RAM address
static inline UINT16 GET_CRAM_WORDADDR(UINT16 addr) { return X_RDBITS(addr,16,6,15); }
UINT16 m_task_mpc[ALTO2_TASKS]; //!< per task micro program counter
UINT16 m_task_next2[ALTO2_TASKS]; //!< per task address modifier
UINT8 m_task; //!< active task
UINT8 m_next_task; //!< next micro instruction's task
UINT8 m_next2_task; //!< next but one micro instruction's task
UINT16 m_mpc; //!< micro program counter
UINT32 m_mir; //!< micro instruction register
/**
* \brief current micro instruction's register selection
* The emulator F2s ACSOURCE and ACDEST modify this.
* Note: The S registers are addressed by the original RSEL[0-4],
* even when the the emulator modifies this.
*/
UINT8 m_rsel;
UINT8 m_d_rsel; //!< decoded RSEL[0-4]
UINT8 m_d_aluf; //!< decoded ALUF[0-3] function
UINT8 m_d_bs; //!< decoded BS[0-2] bus source
UINT8 m_d_f1; //!< decoded F1[0-3] function
UINT8 m_d_f2; //!< decoded F2[0-3] function
UINT8 m_d_loadt; //!< decoded LOADT flag
UINT8 m_d_loadl; //!< decoded LOADL flag
UINT16 m_next; //!< current micro instruction's next
UINT16 m_next2; //!< next micro instruction's next
UINT16 m_r[ALTO2_REGS]; //!< R register file
UINT16 m_s[ALTO2_SREG_BANKS][ALTO2_REGS]; //!< S register file(s)
UINT16 m_bus; //!< wired-AND bus
UINT16 m_t; //!< T register
UINT16 m_alu; //!< the current ALU
UINT16 m_aluc0; //!< the current ALU carry output
UINT16 m_l; //!< L register
UINT16 m_shifter; //!< shifter output
UINT16 m_laluc0; //!< the latched ALU carry output
UINT16 m_m; //!< M register of RAM related tasks (MYL latch in the schematics)
UINT16 m_cram_addr; //!< constant RAM address
UINT16 m_task_wakeup; //!< task wakeup: bit 1<<n set if task n requesting service
a2func m_active_callback[ALTO2_TASKS]; //!< task activation callbacks
UINT16 m_reset_mode; //!< reset mode register: bit 1<<n set if task n starts in ROM
bool m_rdram_flag; //!< set by rdram, action happens on next cycle
bool m_wrtram_flag; //!< set by wrtram, action happens on next cycle
UINT8 m_s_reg_bank[ALTO2_TASKS]; //!< active S register bank per task
UINT8 m_bank_reg[ALTO2_TASKS]; //!< normal and extended RAM banks per task
bool m_ether_enable; //!< set to true, if the ethernet should be simulated
bool m_ewfct; //!< set by Ether task when it want's a wakeup at switch to task_mrt
int m_dsp_time; //!< display_state_machine() time accu
int m_unload_time; //!< unload word time accu
int m_unload_word; //!< unload word number
#if (USE_BITCLK_TIMER == 0)
int m_bitclk_time; //!< bitclk call time accu
int m_bitclk_index; //!< bitclk index (bit number)
#endif
static const char *task_name(int task); //!< human readable task names
static const char *r_name(UINT8 reg); //!< human readable register names
static const char *aluf_name(UINT8 aluf); //!< human readable ALU function names
static const char *bs_name(UINT8 bs); //!< human readable bus source names
static const char *f1_name(UINT8 f1); //!< human readable F1 function names
static const char *f2_name(UINT8 f2); //!< human readable F2 function names
/**
* @brief 2KCTL PROM u3 - 256x4
* <PRE>
* PROM u3 is 256x4 type 3601-1, looks like SN74387, and it
* controls NEXT[6-9]', i.e. the outputs are wire-AND to NEXT
*
* SN74387
* +---+-+---+
* | +-+ |
* A6 -|1 16|- Vcc
* | |
* A5 -|2 15|- A7
* | |
* A4 -|3 14|- FE1'
* | |
* A3 -|4 13|- FE2'
* | |
* A0 -|5 12|- D0
* | |
* A1 -|6 11|- D1
* | |
* A2 -|7 10|- D2
* | |
* GND -|8 9|- D3
* | |
* +---------+
*
*
* It is enabled whenever the Emulator task is active and:
* both F2[0] and F2[1] are 1 F2 functions 014, 015, 016, 017
* F2=14 is 0 not for F2 = 14 (load IR<-)
* IR[0] is 0 not for arithmetic group
*
* This means it controls the F2 functions 015:IDISP<- and 016:<-ACSOURCE
*
* Its address lines are:
* line pin connected to load swap
* -------------------------------------------------------------------
* A0 5 F2[2] (i.e. MIR[18]) IR[07]
* A1 6 IR[01] IR[06]
* A2 7 IR[02] IR[05]
* A3 4 IR[03] IR[04]
* A4 3 IR[04] IR[03]
* A5 2 IR[05] IR[02]
* A6 1 IR[06] IR[01]
* A7 15 IR[07] F2[2]
*
* Its data lines are:
* line pin connected to load
* -------------------------------------------------------------------
* D3 9 NEXT[06]' NEXT[06]
* D2 10 NEXT[07]' NEXT[07]
* D1 11 NEXT[08]' NEXT[08]
* D0 12 NEXT[09]' NEXT[09]
*
* Its address lines are reversed at load time to make it easier to
* access it. Also both, address and data lines, are inverted.
* </PRE>
*/
UINT8* m_ctl2k_u3;
/**
* @brief 2KCTL PROM u38; 82S23; 32x8 bit
* <PRE>
*
* 82S23
* +---+-+---+
* | +-+ |
* B0 -|1 16|- Vcc
* | |
* B1 -|2 15|- EN'
* | |
* B2 -|3 14|- A4
* | |
* B3 -|4 13|- A3
* | |
* B4 -|5 12|- A2
* | |
* B5 -|6 11|- A1
* | |
* B6 -|7 10|- A0
* | |
* GND -|8 9|- B7
* | |
* +---------+
*
* Task priority encoder
*
* line pin signal
* -------------------------------
* A0 10 CT1 (current task LSB)
* A1 11 CT2
* A2 12 CT4
* A3 13 CT8 (current task MSB)
* A4 14 0 (GND)
*
* line pin signal
* -------------------------------
* B0 1 RDCT8'
* B1 2 RDCT4'
* B2 3 RDCT2'
* B3 4 RDCT1'
* B4 5 NEXT[09]'
* B5 6 NEXT[08]'
* B6 7 NEXT[07]'
* B7 9 NEXT[06]'
* </PRE>
*/
UINT8* m_ctl2k_u38;
//! output lines of the 2KCTL U38 PROM
enum {
U38_RDCT8,
U38_RDCT4,
U38_RDCT2,
U38_RDCT1,
U38_NEXT09,
U38_NEXT08,
U38_NEXT07,
U38_NEXT06
};
/**
* @brief 2KCTL PROM u76; P3601-1; 256x4; PC0I and PC1I decoding
* <PRE>
* Replacement for u51, which is used in 1KCTL
*
* SN74387
* +---+-+---+
* | +-+ |
* A6 -|1 16|- Vcc
* | |
* A5 -|2 15|- A7
* | |
* A4 -|3 14|- FE1'
* | |
* A3 -|4 13|- FE2'
* | |
* A0 -|5 12|- D0
* | |
* A1 -|6 11|- D1
* | |
* A2 -|7 10|- D2
* | |
* GND -|8 9|- D3
* | |
* +---------+
*
* input line signal
* ----------------------------
* A7 15 EMACT'
* A6 1 F1(0)
* A5 2 F1(1)'
* A4 3 F1(2)'
* A3 4 F1(3)'
* A2 7 0 (GND)
* A1 6 PC1O
* A0 5 PC0O
*
* output line signal
* ----------------------------
* D0 12 PC1T
* D1 11 PC1F
* D2 10 PC0T
* D3 9 PC0F
*
* The outputs are connected to a dual 4:1 demultiplexer 74S153, so that
* depending on NEXT01' and RESET the following signals are passed through:
*
* RESET NEXT[01]' PC0I PC1I
* --------------------------------------
* 0 0 PC0T PC1T
* 0 1 PC0F PC1F
* 1 0 PC0I4 T14 (?)
* 1 1 -"- -"-
*
* This selects the microcode "page" to jump to on SWMODE (F1 = 010)
* depending on the current NEXT[01]' level.
* </PRE>
*/
UINT8* m_ctl2k_u76;
/**
* @brief 3k CRAM PROM a37
*/
UINT8* m_cram3k_a37;
/**
* @brief memory addressing PROM a64
*/
UINT8* m_madr_a64;
/**
* @brief memory addressing PROM a65
*/
UINT8* m_madr_a65;
/**
* @brief unused PROM a90
* Data sheet 05a_AIM.pdf page 14
* inputs A0-A7 from R0-R7 (?)
* output signal
* -------------------
* Q0 KP3
* Q1 KP4
* Q2 KP5
* Q3 unused
*
* I haven't found yet where KP3-KP5 are used
*/
UINT8* m_madr_a90;
/**
* @brief unused PROM a91
* Data sheet 05a_AIM.pdf page 14
* inputs A0-A7 from R0-R7 (?)
*
* Output Signal
* -------------------
* Q0 KP0
* Q1 KP1
* Q2 KP2
* Q3 unused
* KP0-KP3 are decoded using 7442 a78 to select
* the keyboard row enable
*
* Enable Key[0] Key[1] Key[2] Key[3] Key[4] Key[5] Key[6] Key[7]
* ------------------------------------------------------------------------
* KE(0) KB(R) KB(1) KB(3) KB(5) KB(T) KB(ESC) KB(2) KB(4)
* KE(1) KB(G) KB(TAB) KB(W) KB(6) KB(Y) KB(F) KB(0) KB(E)
* KE(2) KB(H) KB(CTL) KB(S) KB(7) KB(8) KB(C) KB(A) KB(D)
* KE(3) KB(N) KB(J) KB(9) KB(U) KB(M) KB(B) KB(I) KB(V)
* KE(4) KB(LCK) KB(Z) KB(X) KB(Q) KB(SPC) KB(^R) KB(O) KB(K)
* KE(5) KB([) KB(.) KB(L) KB(-) KB(+) KB(;) KB(,) KB(P)
* KE(6) KB(^L) KB(RTN) KB(") KB(/) KB(S3) KB(<-) KB(]) KB(\)
* KE(7) KB(S1) KB(DEL) KB(S2) KB(LF) KB(S4) KB(S5) KB(BW) KB(BS)
*/
UINT8* m_madr_a91;
/**
* @brief ALU function to 74181 operation lookup PROM
*/
UINT8* m_alu_a10;
//! output lines of the ALU a10 PROM
enum {
A10_UNUSED = (1 << 0),
A10_TSELECT = (1 << 1),
A10_ALUCI = (1 << 2),
A10_ALUM = (1 << 3),
A10_ALUS0 = (1 << 4),
A10_ALUS1 = (1 << 5),
A10_ALUS2 = (1 << 6),
A10_ALUS3 = (1 << 7),
A10_ALUIN = (A10_ALUM|A10_ALUCI|A10_ALUS0|A10_ALUS1|A10_ALUS2|A10_ALUS3)
};
//! no operating function to put in the m_bs, m_f1 and m_f2 slots
void noop() {}
//! per task bus source function pointers, early (0) and late (1)
a2func m_bs[2][ALTO2_TASKS][ALTO2_BUSSRC];
void set_bs(UINT8 task, UINT8 fn, a2func f0, a2func f1) {
m_bs[0][task][fn] = f0 ? f0 : &alto2_cpu_device::noop;
m_bs[1][task][fn] = f1 ? f1 : &alto2_cpu_device::noop;
}
//! per task f1 function pointers, early (0) and late (1)
a2func m_f1[2][ALTO2_TASKS][ALTO2_F1MAX];
void set_f1(UINT8 task, UINT8 fn, a2func f0, a2func f1) {
m_f1[0][task][fn] = f0 ? f0 : &alto2_cpu_device::noop;
m_f1[1][task][fn] = f1 ? f1 : &alto2_cpu_device::noop;
}
//! per task f2 function pointers, early (0) and late (1)
a2func m_f2[2][ALTO2_TASKS][ALTO2_F2MAX];
void set_f2(UINT8 task, UINT8 fn, a2func f0, a2func f1) {
m_f2[0][task][fn] = f0 ? f0 : &alto2_cpu_device::noop;
m_f2[1][task][fn] = f1 ? f1 : &alto2_cpu_device::noop;
}
bool m_ram_related[ALTO2_TASKS]; //!< set when task is RAM related
UINT64 m_cycle; //!< number of cycles executed in the current slice
UINT64 cycle() { return m_cycle; } //!< return the current CPU cycle
UINT64 ntime() { return m_cycle*ALTO2_UCYCLE/1000; } //!< return the current nano seconds
void hard_reset(); //!< reset the various registers
void soft_reset(); //!< soft reset
void fn_bs_bad_0(); //! bs dummy early function
void fn_bs_bad_1(); //! bs dummy late function
void fn_f1_bad_0(); //! f1 dummy early function
void fn_f1_bad_1(); //! f1 dummy late function
void fn_f2_bad_0(); //! f2 dummy early function
void fn_f2_bad_1(); //! f2 dummy late function
DECLARE_READ16_MEMBER( noop_r ); //!< read open bus (0177777)
DECLARE_WRITE16_MEMBER( noop_w ); //!< write open bus
DECLARE_READ16_MEMBER( bank_reg_r ); //!< read bank register in memory mapped I/O range
DECLARE_WRITE16_MEMBER( bank_reg_w ); //!< write bank register in memory mapped I/O range
void bs_early_read_r(); //!< bus source: drive bus by R register
void bs_early_load_r(); //!< bus source: load R places 0 on the BUS
void bs_late_load_r(); //!< bus source: load R from SHIFTER
void bs_early_read_md(); //!< bus source: drive BUS from read memory data
void bs_early_mouse(); //!< bus source: drive bus by mouse
void bs_early_disp(); //!< bus source: drive bus by displacement (which?)
void f1_early_block(); //!< F1 func: block active task
void f1_late_load_mar(); //!< F1 func: load memory address register
void f1_early_task(); //!< F1 func: task switch
void f1_late_l_lsh_1(); //!< F1 func: SHIFTER = left shift L once
void f1_late_l_rsh_1(); //!< F1 func: SHIFTER = right shift L once
void f1_late_l_lcy_8(); //!< F1 func: SHIFTER = byte swap L
void f2_late_bus_eq_zero(); //!< F2 func: branch on bus equals zero
void f2_late_shifter_lt_zero(); //!< F2 func: branch on shifter less than zero
void f2_late_shifter_eq_zero(); //!< F2 func: branch on shifter equals zero
void f2_late_bus(); //!< F2 func: branch on bus bits BUS[6-15]
void f2_late_alucy(); //!< F2 func: branch on latched ALU carry
void f2_late_load_md(); //!< F2 func: load memory data
#if USE_ALU_74181
UINT32 alu_74181(UINT32 a, UINT32 b, UINT8 smc);
#endif
void rdram(); //!< read the microcode ROM/RAM halfword
void wrtram(); //!< write the microcode RAM from M register and ALU
UINT8 m_ether_id; //!< configured Ethernet ID for this machine
//*******************************************
// inline the sub-devices
//*******************************************
#include "a2jkff.h"
#include "a2ram.h"
#include "a2hw.h"
#include "a2kbd.h"
#include "a2mouse.h"
#include "a2disk.h"
#include "a2disp.h"
#include "a2mem.h"
#include "a2emu.h"
#include "a2ksec.h"
#include "a2ether.h"
#include "a2mrt.h"
#include "a2dwt.h"
#include "a2curt.h"
#include "a2dht.h"
#include "a2dvt.h"
#include "a2part.h"
#include "a2dwt.h"
#include "a2kwd.h"
};
extern const device_type ALTO2;
#endif /* _CPU_ALTO2_H_ */

View File

@ -0,0 +1,391 @@
/**********************************************************
* Xerox AltoII disassembler
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
**********************************************************/
#include "alto2cpu.h"
#define loc_DASTART 0000420 // display list header
#define loc_DVIBITS 0000421 // display vertical field interrupt bitword
#define loc_ITQUAN 0000422 // interval timer stored quantity
#define loc_ITBITS 0000423 // interval timer bitword
#define loc_MOUSEX 0000424 // mouse X coordinate
#define loc_MOUSEY 0000425 // mouse Y coordinate
#define loc_CURSORX 0000426 // cursor X coordinate
#define loc_CURSORY 0000427 // cursor Y coordinate
#define loc_RTC 0000430 // real time clock
#define loc_CURMAP 0000431 // cursor bitmap (16 words up to 00450)
#define loc_WW 0000452 // interrupt wakeups waiting
#define loc_ACTIVE 0000453 // active interrupt bitword
#define loc_MASKTAB 0000460 // mask table for convert
#define loc_PCLOC 0000500 // saved interrupt PC
#define loc_INTVEC 0000501 // interrupt transfer vector (15 words up to 00517)
#define loc_KBLK 0000521 // disk command block address
#define loc_KSTAT 0000522 // disk status at start of current sector
#define loc_KADDR 0000523 // disk address of latest disk command
#define loc_KSIBITS 0000524 // sector interrupt bit mask
#define loc_ITTIME 0000525 // interval timer timer
#define loc_TRAPPC 0000527 // trap saved PC
#define loc_TRAPVEC 0000530 // trap vectors (up to 0567)
#define loc_TIMERDATA 0000570 // timer data (OS; up to 0577)
#define loc_EPLOC 0000600 // ethernet post location
#define loc_EBLOC 0000601 // ethernet interrupt bitmask
#define loc_EELOC 0000602 // ethernet ending count
#define loc_ELLOC 0000603 // ethernet load location
#define loc_EICLOC 0000604 // ethernet input buffer count
#define loc_EIPLOC 0000605 // ethernet input buffer pointer
#define loc_EOCLOC 0000606 // ethernet output buffer count
#define loc_EOPLOC 0000607 // ethernet output buffer pointer
#define loc_EHLOC 0000610 // ethernet host address
#define loc_ERSVD 0000611 // reserved for ethernet expansion (up to 00612)
#define loc_ALTOV 0000613 // Alto I/II indication that microcode caninterrogate (0 = Alto I, -1 = Alto II)
#define loc_DCBR 0000614 // posted by parity task (main memory parity error)
#define loc_KNMAR 0000615 // -"-
#define loc_DWA 0000616 // -"-
#define loc_CBA 0000617 // -"-
#define loc_PC 0000620 // -"-
#define loc_SAD 0000621 // -"-
#define loc_SWATR 0000700 // saved registers (Swat; up to 00707)
#define loc_UTILOUT 0177016 // printer output (up to 177017)
#define loc_XBUS 0177020 // untility input bus (up to 177023)
#define loc_MEAR 0177024 // memory error address register
#define loc_MESR 0177025 // memory error status register
#define loc_MECR 0177026 // memory error control register
#define loc_UTILIN 0177030 // printer status, mouse keyset
#define loc_KBDAD 0177034 // undecoded keyboard (up to 177037)
#define loc_BANKREGS 0177740 // extended memory option bank registers
/**
* @brief Microcode and constants PROM size
*/
#define MCODE_PAGE 1024
#define MCODE_SIZE (2*MCODE_PAGE) /* Alto II may have 2 pages (or even 4?) */
#define MCODE_MASK (MCODE_SIZE - 1)
#define PROM_SIZE 256
/**
* @brief short names for the 16 tasks
*/
static const char *taskname[16] = {
"EMU", // emulator task
"T01",
"T02",
"T03",
"DSC", // disk sector task
"T05",
"T06",
"ETH", // ethernet task
"MRT", // memory refresh task
"DWT", // display word task
"CUR", // cursor task
"DHT", // display horizontal task
"DVT", // display vertical task
"PAR", // parity task
"DWD", // disk word task
"T17"
};
/**
* @brief names for the 32 R registers
*/
static const char *regname[32] = {
"AC(3)", // emulator accu 3
"AC(2)", // emulator accu 2
"AC(1)", // emulator accu 1
"AC(0)", // emulator accu 0
"R04",
"R05",
"PC", // emulator program counter
"R07",
"R10",
"R11",
"R12",
"R13",
"R14",
"R15",
"R16",
"R17",
"R20",
"R21",
"CBA", // address of the currently active DCB+1
"AECL", // address of end of current scanline's bitmap
"SLC", // scan line count
"HTAB", // number of tab words remaining on current scanline
"DWA", // address of the bit map double word being fetched
"MTEMP", // temporary cell
"R30",
"R31",
"R32",
"R33",
"R34",
"R35",
"R36",
"R37"
};
//! for ALUF which is the value loaded into T, if t flags is set
static const char* t_bus_alu[16] = {
"ALU",
"BUS",
"ALU",
"BUS",
"BUS",
"ALU",
"ALU",
"BUS",
"BUS",
"BUS",
"ALU",
"ALU",
"ALU",
"BUS",
"BUS",
"BUS",
};
/**
* @brief copy of the constant PROM, which this disassembler may not have access to
*/
static UINT16 const_prom[PROM_SIZE] = {
/* 0000 */ 0x0000, 0x0001, 0x0002, 0xfffe, 0xffff, 0xffff, 0x000f, 0xffff,
/* 0008 */ 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0xfff8, 0xfff8,
/* 0010 */ 0x0010, 0x001f, 0x0020, 0x003f, 0x0040, 0x007f, 0x0080, 0x0007,
/* 0018 */ 0x00ff, 0xff00, 0x0400, 0x0100, 0x0110, 0x0151, 0x0114, 0x000f,
/* 0020 */ 0x0116, 0x0118, 0x0ffa, 0xf000, 0x4000, 0xfffc, 0xfff6, 0xffeb,
/* 0028 */ 0x4800, 0x6c00, 0x0800, 0x1000, 0xfe00, 0x7fff, 0x7fe0, 0x7f00,
/* 0030 */ 0xffbd, 0x0f00, 0x0f0f, 0xf0f0, 0x6048, 0x3000, 0x7159, 0x2109,
/* 0038 */ 0x6a3c, 0x4213, 0xa5a5, 0xfe1c, 0x3f00, 0xffc0, 0x012a, 0x0140,
/* 0040 */ 0x8000, 0xffe0, 0x00bf, 0xfff9, 0xfff0, 0xfffd, 0x0970, 0x5d20,
/* 0048 */ 0x3844, 0x6814, 0xfc00, 0xfe20, 0xfe22, 0x0083, 0x00f0, 0xff80,
/* 0050 */ 0xf800, 0xe000, 0xc000, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff,
/* 0058 */ 0x3fff, 0x0200, 0x2000, 0xfff1, 0x0156, 0x0157, 0x0138, 0x0c00,
/* 0060 */ 0x0130, 0x1813, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
/* 0068 */ 0x0186, 0x0187, 0x0188, 0x018a, 0x0112, 0x0113, 0x0102, 0xfff0,
/* 0070 */ 0x0153, 0x0154, 0xffef, 0xffe4, 0xfffb, 0x000a, 0xffc1, 0x001f,
/* 0078 */ 0x0e00, 0x007e, 0xff7e, 0x0018, 0x000d, 0x03f8, 0x83f9, 0xffe0,
/* 0080 */ 0xfbff, 0x0009, 0x000b, 0x000c, 0x000e, 0x0030, 0x01fe, 0xff7f,
/* 0088 */ 0x81ff, 0xffbf, 0xffcc, 0x0557, 0x0041, 0x0198, 0x0199, 0x01a2,
/* 0090 */ 0xfe72, 0xfe58, 0x0012, 0x0014, 0x00dd, 0x02ff, 0x0101, 0x0001,
/* 0098 */ 0x0401, 0x0011, 0x0013, 0x0015, 0x0016, 0x0017, 0x0019, 0x0003,
/* 00a0 */ 0x03bd, 0x01de, 0xfe50, 0x00c0, 0x0c01, 0x6200, 0x6300, 0x0008,
/* 00a8 */ 0x6400, 0x6500, 0x6e00, 0x6700, 0x6900, 0x6d00, 0x6600, 0x000c,
/* 00b0 */ 0x6b00, 0x6b01, 0x6b02, 0x6b03, 0x6b04, 0x6b05, 0x6b06, 0x0010,
/* 00b8 */ 0x6b07, 0x6b08, 0x6b09, 0x6b0a, 0x6b0b, 0x6b0c, 0x6b0d, 0x0020,
/* 00c0 */ 0x6b0e, 0x6b0f, 0xfff3, 0xfe14, 0xfe15, 0xfe16, 0x0ffc, 0x0040,
/* 00c8 */ 0x04ff, 0x05ff, 0x06ff, 0x013f, 0x017e, 0xfe7d, 0xffff, 0x0080,
/* 00d0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00c0,
/* 00d8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00ff,
/* 00e0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
/* 00e8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
/* 00f0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
/* 00f8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
};
/**
* @brief print a symbolic name for an mpc address
*
* @param a microcode address (mpc)
* @return pointer to const string with the address or symbolic name
*/
static const char *addrname(int a)
{
static char buffer[4][32];
static int which = 0;
char *dst;
which = (which + 1) % 4;
dst = buffer[which];
if (a < 020) {
// start value for mpc per task is the task number
snprintf(dst, sizeof(buffer[0]), "*%s", taskname[a]);
} else {
snprintf(dst, sizeof(buffer[0]), "%04o", a);
}
return dst;
}
offs_t alto2_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
{
size_t len = 128;
UINT32 mir = (static_cast<UINT32>(oprom[0]) << 24) |
(static_cast<UINT32>(oprom[1]) << 16) |
(static_cast<UINT32>(oprom[2]) << 8) |
(static_cast<UINT32>(oprom[3]) << 0);
UINT8 rsel = static_cast<UINT8>((mir >> 27) & 31);
UINT8 aluf = static_cast<UINT8>((mir >> 23) & 15);
UINT8 bs = static_cast<UINT8>((mir >> 20) & 7);
UINT8 f1 = static_cast<UINT8>((mir >> 16) & 15);
UINT8 f2 = static_cast<UINT8>((mir >> 12) & 15);
UINT8 t = static_cast<UINT8>((mir >> 11) & 1);
UINT8 l = static_cast<UINT8>((mir >> 10) & 1);
offs_t next = static_cast<offs_t>(mir & 1023);
const UINT8* src = oprom - 4 * pc + 4 * next;
UINT32 next2 = (static_cast<UINT32>(src[0]) << 24) |
(static_cast<UINT32>(src[1]) << 16) |
(static_cast<UINT32>(src[2]) << 8) |
(static_cast<UINT32>(src[3]) << 0);
UINT16 prefetch = next2 & 1023;
char *dst = buffer;
offs_t result = 1 | DASMFLAG_SUPPORTED;
UINT8 pa;
if (next != pc + 1)
result |= DASMFLAG_STEP_OUT;
if (t)
dst += snprintf(dst, len - (size_t)(dst - buffer), "T<-%s ", t_bus_alu[aluf]);
if (l)
dst += snprintf(dst, len - (size_t)(dst - buffer), "L<- ");
if (bs == 1)
dst += snprintf(dst, len - (size_t)(dst - buffer), "%s<- ", regname[rsel]);
switch (aluf) {
case 0: // T?: BUS
// this is somehow redundant and just wasting space
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS) ");
break;
case 1: // : T
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(T) ");
break;
case 2: // T?: BUS OR T
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS|T) ");
break;
case 3: // : BUS AND T
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS&T) ");
break;
case 4: // : BUS XOR T
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS^T) ");
break;
case 5: // T?: BUS + 1
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS+1) ");
break;
case 6: // T?: BUS - 1
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS-1) ");
break;
case 7: // : BUS + T
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS+T) ");
break;
case 8: // : BUS - T
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS-T) ");
break;
case 9: // : BUS - T - 1
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS-T-1) ");
break;
case 10: // T?: BUS + T + 1
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS+T+1) ");
break;
case 11: // T?: BUS + SKIP
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS+SKIP) ");
break;
case 12: // T?: BUS, T (AND)
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS,T) ");
break;
case 13: // : BUS AND NOT T
dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS&~T) ");
break;
case 14: // : undefined
dst += snprintf(dst, len - (size_t)(dst - buffer), "*ALUF(BUS) ");
break;
case 15: // : undefined
dst += snprintf(dst, len - (size_t)(dst - buffer), "*ALUF(BUS) ");
break;
}
switch (bs) {
case 0: // read R
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-%s ", regname[rsel]);
break;
case 1: // load R from shifter output
// dst += snprintf(dst, len - (size_t)(dst - buffer), "; %s<-", regname[rsel]);
break;
case 2: // enables no source to the BUS, leaving it all ones
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-177777 ");
break;
case 3: // performs different functions in different tasks
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-BS3 ");
break;
case 4: // performs different functions in different tasks
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-BS4 ");
break;
case 5: // memory data
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-MD ");
break;
case 6: // BUS[3-0] <- MOUSE; BUS[15-4] <- -1
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-MOUSE ");
break;
case 7: // IR[7-0], possibly sign extended
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-DISP ");
break;
}
switch (f1) {
case 0: // no operation
break;
case 1: // load MAR from ALU output; start main memory reference
dst += snprintf(dst, len - (size_t)(dst - buffer), "MAR<-ALU ");
break;
case 2: // switch tasks if higher priority wakeup is pending
dst += snprintf(dst, len - (size_t)(dst - buffer), "TASK ");
break;
case 3: // disable the current task until re-enabled by a hardware-generated condition
dst += snprintf(dst, len - (size_t)(dst - buffer), "BLOCK ");
break;
case 4: // SHIFTER output will be L shifted left one place
dst += snprintf(dst, len - (size_t)(dst - buffer), "SHIFTER<-L(LSH1) ");
break;
case 5: // SHIFTER output will be L shifted right one place
dst += snprintf(dst, len - (size_t)(dst - buffer), "SHIFTER<-L(RSH1) ");
break;
case 6: // SHIFTER output will be L rotated left 8 places
dst += snprintf(dst, len - (size_t)(dst - buffer), "SHIFTER<-L(LCY8) ");
break;
case 7: // put the constant from PROM (RSELECT,BS) on the bus
pa = (rsel << 3) | bs;
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-%05o CONST[%03o]", const_prom[pa], pa);
break;
default:
dst += snprintf(dst, len - (size_t)(dst - buffer), "F1_%02o ", f1);
break;
}
switch (f2) {
case 0: // no operation
break;
case 1: // NEXT <- NEXT OR (BUS==0 ? 1 : 0)
dst += snprintf(dst, len - (size_t)(dst - buffer), "[BUS==0 ? %s:%s] ",
addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK));
break;
case 2: // NEXT <- NEXT OR (SHIFTER==0 ? 1 : 0)
dst += snprintf(dst, len - (size_t)(dst - buffer), "[SH==0 ? %s:%s] ",
addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK));
break;
case 3: // NEXT <- NEXT OR (SHIFTER<0 ? 1 : 0)
dst += snprintf(dst, len - (size_t)(dst - buffer), "[SH<0 ? %s:%s] ",
addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK));
break;
case 4: // NEXT <- NEXT OR BUS
dst += snprintf(dst, len - (size_t)(dst - buffer), "NEXT<-BUS ");
break;
case 5: // NEXT <- NEXT OR ALUC0. ALUC0 is the carry produced by last L loading microinstruction.
dst += snprintf(dst, len - (size_t)(dst - buffer), "[ALUC0 ? %s:%s] ",
addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK));
break;
case 6: // deliver BUS data to memory
dst += snprintf(dst, len - (size_t)(dst - buffer), "MD<-BUS ");
break;
case 7: // put on the bus the constant from PROM (RSELECT,BS)
if (f1 != 7) {
pa = 8 * rsel + bs;
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-%05o CONST[%03o]", const_prom[pa], pa);
}
break;
default:
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-F2_%02o ", f2);
break;
}
return result;
}

View File

@ -2388,3 +2388,112 @@ $(CPUOBJ)/score/score.o: $(CPUSRC)/score/score.c \
$(CPUOBJ)/score/scoredsm.o: $(CPUSRC)/score/scoredsm.c \
$(CPUSRC)/score/scorem.h
#-------------------------------------------------
# Xerox Alto-II
#@src/emu/cpu/alto2/alto2cpu.h,CPUS += ALTO2
#-------------------------------------------------
ifneq ($(filter ALTO2,$(CPUS)),)
OBJDIRS += $(CPUOBJ)/alto2
CPUOBJS += $(CPUOBJ)/alto2/alto2cpu.o \
$(CPUOBJ)/alto2/a2disk.o \
$(CPUOBJ)/alto2/a2disp.o \
$(CPUOBJ)/alto2/a2curt.o \
$(CPUOBJ)/alto2/a2dht.o \
$(CPUOBJ)/alto2/a2dvt.o \
$(CPUOBJ)/alto2/a2dwt.o \
$(CPUOBJ)/alto2/a2emu.o \
$(CPUOBJ)/alto2/a2ether.o \
$(CPUOBJ)/alto2/a2hw.o \
$(CPUOBJ)/alto2/a2kbd.o \
$(CPUOBJ)/alto2/a2ksec.o \
$(CPUOBJ)/alto2/a2kwd.o \
$(CPUOBJ)/alto2/a2mem.o \
$(CPUOBJ)/alto2/a2mouse.o \
$(CPUOBJ)/alto2/a2mrt.o \
$(CPUOBJ)/alto2/a2part.o \
$(CPUOBJ)/alto2/a2ram.o \
$(CPUOBJ)/alto2/a2roms.o
DASMOBJS += $(CPUOBJ)/alto2/alto2dsm.o
endif
$(CPUOBJ)/alto2/alto2cpu.o: $(CPUSRC)/alto2/alto2cpu.c \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2disk.o: $(CPUSRC)/alto2/a2disk.c \
$(CPUSRC)/alto2/a2disk.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2disp.o: $(CPUSRC)/alto2/a2disp.c \
$(CPUSRC)/alto2/a2disp.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2curt.o: $(CPUSRC)/alto2/a2curt.c \
$(CPUSRC)/alto2/a2curt.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2dht.o: $(CPUSRC)/alto2/a2dht.c \
$(CPUSRC)/alto2/a2dht.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2dvt.o: $(CPUSRC)/alto2/a2dvt.c \
$(CPUSRC)/alto2/a2dvt.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2dwt.o: $(CPUSRC)/alto2/a2dwt.c \
$(CPUSRC)/alto2/a2dwt.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2emu.o: $(CPUSRC)/alto2/a2emu.c \
$(CPUSRC)/alto2/a2emu.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2ether.o: $(CPUSRC)/alto2/a2ether.c \
$(CPUSRC)/alto2/a2ether.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2hw.o: $(CPUSRC)/alto2/a2hw.c \
$(CPUSRC)/alto2/a2hw.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2kbd.o: $(CPUSRC)/alto2/a2kbd.c \
$(CPUSRC)/alto2/a2kbd.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2ksec.o: $(CPUSRC)/alto2/a2ksec.c \
$(CPUSRC)/alto2/a2ksec.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2kwd.o: $(CPUSRC)/alto2/a2kwd.c \
$(CPUSRC)/alto2/a2kwd.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2mem.o: $(CPUSRC)/alto2/a2mem.c \
$(CPUSRC)/alto2/a2mem.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2mouse.o: $(CPUSRC)/alto2/a2mouse.c \
$(CPUSRC)/alto2/a2mouse.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2mrt.o: $(CPUSRC)/alto2/a2mrt.c \
$(CPUSRC)/alto2/a2mrt.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2part.o: $(CPUSRC)/alto2/a2part.c \
$(CPUSRC)/alto2/a2part.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2ram.o: $(CPUSRC)/alto2/a2ram.c \
$(CPUSRC)/alto2/a2ram.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/a2roms.o: $(CPUSRC)/alto2/a2roms.c \
$(CPUSRC)/alto2/a2roms.h \
$(CPUSRC)/alto2/alto2cpu.h
$(CPUOBJ)/alto2/alto2dsm.o: $(CPUSRC)/alto2/alto2dsm.c \
$(CPUSRC)/alto2/alto2cpu.h

View File

@ -176,6 +176,7 @@ enum
XTAL_28_48MHz = 28480000, /* Chromatics CGC-7900 */
XTAL_28_63636MHz = 28636363, /* Later Leland games and Atari GT, Amiga NTSC, Raiden2 h/w (8x NTSC subcarrier)*/
XTAL_28_7MHz = 28700000,
XTAL_29_4912MHz = 29491200, /* Xerox Alto-II system clock (tagged 29.4MHz in the schematics) */
XTAL_30MHz = 30000000, /* Impera Magic Card */
XTAL_30_4761MHz = 30476100, /* Taito JC */
XTAL_30_8MHz = 30800000, /* 15IE-00-013 */

View File

@ -178,6 +178,7 @@ EMUIMAGEDEVOBJS = \
$(EMUIMAGEDEV)/cartslot.o \
$(EMUIMAGEDEV)/cassette.o \
$(EMUIMAGEDEV)/chd_cd.o \
$(EMUIMAGEDEV)/diablo.o \
$(EMUIMAGEDEV)/flopdrv.o \
$(EMUIMAGEDEV)/floppy.o \
$(EMUIMAGEDEV)/harddriv.o \

288
src/emu/imagedev/diablo.c Normal file
View File

@ -0,0 +1,288 @@
/**********************************************************
* DIABLO drive image to hard disk interface
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
**********************************************************/
#include "emu.h"
#include "emuopts.h"
#include "harddisk.h"
#include "diablo.h"
static OPTION_GUIDE_START(dsk_option_guide)
OPTION_INT('C', "cylinders", "Cylinders")
OPTION_INT('H', "heads", "Heads")
OPTION_INT('S', "sectors", "Sectors")
OPTION_INT('L', "sectorlength", "Sector Words")
OPTION_INT('K', "hunksize", "Hunk Bytes")
OPTION_GUIDE_END
static const char *dsk_option_spec =
"C1-[203]-1024;H1/[2]/4/8;S1-[12]-64;L267;K6408";
// device type definition
const device_type DIABLO = &device_creator<diablo_image_device>;
//-------------------------------------------------
// diablo_image_device - constructor
//-------------------------------------------------
diablo_image_device::diablo_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, DIABLO, "Diablo", tag, owner, clock, "diablo_image", __FILE__),
device_image_interface(mconfig, *this),
m_chd(NULL),
m_hard_disk_handle(NULL),
m_device_image_load(device_image_load_delegate()),
m_device_image_unload(device_image_func_delegate())
{
}
//-------------------------------------------------
// diablo_image_device - destructor
//-------------------------------------------------
diablo_image_device::~diablo_image_device()
{
}
//-------------------------------------------------
// device_config_complete - perform any
// operations now that the configuration is
// complete
//-------------------------------------------------
void diablo_image_device::device_config_complete()
{
// inherit a copy of the static data
const diablo_interface *intf = reinterpret_cast<const diablo_interface *>(static_config());
if (intf != NULL)
*static_cast<diablo_interface *>(this) = *intf;
// or initialize to defaults if none provided
else
{
memset(&m_interface, 0, sizeof(m_interface));
memset(&m_device_displayinfo, 0, sizeof(m_device_displayinfo));
}
m_formatlist.append(*global_alloc(image_device_format("chd", "CHD Hard drive", "chd,dsk", dsk_option_spec)));
// set brief and instance name
update_names();
}
const option_guide *diablo_image_device::create_option_guide() const
{
return dsk_option_guide;
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void diablo_image_device::device_start()
{
m_chd = NULL;
// try to locate the CHD from a DISK_REGION
chd_file *handle = get_disk_handle(machine(), tag());
if (handle != NULL)
{
m_hard_disk_handle = hard_disk_open(handle);
}
else
{
m_hard_disk_handle = NULL;
}
}
void diablo_image_device::device_stop()
{
if (m_hard_disk_handle)
hard_disk_close(m_hard_disk_handle);
}
bool diablo_image_device::call_load()
{
int our_result;
our_result = internal_load_dsk();
/* Check if there is an image_load callback defined */
if (!m_device_image_load.isnull())
{
/* Let the override do some additional work/checks */
our_result = m_device_image_load(*this);
}
return our_result;
}
bool diablo_image_device::call_create(int create_format, option_resolution *create_args)
{
int err;
UINT32 sectorsize, hunksize;
UINT32 cylinders, heads, sectors, totalsectors;
astring metadata;
cylinders = option_resolution_lookup_int(create_args, 'C');
heads = option_resolution_lookup_int(create_args, 'H');
sectors = option_resolution_lookup_int(create_args, 'S');
sectorsize = option_resolution_lookup_int(create_args, 'L') * sizeof(UINT16);
hunksize = option_resolution_lookup_int(create_args, 'K');
totalsectors = cylinders * heads * sectors;
/* create the CHD file */
chd_codec_type compression[4] = { CHD_CODEC_NONE };
err = m_origchd.create(*image_core_file(), (UINT64)totalsectors * (UINT64)sectorsize, hunksize, sectorsize, compression);
if (err != CHDERR_NONE)
goto error;
/* if we created the image and hence, have metadata to set, set the metadata */
metadata.format(HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
err = m_origchd.write_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
m_origchd.close();
if (err != CHDERR_NONE)
goto error;
return internal_load_dsk();
error:
return IMAGE_INIT_FAIL;
}
void diablo_image_device::call_unload()
{
/* Check if there is an image_unload callback defined */
if ( !m_device_image_unload.isnull() )
{
m_device_image_unload(*this);
}
if (m_hard_disk_handle != NULL)
{
hard_disk_close(m_hard_disk_handle);
m_hard_disk_handle = NULL;
}
m_origchd.close();
m_diffchd.close();
m_chd = NULL;
}
/*-------------------------------------------------
open_disk_diff - open a DISK diff file
-------------------------------------------------*/
static chd_error open_disk_diff(emu_options &options, const char *name, chd_file &source, chd_file &diff_chd)
{
astring fname(name, ".dif");
/* try to open the diff */
//printf("Opening differencing image file: %s\n", fname.cstr());
emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE);
file_error filerr = diff_file.open(fname);
if (filerr == FILERR_NONE)
{
astring fullpath(diff_file.fullpath());
diff_file.close();
//printf("Opening differencing image file: %s\n", fullpath.cstr());
return diff_chd.open(fullpath, true, &source);
}
/* didn't work; try creating it instead */
//printf("Creating differencing image: %s\n", fname.cstr());
diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
filerr = diff_file.open(fname);
if (filerr == FILERR_NONE)
{
astring fullpath(diff_file.fullpath());
diff_file.close();
/* create the CHD */
//printf("Creating differencing image file: %s\n", fullpath.cstr());
chd_codec_type compression[4] = { CHD_CODEC_NONE };
chd_error err = diff_chd.create(fullpath, source.logical_bytes(), source.hunk_bytes(), compression, source);
if (err != CHDERR_NONE)
return err;
return diff_chd.clone_all_metadata(source);
}
return CHDERR_FILE_NOT_FOUND;
}
int diablo_image_device::internal_load_dsk()
{
astring tempstring;
chd_error err = CHDERR_NONE;
m_chd = NULL;
if (m_hard_disk_handle)
hard_disk_close(m_hard_disk_handle);
/* open the CHD file */
if (software_entry() != NULL)
{
m_chd = get_disk_handle(device().machine(), device().subtag(tempstring,"harddriv"));
}
else
{
err = m_origchd.open(*image_core_file(), true);
if (err == CHDERR_NONE)
{
m_chd = &m_origchd;
}
else if (err == CHDERR_FILE_NOT_WRITEABLE)
{
err = m_origchd.open(*image_core_file(), false);
if (err == CHDERR_NONE)
{
err = open_disk_diff(device().machine().options(), basename_noext(), m_origchd, m_diffchd);
if (err == CHDERR_NONE)
{
m_chd = &m_diffchd;
}
}
}
}
if (m_chd != NULL)
{
/* open the hard disk file */
m_hard_disk_handle = hard_disk_open(m_chd);
if (m_hard_disk_handle != NULL)
return IMAGE_INIT_PASS;
}
/* if we had an error, close out the CHD */
m_origchd.close();
m_diffchd.close();
m_chd = NULL;
seterror(IMAGE_ERROR_UNSPECIFIED, chd_file::error_string(err));
return IMAGE_INIT_FAIL;
}
/*************************************
*
* Get the CHD file (from the src/chd.c core)
* after an image has been opened with the hd core
*
*************************************/
chd_file *diablo_image_device::get_chd_file()
{
chd_file *result = NULL;
hard_disk_file *hd_file = get_hard_disk_file();
if (hd_file)
result = hard_disk_get_chd(hd_file);
return result;
}

100
src/emu/imagedev/diablo.h Normal file
View File

@ -0,0 +1,100 @@
/**********************************************************
* DIABLO drive image to hard disk interface
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
**********************************************************/
#ifndef _IMAGEDEV_DIABLO_H_
#define _IMAGEDEV_DIABLO_H_
#include "harddisk.h"
#define DIABLO_TAG(_id) "diablo"#_id
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
// ======================> diablo_interface
struct diablo_interface
{
const char * m_interface;
device_image_display_info_func m_device_displayinfo;
};
// ======================> diablo_image_device
class diablo_image_device : public device_t,
public diablo_interface,
public device_image_interface
{
public:
// construction/destruction
diablo_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual ~diablo_image_device();
void set_device_load(device_image_load_delegate _load) { m_device_image_load = _load; }
void set_device_unload(device_image_func_delegate _unload) { m_device_image_unload = _unload; }
// image-level overrides
virtual bool call_load();
virtual bool call_create(int create_format, option_resolution *create_args);
virtual void call_unload();
virtual void call_display_info() { if (m_device_displayinfo) m_device_displayinfo(*this); }
virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { load_software_part_region(*this, swlist, swname, start_entry ); return TRUE; }
virtual iodevice_t image_type() const { return IO_HARDDISK; }
virtual bool is_readable() const { return 1; }
virtual bool is_writeable() const { return 1; }
virtual bool is_creatable() const { return 0; }
virtual bool must_be_loaded() const { return 0; }
virtual bool is_reset_on_load() const { return 0; }
virtual const char *image_interface() const { return m_interface; }
virtual const char *file_extensions() const { return "chd,dsk"; }
virtual const option_guide *create_option_guide() const;
// specific implementation
hard_disk_file *get_hard_disk_file() { return m_hard_disk_handle; }
chd_file *get_chd_file();
protected:
// device-level overrides
virtual void device_config_complete();
virtual void device_start();
virtual void device_stop();
int internal_load_dsk();
chd_file *m_chd;
chd_file m_origchd; /* handle to the original CHD */
chd_file m_diffchd; /* handle to the diff CHD */
hard_disk_file *m_hard_disk_handle;
device_image_load_delegate m_device_image_load;
device_image_func_delegate m_device_image_unload;
};
// device type definition
extern const device_type DIABLO;
/***************************************************************************
DEVICE CONFIGURATION MACROS
***************************************************************************/
#define MCFG_DIABLO_ADD(_tag) \
MCFG_DEVICE_ADD(_tag, DIABLO, 0)
#define MCFG_DIABLO_CONFIG_ADD(_tag,_config) \
MCFG_DEVICE_ADD(_tag, DIABLO, 0) \
MCFG_DEVICE_CONFIG(_config)
#define MCFG_DIABLO_LOAD(_class,_load) \
static_cast<diablo_image_device *>(device)->set_device_load( DEVICE_IMAGE_LOAD_DELEGATE(_class,_load));
#define MCFG_DIABLO_UNLOAD(_class,_unload) \
static_cast<diablo_image_device *>(device)->set_device_unload( DEVICE_IMAGE_UNLOAD_DELEGATE(_class,_unload));
#endif /* _IMAGEDEV_DIABLO_H_ */

1466
src/emu/machine/diablo_hd.c Normal file

File diff suppressed because it is too large Load Diff

180
src/emu/machine/diablo_hd.h Normal file
View File

@ -0,0 +1,180 @@
/**********************************************************
* DIABLO31 and DIABLO44 hard drive support
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
**********************************************************/
#if !defined(_DIABLO_HD_DEVICE_)
#define _DIABLO_HD_DEVICE_
#include "emu.h"
#include "imagedev/diablo.h"
#ifndef DIABLO_DEBUG
#define DIABLO_DEBUG 1 //!< set to 1 to enable debug log output
#endif
#define DIABLO_HD_0 "diablo0"
#define DIABLO_HD_1 "diablo1"
extern const device_type DIABLO_HD;
class diablo_hd_device : public device_t
{
public:
diablo_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
~diablo_hd_device();
static const int DIABLO_UNIT_MAX = 2; //!< max number of drive units
static const int DIABLO_CYLINDERS = 203; //!< number of cylinders per drive
static const int DIABLO_CYLINDER_MASK = 0777; //!< bit maks for cylinder number (9 bits)
static const int DIABLO_SPT = 12; //!< number of sectors per track
static const int DIABLO_SECTOR_MASK = 017; //!< bit maks for sector number (4 bits)
static const int DIABLO_HEADS = 2; //!< number of heads per drive
static const int DIABLO_HEAD_MASK = 1; //!< bit maks for head number (1 bit)
static const int DIABLO_PAGES = 203*2*12; //!< number of pages per drive
//! convert a cylinder/head/sector to a logical block address (page)
static inline int DIABLO_PAGE(int c, int h, int s) { return (c * DIABLO_HEADS + h) * DIABLO_SPT + s; }
void set_sector_callback(void* cookie, void(*callback)(void*, int));
int bits_per_sector() const;
const char* description() const;
int unit() const;
attotime rotation_time() const;
attotime sector_time() const;
attotime bit_time() const;
int get_seek_read_write_0() const;
int get_ready_0() const;
int get_sector_mark_0() const;
int get_addx_acknowledge_0() const;
int get_log_addx_interlock_0() const;
int get_seek_incomplete_0() const;
int get_cylinder() const;
int get_head() const;
int get_sector() const;
int get_page() const;
void select(int unit);
void set_head(int head);
void set_cylinder(int cylinder);
void set_restore(int restore);
void set_strobe(int strobe);
void set_egate(int gate);
void set_wrgate(int gate);
void set_rdgate(int gate);
void wr_data(int index, int wrdata);
int rd_data(int index);
int rd_clock(int index);
protected:
virtual void device_start();
virtual void device_reset();
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
virtual machine_config_constructor device_mconfig_additions() const;
private:
#if DIABLO_DEBUG
int m_log_level;
void logprintf(int level, const char* format, ...);
# define LOG_DRIVE(x) logprintf x
#else
# define LOG_DRIVE(x)
#endif
bool m_diablo31; //!< true, if this is a DIABLO31 drive
int m_unit; //!< drive unit number (0 or 1)
char m_description[32]; //!< description of the drive(s)
int m_packs; //!< number of packs in drive (1 or 2)
attotime m_rotation_time; //!< rotation time in atto seconds
attotime m_sector_time; //!< sector time in atto seconds
attotime m_sector_mark_0_time; //!< sector mark going 0 before sector pulse time
attotime m_sector_mark_1_time; //!< sector mark going 1 after sector pulse time
attotime m_bit_time; //!< bit time in atto seconds
int m_s_r_w_0; //!< drive seek/read/write signal (active 0)
int m_ready_0; //!< drive ready signal (active 0)
int m_sector_mark_0; //!< sector mark (0 if new sector)
int m_addx_acknowledge_0; //!< address acknowledge, i.e. seek successful (active 0)
int m_log_addx_interlock_0; //!< log address interlock, i.e. seek in progress (active 0)
int m_seek_incomplete_0; //!< seek incomplete, i.e. seek in progress (active 0)
int m_egate_0; //!< erase gate
int m_wrgate_0; //!< write gate
int m_rdgate_0; //!< read gate
int m_cylinders; //!< total number of cylinders
int m_pages; //!< total number of pages
int m_seekto; //!< seek to cylinder number
int m_restore; //!< restore to cylinder 0 flag
int m_cylinder; //!< current cylinder number
int m_head; //!< current head (track) number on cylinder
int m_sector; //!< current sector number in track
int m_page; //!< current page (derived from cylinder, head and sector)
UINT8** m_cache; //!< pages raw bytes
UINT32** m_bits; //!< pages expanded to bits
int m_rdfirst; //!< set to first bit of a sector that is read from
int m_rdlast; //!< set to last bit of a sector that was read from
int m_wrfirst; //!< set to non-zero if a sector is written to
int m_wrlast; //!< set to last bit of a sector that was written to
void *m_sector_callback_cookie; //!< cookie to pass to callback
void (*m_sector_callback)(void*,int); //!< callback to call at the start of each sector
emu_timer* m_timer; //!< sector timer
diablo_image_device* m_image; //!< diablo_image_device interfacing the CHD
chd_file* m_handle; //!< underlying CHD handle
hard_disk_file* m_disk; //!< underlying hard disk file
//! translate C/H/S to a page and read the sector
void read_sector();
//! compute the checksum of a record
int cksum(UINT8 *src, size_t size, int start);
//! expand a series of clock bits and 0 data bits
size_t expand_zeroes(UINT32 *bits, size_t dst, size_t size);
//! expand a series of 0 words and write a final sync bit
size_t expand_sync(UINT32 *bits, size_t dst, size_t size);
//! expand a record of words into a array of bits at dst
size_t expand_record(UINT32 *bits, size_t dst, UINT8 *field, size_t size);
//! expand a record's checksum word to 32 bits
size_t expand_cksum(UINT32 *bits, size_t dst, UINT8 *field, size_t size);
//! expand a sector into an array of clock and data bits
UINT32* expand_sector();
#if DIABLO_DEBUG
//! dump a number of words as ASCII characters
void dump_ascii(UINT8 *src, size_t size);
//! dump a record's contents
size_t dump_record(UINT8 *src, size_t addr, size_t size, const char *name, int cr);
#endif
//! find a sync bit in an array of clock and data bits
size_t squeeze_sync(UINT32 *bits, size_t src, size_t size);
//! find a 16 x 0 bits sequence in an array of clock and data bits
size_t squeeze_unsync(UINT32 *bits, size_t src, size_t size);
//! squeeze an array of clock and data bits into a sector's record
size_t squeeze_record(UINT32 *bits, size_t src, UINT8 *field, size_t size);
//! squeeze an array of 32 clock and data bits into a checksum word
size_t squeeze_cksum(UINT32 *bits, size_t src, int *cksum);
//! squeeze a array of clock and data bits into a sector's data
void squeeze_sector();
//! deassert the sector mark
void sector_mark_1();
//! assert the sector mark and read the next sector
void sector_mark_0();
};
#define MCFG_DIABLO_DRIVES_ADD() \
MCFG_DEVICE_ADD(DIABLO_HD_0, DIABLO_HD, ATTOSECONDS_TO_HZ(attotime::from_nsec(300).as_double())) \
MCFG_DEVICE_ADD(DIABLO_HD_1, DIABLO_HD, ATTOSECONDS_TO_HZ(attotime::from_nsec(300).as_double()))
#endif // !defined(_DIABLO_HD_DEVICE_)

View File

@ -1829,3 +1829,11 @@ ifneq ($(filter WOZFDC,$(MACHINES)),)
MACHINEOBJS += $(MACHINEOBJ)/wozfdc.o
endif
#-------------------------------------------------
#
#@src/emu/machine/diablo_hd.h,MACHINES += DIABLO_HD
#-------------------------------------------------
ifneq ($(filter DIABLO_HD,$(MACHINES)),)
MACHINEOBJS += $(MACHINEOBJ)/diablo_hd.o
endif

View File

@ -219,8 +219,19 @@ void CLIB_DECL logerror(const char *format, ...)
{
va_list arg;
va_start(arg, format);
if (global_machine != NULL)
global_machine->vlogerror(format, arg);
vlogerror(format, arg);
va_end(arg);
}
/*-------------------------------------------------
vlogerror - log to the debugger and any other
OSD-defined output streams
-------------------------------------------------*/
void CLIB_DECL vlogerror(const char *format, va_list arg)
{
if (global_machine != NULL)
global_machine->vlogerror(format, arg);
}

View File

@ -101,6 +101,7 @@ void CLIB_DECL popmessage(const char *format, ...) ATTR_PRINTF(1,2);
// log to the standard error.log file
void CLIB_DECL logerror(const char *format, ...) ATTR_PRINTF(1,2);
void CLIB_DECL vlogerror(const char *format, va_list arg);
#endif /* __MAME_H__ */

304
src/mess/drivers/alto2.c Normal file
View File

@ -0,0 +1,304 @@
/***************************************************************************
* Xerox AltoII driver for MESS
*
* Copyright Juergen Buchmueller <pullmoll@t-online.de>
*
* Licenses: MAME, GPLv2
***************************************************************************/
#include "emu.h"
#include "rendlay.h"
#include "cpu/alto2/alto2cpu.h"
#include "machine/diablo_hd.h"
class alto2_state : public driver_device
{
public:
alto2_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_io_row0(*this, "ROW0"),
m_io_row1(*this, "ROW1"),
m_io_row2(*this, "ROW2"),
m_io_row3(*this, "ROW3"),
m_io_row4(*this, "ROW4"),
m_io_row5(*this, "ROW5"),
m_io_row6(*this, "ROW6"),
m_io_row7(*this, "ROW7"),
m_io_config(*this, "CONFIG")
{ }
DECLARE_DRIVER_INIT(alto2);
DECLARE_MACHINE_RESET(alto2);
protected:
required_device<cpu_device> m_maincpu;
required_ioport m_io_row0;
required_ioport m_io_row1;
required_ioport m_io_row2;
required_ioport m_io_row3;
required_ioport m_io_row4;
required_ioport m_io_row5;
required_ioport m_io_row6;
required_ioport m_io_row7;
optional_ioport m_io_config;
};
/* Input Ports */
#define PORT_KEY(_bit,_code,_char1,_char2,_name) \
PORT_BIT(_bit, IP_ACTIVE_LOW, IPT_KEYBOARD) \
PORT_CODE(_code) PORT_NAME(_name) \
PORT_CHAR(_char1) PORT_CHAR(_char2)
#define SPACING " "
static INPUT_PORTS_START( alto2 )
PORT_START("ROW0")
PORT_KEY(A2_KEY_5, KEYCODE_5, '5', '%', "5" SPACING "%") //!< normal: 5 shifted: %
PORT_KEY(A2_KEY_4, KEYCODE_4, '4', '$', "4" SPACING "$") //!< normal: 4 shifted: $
PORT_KEY(A2_KEY_6, KEYCODE_6, '6', '~', "6" SPACING "~") //!< normal: 6 shifted: ~
PORT_KEY(A2_KEY_E, KEYCODE_E, 'e', 'E', "e" SPACING "E") //!< normal: e shifted: E
PORT_KEY(A2_KEY_7, KEYCODE_7, '7', '&', "7" SPACING "&") //!< normal: 7 shifted: &
PORT_KEY(A2_KEY_D, KEYCODE_D, 'd', 'D', "d" SPACING "D") //!< normal: d shifted: D
PORT_KEY(A2_KEY_U, KEYCODE_U, 'u', 'U', "u" SPACING "U") //!< normal: u shifted: U
PORT_KEY(A2_KEY_V, KEYCODE_V, 'v', 'V', "v" SPACING "V") //!< normal: v shifted: V
PORT_KEY(A2_KEY_0, KEYCODE_0, '0', ')', "0" SPACING ")") //!< normal: 0 shifted: )
PORT_KEY(A2_KEY_K, KEYCODE_K, 'k', 'K', "k" SPACING "K") //!< normal: k shifted: K
PORT_KEY(A2_KEY_MINUS, KEYCODE_MINUS, '-', '_', "-" SPACING "_") //!< normal: - shifted: _
PORT_KEY(A2_KEY_P, KEYCODE_P, 'p', 'P', "p" SPACING "P") //!< normal: p shifted: P
PORT_KEY(A2_KEY_SLASH, KEYCODE_SLASH, '/', '?', "/" SPACING "?") //!< normal: / shifted: ?
PORT_KEY(A2_KEY_BACKSLASH, KEYCODE_BACKSLASH, '\\', '|', "\\" SPACING "|") //!< normal: \ shifted: |
PORT_KEY(A2_KEY_LF, KEYCODE_DOWN, 10, 10, "LF" ) //!< normal: LF shifted: ?
PORT_KEY(A2_KEY_BS, KEYCODE_BACKSPACE, 8, 8, "BS" ) //!< normal: BS shifted: ?
PORT_START("ROW1")
PORT_KEY(A2_KEY_3, KEYCODE_3, '3', '#', "3" SPACING "#") //!< normal: 3 shifted: #
PORT_KEY(A2_KEY_2, KEYCODE_2, '2', '@', "2" SPACING "@") //!< normal: 2 shifted: @
PORT_KEY(A2_KEY_W, KEYCODE_W, 'w', 'W', "w" SPACING "W") //!< normal: w shifted: W
PORT_KEY(A2_KEY_Q, KEYCODE_Q, 'q', 'Q', "q" SPACING "Q") //!< normal: q shifted: Q
PORT_KEY(A2_KEY_S, KEYCODE_S, 's', 'S', "s" SPACING "S") //!< normal: s shifted: S
PORT_KEY(A2_KEY_A, KEYCODE_A, 'a', 'A', "a" SPACING "A") //!< normal: a shifted: A
PORT_KEY(A2_KEY_9, KEYCODE_9, '9', '(', "9" SPACING "(") //!< normal: 9 shifted: (
PORT_KEY(A2_KEY_I, KEYCODE_I, 'i', 'I', "i" SPACING "I") //!< normal: i shifted: I
PORT_KEY(A2_KEY_X, KEYCODE_X, 'x', 'X', "x" SPACING "X") //!< normal: x shifted: X
PORT_KEY(A2_KEY_O, KEYCODE_O, 'o', 'O', "o" SPACING "O") //!< normal: o shifted: O
PORT_KEY(A2_KEY_L, KEYCODE_L, 'l', 'L', "l" SPACING "L") //!< normal: l shifted: L
PORT_KEY(A2_KEY_COMMA, KEYCODE_COMMA, ',', '<', "," SPACING "<") //!< normal: , shifted: <
PORT_KEY(A2_KEY_QUOTE, KEYCODE_QUOTE, 39, 34, "'" SPACING "\"") //!< normal: ' shifted: "
PORT_KEY(A2_KEY_RBRACKET, KEYCODE_CLOSEBRACE, ']', '}', "]" SPACING "}") //!< normal: ] shifted: }
PORT_KEY(A2_KEY_BLANK_MID, KEYCODE_END, 0, 0, "MID" ) //!< middle blank key
PORT_KEY(A2_KEY_BLANK_TOP, KEYCODE_PGUP, 0, 0, "TOP" ) //!< top blank key
PORT_START("ROW2")
PORT_KEY(A2_KEY_1, KEYCODE_1, '1', '!', "1" SPACING "!") //!< normal: 1 shifted: !
PORT_KEY(A2_KEY_ESCAPE, KEYCODE_ESC, 27, 0, "ESC" ) //!< normal: ESC shifted: ?
PORT_KEY(A2_KEY_TAB, KEYCODE_TAB, 9, 0, "TAB" ) //!< normal: TAB shifted: ?
PORT_KEY(A2_KEY_F, KEYCODE_F, 'f', 'F', "f" SPACING "F") //!< normal: f shifted: F
PORT_KEY(A2_KEY_CTRL, KEYCODE_LCONTROL, 0, 0, "CTRL" ) //!< CTRL
PORT_KEY(A2_KEY_C, KEYCODE_C, 'c', 'C', "c" SPACING "C") //!< normal: c shifted: C
PORT_KEY(A2_KEY_J, KEYCODE_J, 'j', 'J', "j" SPACING "J") //!< normal: j shifted: J
PORT_KEY(A2_KEY_B, KEYCODE_B, 'b', 'B', "b" SPACING "B") //!< normal: b shifted: B
PORT_KEY(A2_KEY_Z, KEYCODE_Z, 'z', 'Z', "z" SPACING "Z") //!< normal: z shifted: Z
PORT_KEY(A2_KEY_LSHIFT, KEYCODE_LSHIFT, UCHAR_SHIFT_1, 0, "LSHIFT" ) //!< LSHIFT
PORT_KEY(A2_KEY_PERIOD, KEYCODE_STOP, '.', '>', "." SPACING ">") //!< normal: . shifted: >
PORT_KEY(A2_KEY_SEMICOLON, KEYCODE_COLON, ';', ':', ";" SPACING ":") //!< normal: ; shifted: :
PORT_KEY(A2_KEY_RETURN, KEYCODE_ENTER, 13, 0, "RETURN" ) //!< RETURN
PORT_KEY(A2_KEY_LEFTARROW, KEYCODE_LEFT, 0, 0, "???" SPACING "???") //!< normal: left arrow shifted: up arrow (caret)
PORT_KEY(A2_KEY_DEL, KEYCODE_DEL, UCHAR_MAMEKEY(DEL), 0, "DEL" ) //!< normal: DEL shifted: ?
PORT_KEY(A2_KEY_MSW_2_17, KEYCODE_MENU, 0, 0, "MSW2/17" ) //!< unused on Microswitch KDB
PORT_START("ROW3")
PORT_KEY(A2_KEY_R, KEYCODE_R, 'r', 'R', "r" SPACING "R") //!< normal: r shifted: R
PORT_KEY(A2_KEY_T, KEYCODE_T, 't', 'T', "t" SPACING "T") //!< normal: t shifted: T
PORT_KEY(A2_KEY_G, KEYCODE_G, 'g', 'G', "g" SPACING "G") //!< normal: g shifted: G
PORT_KEY(A2_KEY_Y, KEYCODE_Y, 'y', 'Y', "y" SPACING "Y") //!< normal: y shifted: Y
PORT_KEY(A2_KEY_H, KEYCODE_H, 'h', 'H', "h" SPACING "H") //!< normal: h shifted: H
PORT_KEY(A2_KEY_8, KEYCODE_8, '8', '*', "8" SPACING "*") //!< normal: 8 shifted: *
PORT_KEY(A2_KEY_N, KEYCODE_N, 'n', 'N', "n" SPACING "N") //!< normal: n shifted: N
PORT_KEY(A2_KEY_M, KEYCODE_M, 'm', 'M', "m" SPACING "M") //!< normal: m shifted: M
PORT_KEY(A2_KEY_LOCK, KEYCODE_SCRLOCK, 0, 0, "LOCK" ) //!< LOCK
PORT_KEY(A2_KEY_SPACE, KEYCODE_SPACE, 32, 0, "SPACE" ) //!< SPACE
PORT_KEY(A2_KEY_LBRACKET, KEYCODE_OPENBRACE, '[', '{', "[" SPACING "{") //!< normal: [ shifted: {
PORT_KEY(A2_KEY_EQUALS, KEYCODE_EQUALS, '=', '+', "=" SPACING "+") //!< normal: = shifted: +
PORT_KEY(A2_KEY_RSHIFT, KEYCODE_RSHIFT, UCHAR_SHIFT_2, 0, "RSHIFT" ) //!< RSHIFT
PORT_KEY(A2_KEY_BLANK_BOT, KEYCODE_PGDN, 0, 0, "BOT" ) //!< bottom blank key
PORT_KEY(A2_KEY_MSW_3_16, KEYCODE_HOME, 0, 0, "MSW3/16" ) //!< unused on Microswitch KDB
PORT_KEY(A2_KEY_MSW_3_17, KEYCODE_INSERT, 0, 0, "MSW3/17" ) //!< unused on Microswitch KDB
PORT_START("ROW4")
PORT_KEY(A2_KEY_FR2, KEYCODE_F6, 0, 0, "FR2" ) //!< ADL right function key 2
PORT_KEY(A2_KEY_FL2, KEYCODE_F2, 0, 0, "FL2" ) //!< ADL left function key 2
PORT_START("ROW5")
PORT_KEY(A2_KEY_FR4, KEYCODE_F8, 0, 0, "FR4" ) //!< ADL right funtion key 4
PORT_KEY(A2_KEY_BW, KEYCODE_F10, 0, 0, "BW" ) //!< ADL BW (?)
PORT_START("ROW6")
PORT_KEY(A2_KEY_FR3, KEYCODE_F7, 0, 0, "FR3" ) //!< ADL right function key 3
PORT_KEY(A2_KEY_FL1, KEYCODE_F1, 0, 0, "FL1" ) //!< ADL left function key 1
PORT_KEY(A2_KEY_FL3, KEYCODE_F3, 0, 0, "FL3" ) //!< ADL left function key 3
PORT_START("ROW7")
PORT_KEY(A2_KEY_FR1, KEYCODE_F5, 0, 0, "FR1" ) //!< ADL right function key 1
PORT_KEY(A2_KEY_FL4, KEYCODE_F4, 0, 0, "FL4" ) //!< ADL left function key 4
PORT_KEY(A2_KEY_FR5, KEYCODE_F9, 0, 0, "FR5" ) //!< ADL right function key 5
PORT_START("mouseb0") // Mouse button 0
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Mouse RED (left)") PORT_PLAYER(1) PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER( ":maincpu", alto2_cpu_device, mouse_button_0, 0 )
PORT_START("mouseb1") // Mouse button 1
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Mouse BLUE (right)") PORT_PLAYER(1) PORT_CODE(MOUSECODE_BUTTON2) PORT_CHANGED_MEMBER( ":maincpu", alto2_cpu_device, mouse_button_1, 0 )
PORT_START("mouseb2") // Mouse button 2
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("Mouse YELLOW (middle)") PORT_PLAYER(1) PORT_CODE(MOUSECODE_BUTTON3) PORT_CHANGED_MEMBER( ":maincpu", alto2_cpu_device, mouse_button_2, 0 )
PORT_START("mousex") // Mouse - X AXIS
PORT_BIT( 0xffff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_CHANGED_MEMBER( ":maincpu", alto2_cpu_device, mouse_motion_x, 0 )
PORT_START("mousey") // Mouse - Y AXIS
PORT_BIT( 0xffff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_CHANGED_MEMBER( ":maincpu", alto2_cpu_device, mouse_motion_y, 0 )
PORT_START("CONFIG") /* Memory switch on AIM board */
PORT_CONFNAME( 0x01, 0x01, "Memory switch")
PORT_CONFSETTING( 0x00, "on")
PORT_CONFSETTING( 0x01, "off")
PORT_CONFNAME( 0x70, 0x00, "Ethernet breath-of-life")
PORT_CONFSETTING( 0x00, "off")
PORT_CONFSETTING( 0x10, "5 seconds")
PORT_CONFSETTING( 0x20, "10 seconds")
PORT_CONFSETTING( 0x30, "15 seconds")
PORT_CONFSETTING( 0x40, "30 seconds")
PORT_CONFSETTING( 0x50, "60 seconds")
PORT_CONFSETTING( 0x60, "90 seconds")
PORT_CONFSETTING( 0x70, "120 seconds")
PORT_START("ETHERID")
PORT_DIPNAME( 0377, 0042, "Ethernet ID")
PORT_DIPSETTING( 0000, "No ether") PORT_DIPSETTING( 0001, "ID 001") PORT_DIPSETTING( 0002, "ID 002") PORT_DIPSETTING( 0003, "ID 003")
PORT_DIPSETTING( 0004, "ID 004") PORT_DIPSETTING( 0005, "ID 005") PORT_DIPSETTING( 0006, "ID 006") PORT_DIPSETTING( 0007, "ID 007")
PORT_DIPSETTING( 0010, "ID 010") PORT_DIPSETTING( 0011, "ID 011") PORT_DIPSETTING( 0012, "ID 012") PORT_DIPSETTING( 0013, "ID 013")
PORT_DIPSETTING( 0014, "ID 014") PORT_DIPSETTING( 0015, "ID 015") PORT_DIPSETTING( 0016, "ID 016") PORT_DIPSETTING( 0017, "ID 017")
PORT_DIPSETTING( 0020, "ID 020") PORT_DIPSETTING( 0021, "ID 021") PORT_DIPSETTING( 0022, "ID 022") PORT_DIPSETTING( 0023, "ID 023")
PORT_DIPSETTING( 0024, "ID 024") PORT_DIPSETTING( 0025, "ID 025") PORT_DIPSETTING( 0026, "ID 026") PORT_DIPSETTING( 0027, "ID 027")
PORT_DIPSETTING( 0030, "ID 030") PORT_DIPSETTING( 0031, "ID 031") PORT_DIPSETTING( 0032, "ID 032") PORT_DIPSETTING( 0033, "ID 033")
PORT_DIPSETTING( 0034, "ID 034") PORT_DIPSETTING( 0035, "ID 035") PORT_DIPSETTING( 0036, "ID 036") PORT_DIPSETTING( 0037, "ID 037")
PORT_DIPSETTING( 0040, "ID 040") PORT_DIPSETTING( 0041, "ID 041") PORT_DIPSETTING( 0042, "ID 042") PORT_DIPSETTING( 0043, "ID 043")
PORT_DIPSETTING( 0044, "ID 044") PORT_DIPSETTING( 0045, "ID 045") PORT_DIPSETTING( 0046, "ID 046") PORT_DIPSETTING( 0047, "ID 047")
PORT_DIPSETTING( 0050, "ID 050") PORT_DIPSETTING( 0051, "ID 051") PORT_DIPSETTING( 0052, "ID 052") PORT_DIPSETTING( 0053, "ID 053")
PORT_DIPSETTING( 0054, "ID 054") PORT_DIPSETTING( 0055, "ID 055") PORT_DIPSETTING( 0056, "ID 056") PORT_DIPSETTING( 0057, "ID 057")
PORT_DIPSETTING( 0060, "ID 060") PORT_DIPSETTING( 0061, "ID 061") PORT_DIPSETTING( 0062, "ID 062") PORT_DIPSETTING( 0063, "ID 063")
PORT_DIPSETTING( 0064, "ID 064") PORT_DIPSETTING( 0065, "ID 065") PORT_DIPSETTING( 0066, "ID 066") PORT_DIPSETTING( 0067, "ID 067")
PORT_DIPSETTING( 0070, "ID 070") PORT_DIPSETTING( 0071, "ID 071") PORT_DIPSETTING( 0072, "ID 072") PORT_DIPSETTING( 0073, "ID 073")
PORT_DIPSETTING( 0074, "ID 074") PORT_DIPSETTING( 0075, "ID 075") PORT_DIPSETTING( 0076, "ID 076") PORT_DIPSETTING( 0077, "ID 077")
PORT_DIPSETTING( 0100, "ID 100") PORT_DIPSETTING( 0101, "ID 101") PORT_DIPSETTING( 0102, "ID 102") PORT_DIPSETTING( 0103, "ID 103")
PORT_DIPSETTING( 0104, "ID 104") PORT_DIPSETTING( 0105, "ID 105") PORT_DIPSETTING( 0106, "ID 106") PORT_DIPSETTING( 0107, "ID 107")
PORT_DIPSETTING( 0110, "ID 110") PORT_DIPSETTING( 0111, "ID 111") PORT_DIPSETTING( 0112, "ID 112") PORT_DIPSETTING( 0113, "ID 113")
PORT_DIPSETTING( 0114, "ID 114") PORT_DIPSETTING( 0115, "ID 115") PORT_DIPSETTING( 0116, "ID 116") PORT_DIPSETTING( 0117, "ID 117")
PORT_DIPSETTING( 0120, "ID 120") PORT_DIPSETTING( 0121, "ID 121") PORT_DIPSETTING( 0122, "ID 122") PORT_DIPSETTING( 0123, "ID 123")
PORT_DIPSETTING( 0124, "ID 124") PORT_DIPSETTING( 0125, "ID 125") PORT_DIPSETTING( 0126, "ID 126") PORT_DIPSETTING( 0127, "ID 127")
PORT_DIPSETTING( 0130, "ID 130") PORT_DIPSETTING( 0131, "ID 131") PORT_DIPSETTING( 0132, "ID 132") PORT_DIPSETTING( 0133, "ID 133")
PORT_DIPSETTING( 0134, "ID 134") PORT_DIPSETTING( 0135, "ID 135") PORT_DIPSETTING( 0136, "ID 136") PORT_DIPSETTING( 0137, "ID 137")
PORT_DIPSETTING( 0140, "ID 140") PORT_DIPSETTING( 0141, "ID 141") PORT_DIPSETTING( 0142, "ID 142") PORT_DIPSETTING( 0143, "ID 143")
PORT_DIPSETTING( 0144, "ID 144") PORT_DIPSETTING( 0145, "ID 145") PORT_DIPSETTING( 0146, "ID 146") PORT_DIPSETTING( 0147, "ID 147")
PORT_DIPSETTING( 0150, "ID 150") PORT_DIPSETTING( 0151, "ID 151") PORT_DIPSETTING( 0152, "ID 152") PORT_DIPSETTING( 0153, "ID 153")
PORT_DIPSETTING( 0154, "ID 154") PORT_DIPSETTING( 0155, "ID 155") PORT_DIPSETTING( 0156, "ID 156") PORT_DIPSETTING( 0157, "ID 157")
PORT_DIPSETTING( 0160, "ID 160") PORT_DIPSETTING( 0161, "ID 161") PORT_DIPSETTING( 0162, "ID 162") PORT_DIPSETTING( 0163, "ID 163")
PORT_DIPSETTING( 0164, "ID 164") PORT_DIPSETTING( 0165, "ID 165") PORT_DIPSETTING( 0166, "ID 166") PORT_DIPSETTING( 0167, "ID 167")
PORT_DIPSETTING( 0170, "ID 170") PORT_DIPSETTING( 0171, "ID 171") PORT_DIPSETTING( 0172, "ID 172") PORT_DIPSETTING( 0173, "ID 173")
PORT_DIPSETTING( 0174, "ID 174") PORT_DIPSETTING( 0175, "ID 175") PORT_DIPSETTING( 0176, "ID 176") PORT_DIPSETTING( 0177, "ID 177")
PORT_DIPSETTING( 0200, "ID 200") PORT_DIPSETTING( 0201, "ID 201") PORT_DIPSETTING( 0202, "ID 202") PORT_DIPSETTING( 0203, "ID 203")
PORT_DIPSETTING( 0204, "ID 204") PORT_DIPSETTING( 0205, "ID 205") PORT_DIPSETTING( 0206, "ID 206") PORT_DIPSETTING( 0207, "ID 207")
PORT_DIPSETTING( 0210, "ID 210") PORT_DIPSETTING( 0211, "ID 211") PORT_DIPSETTING( 0212, "ID 212") PORT_DIPSETTING( 0213, "ID 213")
PORT_DIPSETTING( 0214, "ID 214") PORT_DIPSETTING( 0215, "ID 215") PORT_DIPSETTING( 0216, "ID 216") PORT_DIPSETTING( 0217, "ID 217")
PORT_DIPSETTING( 0220, "ID 220") PORT_DIPSETTING( 0221, "ID 221") PORT_DIPSETTING( 0222, "ID 222") PORT_DIPSETTING( 0223, "ID 223")
PORT_DIPSETTING( 0224, "ID 224") PORT_DIPSETTING( 0225, "ID 225") PORT_DIPSETTING( 0226, "ID 226") PORT_DIPSETTING( 0227, "ID 227")
PORT_DIPSETTING( 0230, "ID 230") PORT_DIPSETTING( 0231, "ID 231") PORT_DIPSETTING( 0232, "ID 232") PORT_DIPSETTING( 0233, "ID 233")
PORT_DIPSETTING( 0234, "ID 234") PORT_DIPSETTING( 0235, "ID 235") PORT_DIPSETTING( 0236, "ID 236") PORT_DIPSETTING( 0237, "ID 237")
PORT_DIPSETTING( 0240, "ID 240") PORT_DIPSETTING( 0241, "ID 241") PORT_DIPSETTING( 0242, "ID 242") PORT_DIPSETTING( 0243, "ID 243")
PORT_DIPSETTING( 0244, "ID 244") PORT_DIPSETTING( 0245, "ID 245") PORT_DIPSETTING( 0246, "ID 246") PORT_DIPSETTING( 0247, "ID 247")
PORT_DIPSETTING( 0250, "ID 250") PORT_DIPSETTING( 0251, "ID 251") PORT_DIPSETTING( 0252, "ID 252") PORT_DIPSETTING( 0253, "ID 253")
PORT_DIPSETTING( 0254, "ID 254") PORT_DIPSETTING( 0255, "ID 255") PORT_DIPSETTING( 0256, "ID 256") PORT_DIPSETTING( 0257, "ID 257")
PORT_DIPSETTING( 0260, "ID 260") PORT_DIPSETTING( 0261, "ID 261") PORT_DIPSETTING( 0262, "ID 262") PORT_DIPSETTING( 0263, "ID 263")
PORT_DIPSETTING( 0264, "ID 264") PORT_DIPSETTING( 0265, "ID 265") PORT_DIPSETTING( 0266, "ID 266") PORT_DIPSETTING( 0267, "ID 267")
PORT_DIPSETTING( 0270, "ID 270") PORT_DIPSETTING( 0271, "ID 271") PORT_DIPSETTING( 0272, "ID 272") PORT_DIPSETTING( 0273, "ID 273")
PORT_DIPSETTING( 0274, "ID 274") PORT_DIPSETTING( 0275, "ID 275") PORT_DIPSETTING( 0276, "ID 276") PORT_DIPSETTING( 0277, "ID 277")
PORT_DIPSETTING( 0300, "ID 300") PORT_DIPSETTING( 0301, "ID 301") PORT_DIPSETTING( 0302, "ID 302") PORT_DIPSETTING( 0303, "ID 303")
PORT_DIPSETTING( 0304, "ID 304") PORT_DIPSETTING( 0305, "ID 305") PORT_DIPSETTING( 0306, "ID 306") PORT_DIPSETTING( 0307, "ID 307")
PORT_DIPSETTING( 0310, "ID 310") PORT_DIPSETTING( 0311, "ID 311") PORT_DIPSETTING( 0312, "ID 312") PORT_DIPSETTING( 0313, "ID 313")
PORT_DIPSETTING( 0314, "ID 314") PORT_DIPSETTING( 0315, "ID 315") PORT_DIPSETTING( 0316, "ID 316") PORT_DIPSETTING( 0317, "ID 317")
PORT_DIPSETTING( 0320, "ID 320") PORT_DIPSETTING( 0321, "ID 321") PORT_DIPSETTING( 0322, "ID 322") PORT_DIPSETTING( 0323, "ID 323")
PORT_DIPSETTING( 0324, "ID 324") PORT_DIPSETTING( 0325, "ID 325") PORT_DIPSETTING( 0326, "ID 326") PORT_DIPSETTING( 0327, "ID 327")
PORT_DIPSETTING( 0330, "ID 330") PORT_DIPSETTING( 0331, "ID 331") PORT_DIPSETTING( 0332, "ID 332") PORT_DIPSETTING( 0333, "ID 333")
PORT_DIPSETTING( 0334, "ID 334") PORT_DIPSETTING( 0335, "ID 335") PORT_DIPSETTING( 0336, "ID 336") PORT_DIPSETTING( 0337, "ID 337")
PORT_DIPSETTING( 0340, "ID 340") PORT_DIPSETTING( 0341, "ID 341") PORT_DIPSETTING( 0342, "ID 342") PORT_DIPSETTING( 0343, "ID 343")
PORT_DIPSETTING( 0344, "ID 344") PORT_DIPSETTING( 0345, "ID 345") PORT_DIPSETTING( 0346, "ID 346") PORT_DIPSETTING( 0347, "ID 347")
PORT_DIPSETTING( 0350, "ID 350") PORT_DIPSETTING( 0351, "ID 351") PORT_DIPSETTING( 0352, "ID 352") PORT_DIPSETTING( 0353, "ID 353")
PORT_DIPSETTING( 0354, "ID 354") PORT_DIPSETTING( 0355, "ID 355") PORT_DIPSETTING( 0356, "ID 356") PORT_DIPSETTING( 0357, "ID 357")
PORT_DIPSETTING( 0360, "ID 360") PORT_DIPSETTING( 0361, "ID 361") PORT_DIPSETTING( 0362, "ID 362") PORT_DIPSETTING( 0363, "ID 363")
PORT_DIPSETTING( 0364, "ID 364") PORT_DIPSETTING( 0365, "ID 365") PORT_DIPSETTING( 0366, "ID 366") PORT_DIPSETTING( 0367, "ID 367")
PORT_DIPSETTING( 0370, "ID 370") PORT_DIPSETTING( 0371, "ID 371") PORT_DIPSETTING( 0372, "ID 372") PORT_DIPSETTING( 0373, "ID 373")
PORT_DIPSETTING( 0374, "ID 374") PORT_DIPSETTING( 0375, "ID 375")
INPUT_PORTS_END
/* ROM */
ROM_START( alto2 )
// dummy region for the maincpu - this is not used in any way
ROM_REGION( 0400, "maincpu", 0 )
ROM_FILL(0, 0400, ALTO2_UCODE_INVERTED)
ROM_END
//**************************************************************************
// ADDRESS MAPS
//**************************************************************************
ADDRESS_MAP_START( alto2_ucode_map, AS_0, 32, alto2_state )
AM_RANGE(0, ALTO2_UCODE_SIZE-1) AM_DEVICE32( "maincpu", alto2_cpu_device, ucode_map, 0xffffffffUL )
ADDRESS_MAP_END
ADDRESS_MAP_START( alto2_const_map, AS_1, 16, alto2_state )
AM_RANGE(0, ALTO2_CONST_SIZE-1) AM_DEVICE16( "maincpu", alto2_cpu_device, const_map, 0xffffU )
ADDRESS_MAP_END
ADDRESS_MAP_START( alto2_iomem_map, AS_2, 16, alto2_state )
AM_RANGE(0, 2*ALTO2_RAM_SIZE-1) AM_DEVICE16( "maincpu", alto2_cpu_device, iomem_map, 0xffffU )
ADDRESS_MAP_END
static MACHINE_CONFIG_START( alto2, alto2_state )
/* basic machine hardware */
// SYSCLK is Display Control part A51 (tagged 29.4MHz) divided by 5(?)
// 5.8MHz according to de.wikipedia.org/wiki/Xerox_Alto
MCFG_CPU_ADD("maincpu", ALTO2, XTAL_29_4912MHz/5)
MCFG_CPU_PROGRAM_MAP(alto2_ucode_map)
MCFG_CPU_DATA_MAP(alto2_const_map)
MCFG_CPU_IO_MAP(alto2_iomem_map)
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_RAW_PARAMS(XTAL_20_16MHz,
ALTO2_DISPLAY_TOTAL_WIDTH, 0, ALTO2_DISPLAY_WIDTH,
ALTO2_DISPLAY_TOTAL_HEIGHT, 0, ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H)
MCFG_SCREEN_REFRESH_RATE(60) // two interlaced fields
MCFG_SCREEN_VBLANK_TIME(ALTO2_DISPLAY_VBLANK_TIME)
MCFG_SCREEN_UPDATE_DEVICE("maincpu", alto2_cpu_device, screen_update)
MCFG_SCREEN_VBLANK_DEVICE("maincpu", alto2_cpu_device, screen_eof)
MCFG_SCREEN_PALETTE("palette")
MCFG_DEFAULT_LAYOUT( layout_vertical )
MCFG_PALETTE_ADD_WHITE_AND_BLACK("palette")
MCFG_DIABLO_DRIVES_ADD()
MACHINE_CONFIG_END
/* Driver Init */
DRIVER_INIT_MEMBER( alto2_state, alto2 )
{
// make the diablo drives known to the CPU core
alto2_cpu_device* cpu = downcast<alto2_cpu_device *>(m_maincpu.target());
cpu->set_diablo(0, downcast<diablo_hd_device *>(machine().device(DIABLO_HD_0)));
cpu->set_diablo(1, downcast<diablo_hd_device *>(machine().device(DIABLO_HD_1)));
}
/* Game Drivers */
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP( 1977, alto2, 0, 0, alto2, alto2, alto2_state, alto2, "Xerox", "Alto-II", GAME_NO_SOUND )

View File

@ -2362,3 +2362,4 @@ mx2178
hunter2
amust
fc100
alto2

View File

@ -128,6 +128,7 @@ CPUS += ES5510
CPUS += SCUDSP
CPUS += IE15
CPUS += 8X300
CPUS += ALTO2
#-------------------------------------------------
# specify available sound cores; some of these are
@ -515,6 +516,7 @@ MACHINES += TI99_HD
MACHINES += STRATA
MACHINES += CORVUSHD
MACHINES += WOZFDC
MACHINES += DIABLO_HD
#-------------------------------------------------
# specify available bus cores
@ -1992,6 +1994,7 @@ $(MESSOBJ)/wavemate.a: \
$(MESSOBJ)/xerox.a: \
$(MESS_DRIVERS)/xerox820.o \
$(MESS_DRIVERS)/bigbord2.o \
$(MESS_DRIVERS)/alto2.o \
$(MESSOBJ)/xussrpc.a: \
$(MESS_DRIVERS)/ec184x.o \