tx0.c: Modernized cpu core. [Wilbert Pol]

Out of whatsnew:
Also copied over the support for octal in
debugger state from the alto2 branch.
This commit is contained in:
Wilbert Pol 2013-12-25 12:00:22 +00:00
parent 9c03593b09
commit cc74ef9ade
5 changed files with 693 additions and 791 deletions

File diff suppressed because it is too large Load Diff

View File

@ -15,14 +15,103 @@ enum
TX0_CM_SEL, TX0_LR_SEL, TX0_GBL_CM_SEL,
TX0_STOP_CYC0, TX0_STOP_CYC1,
TX0_RUN, TX0_RIM,
TX0_CYCLE, TX0_IOH, TX0_IOS,
TX0_RESET, /* hack, do not use directly, use tx0_pulse_reset instead */
TX0_IO_COMPLETE /* hack, do not use directly, use tx0_pulse_io_complete instead */
TX0_CYCLE, TX0_IOH, TX0_IOS
};
struct tx0_reset_param_t
#define MCFG_TX0_CONFIG(_cpy_devcb, _r1l_devcb, _dis_devcb, _r3l_devcb, _prt_devcb, _rsv_devcb, _p6h_devcb, _p7h_devcb, _sel_devcb, _res_devcb) \
tx0_device::set_cpy_cb(*device, DEVCB2_##_cpy_devcb); \
tx0_device::set_r1l_cb(*device, DEVCB2_##_r1l_devcb); \
tx0_device::set_dis_cb(*device, DEVCB2_##_dis_devcb); \
tx0_device::set_r3l_cb(*device, DEVCB2_##_r3l_devcb); \
tx0_device::set_prt_cb(*device, DEVCB2_##_prt_devcb); \
tx0_device::set_rsv_cb(*device, DEVCB2_##_rsv_devcb); \
tx0_device::set_p6h_cb(*device, DEVCB2_##_p6h_devcb); \
tx0_device::set_p7h_cb(*device, DEVCB2_##_p7h_devcb); \
tx0_device::set_sel_cb(*device, DEVCB2_##_sel_devcb); \
tx0_device::set_res_cb(*device, DEVCB2_##_res_devcb);
class tx0_device : public cpu_device
{
public:
// construction/destruction
tx0_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int addr_bits, int address_mask, int ir_mask);
// static configuration helpers
template<class _Object> static devcb2_base &set_cpy_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_cpy_handler.set_callback(object); }
template<class _Object> static devcb2_base &set_r1l_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_r1l_handler.set_callback(object); }
template<class _Object> static devcb2_base &set_dis_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_dis_handler.set_callback(object); }
template<class _Object> static devcb2_base &set_r3l_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_r3l_handler.set_callback(object); }
template<class _Object> static devcb2_base &set_prt_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_prt_handler.set_callback(object); }
template<class _Object> static devcb2_base &set_rsv_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_rsv_handler.set_callback(object); }
template<class _Object> static devcb2_base &set_p6h_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_p6h_handler.set_callback(object); }
template<class _Object> static devcb2_base &set_p7h_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_p7h_handler.set_callback(object); }
template<class _Object> static devcb2_base &set_sel_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_sel_handler.set_callback(object); }
template<class _Object> static devcb2_base &set_res_cb(device_t &device, _Object object) { return downcast<tx0_device &>(device).m_io_reset_callback.set_callback(object); }
void pulse_reset();
void io_complete();
protected:
// device-level overrides
virtual void device_start();
virtual void device_reset();
// device_execute_interface overrides
virtual UINT32 execute_min_cycles() const { return 1; }
virtual UINT32 execute_max_cycles() const { return 3; }
// device_memory_interface overrides
virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; }
// device_disasm_interface overrides
virtual UINT32 disasm_min_opcode_bytes() const { return 4; }
virtual UINT32 disasm_max_opcode_bytes() const { return 4; }
protected:
address_space_config m_program_config;
/* processor registers */
int m_mbr; /* memory buffer register (18 bits) */
int m_ac; /* accumulator (18 bits) */
int m_mar; /* memory address register (16 (64kW) or 13 (8kW) bits) */
int m_pc; /* program counter (16 (64kW) or 13 (8kW) bits) */
int m_ir; /* instruction register (2 (64kW) or 5 (8kW) bits) */
int m_lr; /* live register (18 bits) */
int m_xr; /* index register (14 bits) (8kW only) */
int m_pf; /* program flags (6 bits expandable to 10) (8kW only) */
/* operator panel switches */
int m_tbr; /* toggle switch buffer register (18 bits) */
int m_tac; /* toggle switch accumulator (18 bits) */
int m_tss[16]; /* toggle switch storage (18 bits * 16) */
UINT16 m_cm_sel; /* individual cm select (1 bit * 16) */
UINT16 m_lr_sel; /* individual lr select (1 bit * 16) */
unsigned int m_gbl_cm_sel;/* global cm select (1 bit) */
unsigned int m_stop_cyc0; /* stop on cycle 0 */
unsigned int m_stop_cyc1; /* stop on cycle 1 */
/* processor state flip-flops */
unsigned int m_run; /* processor is running */
unsigned int m_rim; /* processor is in read-in mode */
unsigned int m_cycle; /* 0 -> fetch */
/* 1 -> execute (except for taken branches) */
/* 2 -> extra execute cycle for SXA and ADO */
unsigned int m_ioh; /* i-o halt: processor is executing an Input-Output Transfer wait */
unsigned int m_ios; /* i-o synchronizer: set on i-o operation completion */
/* additional emulator state variables */
int m_rim_step; /* current step in rim execution */
int m_address_mask; /* address mask */
int m_ir_mask; /* IR mask */
int m_icount;
address_space *m_program;
/* 8 standard I/O handlers:
0: cpy (8kW only)
1: r1l
@ -32,18 +121,57 @@ struct tx0_reset_param_t
5: reserved (for unimplemented typ instruction?)
6: p6h
7: p7h */
void (*io_handlers[8])(device_t *device);
devcb2_write_line m_cpy_handler;
devcb2_write_line m_r1l_handler;
devcb2_write_line m_dis_handler;
devcb2_write_line m_r3l_handler;
devcb2_write_line m_prt_handler;
devcb2_write_line m_rsv_handler;
devcb2_write_line m_p6h_handler;
devcb2_write_line m_p7h_handler;
/* select instruction handler */
void (*sel_handler)(device_t *device);
devcb2_write_line m_sel_handler;
/* callback called when reset line is pulsed: IO devices should reset */
void (*io_reset_callback)(device_t *device);
devcb2_write_line m_io_reset_callback;
int tx0_read(offs_t address);
void tx0_write(offs_t address, int data);
void call_io_handler(int io_handler);
void indexed_address_eval();
};
/* PUBLIC FUNCTIONS */
DECLARE_LEGACY_CPU_DEVICE(TX0_64KW, tx0_64kw);
DECLARE_LEGACY_CPU_DEVICE(TX0_8KW, tx0_8kw);
CPU_DISASSEMBLE( tx0_64kw );
CPU_DISASSEMBLE( tx0_8kw );
class tx0_8kw_device : public tx0_device
{
public:
// construction/destruction
tx0_8kw_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock);
protected:
virtual void execute_run();
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
private:
void execute_instruction_8kw();
};
class tx0_64kw_device : public tx0_device
{
public:
// construction/destruction
tx0_64kw_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock);
protected:
virtual void execute_run();
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
private:
void execute_instruction_64kw();
};
extern const device_type TX0_64KW;
extern const device_type TX0_8KW;
#endif /* __TX0_H__ */

View File

@ -248,6 +248,31 @@ astring &device_state_entry::format(astring &dest, const char *string, bool maxo
reset = true;
break;
// O outputs as octal
case 'O':
if (width == 0)
throw emu_fatalerror("Width required for %%O formats\n");
hitnonzero = false;
while (leadzero && width > 22)
{
dest.cat(" ");
width--;
}
for (int digitnum = 21; digitnum >= 0; digitnum--)
{
int digit = (result >> (3 * digitnum)) & 07;
if (digit != 0)
{
static const char octchars[] = "01234567";
dest.cat(&octchars[digit], 1);
hitnonzero = true;
}
else if (hitnonzero || (leadzero && digitnum < width) || digitnum == 0)
dest.cat("0");
}
reset = true;
break;
// d outputs as signed decimal
case 'd':
if (width == 0)

View File

@ -301,31 +301,6 @@ void tx0_state::palette_init()
colortable_entry_set_value(machine().colortable, total_colors_needed + i, tx0_palette[i]);
}
static void tx0_io_cpy(device_t *device);
static void tx0_io_r1l(device_t *device);
static void tx0_io_r3l(device_t *device);
static void tx0_io_p6h(device_t *device);
static void tx0_io_p7h(device_t *device);
static void tx0_io_prt(device_t *device);
static void tx0_io_dis(device_t *device);
static void tx0_sel(device_t *device);
static void tx0_io_reset_callback(device_t *device);
static const tx0_reset_param_t tx0_reset_param =
{
{
tx0_io_cpy,
tx0_io_r1l,
tx0_io_dis,
tx0_io_r3l,
tx0_io_prt,
/*tx0_io_typ*/NULL,
tx0_io_p6h,
tx0_io_p7h
},
tx0_sel,
tx0_io_reset_callback
};
static const crt_interface tx0_crt_interface =
{
@ -705,51 +680,47 @@ TIMER_CALLBACK_MEMBER(tx0_state::puncher_callback)
/*
Initiate read of a 6-bit word from tape
*/
static void tx0_io_r1l(device_t *device)
WRITE_LINE_MEMBER( tx0_state::tx0_io_r1l )
{
tx0_state *state = device->machine().driver_data<tx0_state>();
state->begin_tape_read( 0);
begin_tape_read( 0);
}
/*
Initiate read of a 18-bit word from tape (used in read-in mode)
*/
static void tx0_io_r3l(device_t *device)
WRITE_LINE_MEMBER( tx0_state::tx0_io_r3l )
{
tx0_state *state = device->machine().driver_data<tx0_state>();
state->begin_tape_read(1);
begin_tape_read(1);
}
/*
Write a 7-bit word to tape (7th bit clear)
*/
static void tx0_io_p6h(device_t *device)
WRITE_LINE_MEMBER( tx0_state::tx0_io_p6h )
{
tx0_state *state = device->machine().driver_data<tx0_state>();
int ac;
/* read current AC */
ac = device->state().state_int(TX0_AC);
ac = m_maincpu->state_int(TX0_AC);
/* shuffle and punch 6-bit word */
state->tape_write(((ac & 0100000) >> 15) | ((ac & 0010000) >> 11) | ((ac & 0001000) >> 7) | ((ac & 0000100) >> 3) | ((ac & 0000010) << 1) | ((ac & 0000001) << 5));
tape_write(((ac & 0100000) >> 15) | ((ac & 0010000) >> 11) | ((ac & 0001000) >> 7) | ((ac & 0000100) >> 3) | ((ac & 0000010) << 1) | ((ac & 0000001) << 5));
state->m_tape_puncher.timer->adjust(attotime::from_usec(15800));
m_tape_puncher.timer->adjust(attotime::from_usec(15800));
}
/*
Write a 7-bit word to tape (7th bit set)
*/
static void tx0_io_p7h(device_t *device)
WRITE_LINE_MEMBER( tx0_state::tx0_io_p7h )
{
tx0_state *state = device->machine().driver_data<tx0_state>();
int ac;
/* read current AC */
ac = device->state().state_int(TX0_AC);
ac = m_maincpu->state_int(TX0_AC);
/* shuffle and punch 6-bit word */
state->tape_write(((ac & 0100000) >> 15) | ((ac & 0010000) >> 11) | ((ac & 0001000) >> 7) | ((ac & 0000100) >> 3) | ((ac & 0000010) << 1) | ((ac & 0000001) << 5) | 0100);
tape_write(((ac & 0100000) >> 15) | ((ac & 0010000) >> 11) | ((ac & 0001000) >> 7) | ((ac & 0000100) >> 3) | ((ac & 0000010) << 1) | ((ac & 0000001) << 5) | 0100);
state->m_tape_puncher.timer->adjust(attotime::from_usec(15800));
m_tape_puncher.timer->adjust(attotime::from_usec(15800));
}
@ -793,25 +764,24 @@ void tx0_state::typewriter_out(UINT8 data)
*/
TIMER_CALLBACK_MEMBER(tx0_state::prt_callback)
{
m_maincpu->set_state_int(TX0_IOS,1);
m_maincpu->io_complete();
}
/*
prt io callback
*/
static void tx0_io_prt(device_t *device)
WRITE_LINE_MEMBER( tx0_state::tx0_io_prt )
{
tx0_state *state = device->machine().driver_data<tx0_state>();
int ac;
int ch;
/* read current AC */
ac = device->state().state_int(TX0_AC);
ac = m_maincpu->state_int(TX0_AC);
/* shuffle and print 6-bit word */
ch = ((ac & 0100000) >> 15) | ((ac & 0010000) >> 11) | ((ac & 0001000) >> 7) | ((ac & 0000100) >> 3) | ((ac & 0000010) << 1) | ((ac & 0000001) << 5);
state->typewriter_out(ch);
typewriter_out(ch);
state->m_typewriter.prt_timer->adjust(attotime::from_msec(100));
m_typewriter.prt_timer->adjust(attotime::from_msec(100));
}
@ -820,25 +790,24 @@ static void tx0_io_prt(device_t *device)
*/
TIMER_CALLBACK_MEMBER(tx0_state::dis_callback)
{
m_maincpu->set_state_int(TX0_IOS,1);
m_maincpu->io_complete();
}
/*
Plot one point on crt
*/
static void tx0_io_dis(device_t *device)
WRITE_LINE_MEMBER( tx0_state::tx0_io_dis )
{
tx0_state *state = device->machine().driver_data<tx0_state>();
int ac;
int x;
int y;
ac = device->state().state_int(TX0_AC);
ac = m_maincpu->state_int(TX0_AC);
x = ac >> 9;
y = ac & 0777;
state->tx0_plot(x, y);
tx0_plot(x, y);
state->m_dis_timer->adjust(attotime::from_usec(50));
m_dis_timer->adjust(attotime::from_usec(50));
}
@ -944,143 +913,142 @@ void tx0_magtape_image_device::call_unload()
}
}
static void magtape_callback(device_t *device)
void tx0_state::magtape_callback()
{
tx0_state *state = device->machine().driver_data<tx0_state>();
UINT8 buf = 0;
int lr;
switch (state->m_magtape.state)
switch (m_magtape.state)
{
case MTS_UNSELECTING:
state->m_magtape.state = MTS_UNSELECTED;
m_magtape.state = MTS_UNSELECTED;
case MTS_UNSELECTED:
if (state->m_magtape.sel_pending)
if (m_magtape.sel_pending)
{
int mar;
mar = device->state().state_int(TX0_MAR);
mar = m_maincpu->state_int(TX0_MAR);
if ((mar & 03) != 1)
{ /* unimplemented device: remain in unselected state and set rwc
flag? */
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_RWC);
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_RWC);
}
else
{
state->m_magtape.state = MTS_SELECTING;
m_magtape.state = MTS_SELECTING;
state->m_magtape.command = (mar & 014 >> 2);
m_magtape.command = (mar & 014 >> 2);
state->m_magtape.binary_flag = (mar & 020 >> 4);
m_magtape.binary_flag = (mar & 020 >> 4);
if (state->m_magtape.img)
state->schedule_select();
if (m_magtape.img)
schedule_select();
}
state->m_magtape.sel_pending = FALSE;
device->state().set_state_int(TX0_IOS,1);
m_magtape.sel_pending = FALSE;
m_maincpu->io_complete();
}
break;
case MTS_SELECTING:
state->m_magtape.state = MTS_SELECTED;
switch (state->m_magtape.command)
m_magtape.state = MTS_SELECTED;
switch (m_magtape.command)
{
case 0: /* backspace */
state->m_magtape.long_parity = 0177;
state->m_magtape.u.backspace_state = MTBSS_STATE0;
m_magtape.long_parity = 0177;
m_magtape.u.backspace_state = MTBSS_STATE0;
break;
case 1: /* read */
state->m_magtape.long_parity = 0177;
state->m_magtape.u.read.state = MTRDS_STATE0;
m_magtape.long_parity = 0177;
m_magtape.u.read.state = MTRDS_STATE0;
break;
case 2: /* rewind */
break;
case 3: /* write */
state->m_magtape.long_parity = 0177;
state->m_magtape.u.write.state = MTWTS_STATE0;
switch (state->m_magtape.irg_pos)
m_magtape.long_parity = 0177;
m_magtape.u.write.state = MTWTS_STATE0;
switch (m_magtape.irg_pos)
{
case MTIRGP_START:
state->m_magtape.u.write.counter = 150;
m_magtape.u.write.counter = 150;
break;
case MTIRGP_ENDMINUS1:
state->m_magtape.u.write.counter = 1;
m_magtape.u.write.counter = 1;
break;
case MTIRGP_END:
state->m_magtape.u.write.counter = 0;
m_magtape.u.write.counter = 0;
break;
}
break;
}
case MTS_SELECTED:
switch (state->m_magtape.command)
switch (m_magtape.command)
{
case 0: /* backspace */
if (state->m_magtape.img->ftell() == 0)
if (m_magtape.img->ftell() == 0)
{ /* tape at ldp */
state->m_magtape.state = MTS_UNSELECTING;
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_RWC);
state->schedule_unselect();
m_magtape.state = MTS_UNSELECTING;
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_RWC);
schedule_unselect();
}
else if (state->m_magtape.img->fseek( -1, SEEK_CUR))
else if (m_magtape.img->fseek( -1, SEEK_CUR))
{ /* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
else if (state->m_magtape.img->fread(&buf, 1) != 1)
else if (m_magtape.img->fread(&buf, 1) != 1)
{ /* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
else if (state->m_magtape.img->fseek( -1, SEEK_CUR))
else if (m_magtape.img->fseek( -1, SEEK_CUR))
{ /* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
else
{
buf &= 0x7f; /* 7-bit tape, ignore 8th bit */
state->m_magtape.long_parity ^= buf;
switch (state->m_magtape.u.backspace_state)
m_magtape.long_parity ^= buf;
switch (m_magtape.u.backspace_state)
{
case MTBSS_STATE0:
/* STATE0 -> initial interrecord gap, longitudinal parity;
if longitudinal parity was all 0s, gap between longitudinal
parity and data, first byte of data */
if (buf != 0)
state->m_magtape.u.backspace_state = MTBSS_STATE1;
m_magtape.u.backspace_state = MTBSS_STATE1;
break;
case MTBSS_STATE1:
/* STATE1 -> first byte of gap between longitudinal parity and
data, second byte of data */
if (buf == 0)
state->m_magtape.u.backspace_state = MTBSS_STATE2;
m_magtape.u.backspace_state = MTBSS_STATE2;
else
state->m_magtape.u.backspace_state = MTBSS_STATE5;
m_magtape.u.backspace_state = MTBSS_STATE5;
break;
case MTBSS_STATE2:
/* STATE2 -> second byte of gap between longitudinal parity and
data */
if (buf == 0)
state->m_magtape.u.backspace_state = MTBSS_STATE3;
m_magtape.u.backspace_state = MTBSS_STATE3;
else
{
logerror("tape seems to be corrupt\n");
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
break;
case MTBSS_STATE3:
/* STATE3 -> third byte of gap between longitudinal parity and
data */
if (buf == 0)
state->m_magtape.u.backspace_state = MTBSS_STATE4;
m_magtape.u.backspace_state = MTBSS_STATE4;
else
{
logerror("tape seems to be corrupt\n");
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
break;
case MTBSS_STATE4:
@ -1088,16 +1056,16 @@ static void magtape_callback(device_t *device)
interrecord gap after data */
if (buf == 0)
{
if (state->m_magtape.long_parity)
if (m_magtape.long_parity)
logerror("invalid longitudinal parity\n");
/* set EOR and unselect... */
state->m_magtape.state = MTS_UNSELECTING;
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_EOR);
state->schedule_unselect();
state->m_magtape.irg_pos = MTIRGP_ENDMINUS1;
m_magtape.state = MTS_UNSELECTING;
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_EOR);
schedule_unselect();
m_magtape.irg_pos = MTIRGP_ENDMINUS1;
}
else
state->m_magtape.u.backspace_state = MTBSS_STATE5;
m_magtape.u.backspace_state = MTBSS_STATE5;
break;
case MTBSS_STATE5:
/* STATE5 -> second byte of data word */
@ -1105,10 +1073,10 @@ static void magtape_callback(device_t *device)
{
logerror("tape seems to be corrupt\n");
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
else
state->m_magtape.u.backspace_state = MTBSS_STATE6;
m_magtape.u.backspace_state = MTBSS_STATE6;
break;
case MTBSS_STATE6:
/* STATE6 -> third byte of data word */
@ -1116,67 +1084,67 @@ static void magtape_callback(device_t *device)
{
logerror("tape seems to be corrupt\n");
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
else
state->m_magtape.u.backspace_state = MTBSS_STATE6;
m_magtape.u.backspace_state = MTBSS_STATE6;
break;
}
if (state->m_magtape.state != MTS_UNSELECTING)
state->m_magtape.timer->adjust(attotime::from_usec(66));
if (m_magtape.state != MTS_UNSELECTING)
m_magtape.timer->adjust(attotime::from_usec(66));
}
break;
case 1: /* read */
if (state->m_magtape.img->fread(&buf, 1) != 1)
if (m_magtape.img->fread(&buf, 1) != 1)
{ /* I/O error or EOF? */
/* The MAME fileio layer makes it very hard to make the
difference... MAME seems to assume that I/O errors never
happen, whereas it is really easy to cause one by
deconnecting an external drive the image is located on!!! */
UINT64 offs;
offs = state->m_magtape.img->ftell();
if (state->m_magtape.img->fseek( 0, SEEK_END) || (offs != state->m_magtape.img->ftell()))
offs = m_magtape.img->ftell();
if (m_magtape.img->fseek( 0, SEEK_END) || (offs != m_magtape.img->ftell()))
{ /* I/O error */
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
else
{ /* end of tape -> ??? */
/* maybe we run past end of tape, so that tape is ejected from
upper reel and unit becomes unavailable??? */
/*state->m_magtape.img->unload();*/
/*m_magtape.img->unload();*/
/* Or do we stop at EOT mark??? */
state->m_magtape.state = MTS_UNSELECTING;
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_EOT);
state->schedule_unselect();
m_magtape.state = MTS_UNSELECTING;
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_EOT);
schedule_unselect();
}
}
else
{
buf &= 0x7f; /* 7-bit tape, ignore 8th bit */
state->m_magtape.long_parity ^= buf;
switch (state->m_magtape.u.read.state)
m_magtape.long_parity ^= buf;
switch (m_magtape.u.read.state)
{
case MTRDS_STATE0:
/* STATE0 -> interrecord blank or first byte of data */
if (buf != 0)
{
if (state->m_magtape.cpy_pending)
if (m_magtape.cpy_pending)
{ /* read command */
state->m_magtape.u.read.space_flag = FALSE;
device->state().set_state_int(TX0_IOS,1);
device->state().set_state_int(TX0_LR, ((device->state().state_int(TX0_LR) >> 1) & 0333333)
m_magtape.u.read.space_flag = FALSE;
m_maincpu->set_state_int(TX0_IOS,1);
m_maincpu->set_state_int(TX0_LR, ((m_maincpu->state_int(TX0_LR) >> 1) & 0333333)
| ((buf & 040) << 12) | ((buf & 020) << 10) | ((buf & 010) << 8) | ((buf & 004) << 6) | ((buf & 002) << 4) | ((buf & 001) << 2));
/* check parity */
if (! (((buf ^ (buf >> 1) ^ (buf >> 2) ^ (buf >> 3) ^ (buf >> 4) ^ (buf >> 5) ^ (buf >> 6) ^ (buf >> 7)) & 1) ^ state->m_magtape.binary_flag))
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_PC);
if (! (((buf ^ (buf >> 1) ^ (buf >> 2) ^ (buf >> 3) ^ (buf >> 4) ^ (buf >> 5) ^ (buf >> 6) ^ (buf >> 7)) & 1) ^ m_magtape.binary_flag))
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_PC);
}
else
{ /* space command */
state->m_magtape.u.read.space_flag = TRUE;
m_magtape.u.read.space_flag = TRUE;
}
state->m_magtape.u.read.state = MTRDS_STATE1;
m_magtape.u.read.state = MTRDS_STATE1;
}
break;
case MTRDS_STATE1:
@ -1185,17 +1153,17 @@ static void magtape_callback(device_t *device)
{
logerror("tape seems to be corrupt\n");
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
if (!state->m_magtape.u.read.space_flag)
if (!m_magtape.u.read.space_flag)
{
device->state().set_state_int(TX0_LR, ((device->state().state_int(TX0_LR) >> 1) & 0333333)
m_maincpu->set_state_int(TX0_LR, ((m_maincpu->state_int(TX0_LR) >> 1) & 0333333)
| ((buf & 040) << 12) | ((buf & 020) << 10) | ((buf & 010) << 8) | ((buf & 004) << 6) | ((buf & 002) << 4) | ((buf & 001) << 2));
/* check parity */
if (! (((buf ^ (buf >> 1) ^ (buf >> 2) ^ (buf >> 3) ^ (buf >> 4) ^ (buf >> 5) ^ (buf >> 6) ^ (buf >> 7)) & 1) ^ state->m_magtape.binary_flag))
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_PC);
if (! (((buf ^ (buf >> 1) ^ (buf >> 2) ^ (buf >> 3) ^ (buf >> 4) ^ (buf >> 5) ^ (buf >> 6) ^ (buf >> 7)) & 1) ^ m_magtape.binary_flag))
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_PC);
}
state->m_magtape.u.read.state = MTRDS_STATE2;
m_magtape.u.read.state = MTRDS_STATE2;
break;
case MTRDS_STATE2:
/* STATE2 -> third byte of data word */
@ -1203,40 +1171,40 @@ static void magtape_callback(device_t *device)
{
logerror("tape seems to be corrupt\n");
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
if (!state->m_magtape.u.read.space_flag)
if (!m_magtape.u.read.space_flag)
{
device->state().set_state_int(TX0_LR, ((device->state().state_int(TX0_LR) >> 1) & 0333333)
m_maincpu->set_state_int(TX0_LR, ((m_maincpu->state_int(TX0_LR) >> 1) & 0333333)
| ((buf & 040) << 12) | ((buf & 020) << 10) | ((buf & 010) << 8) | ((buf & 004) << 6) | ((buf & 002) << 4) | ((buf & 001) << 2));
/* check parity */
if (! (((buf ^ (buf >> 1) ^ (buf >> 2) ^ (buf >> 3) ^ (buf >> 4) ^ (buf >> 5) ^ (buf >> 6) ^ (buf >> 7)) & 1) ^ state->m_magtape.binary_flag))
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_PC);
if (! (((buf ^ (buf >> 1) ^ (buf >> 2) ^ (buf >> 3) ^ (buf >> 4) ^ (buf >> 5) ^ (buf >> 6) ^ (buf >> 7)) & 1) ^ m_magtape.binary_flag))
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_PC);
/* synchronize with cpy instruction */
if (state->m_magtape.cpy_pending)
device->state().set_state_int(TX0_IOS,1);
if (m_magtape.cpy_pending)
m_maincpu->set_state_int(TX0_IOS,1);
else
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_RWC);
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_RWC);
}
state->m_magtape.u.read.state = MTRDS_STATE3;
m_magtape.u.read.state = MTRDS_STATE3;
break;
case MTRDS_STATE3:
/* STATE3 -> first byte of new word of data, or first byte
of gap between data and longitudinal parity */
if (buf != 0)
{
state->m_magtape.u.read.state = MTRDS_STATE1;
if (!state->m_magtape.u.read.space_flag)
m_magtape.u.read.state = MTRDS_STATE1;
if (!m_magtape.u.read.space_flag)
{
device->state().set_state_int(TX0_LR, ((device->state().state_int(TX0_LR) >> 1) & 0333333)
m_maincpu->set_state_int(TX0_LR, ((m_maincpu->state_int(TX0_LR) >> 1) & 0333333)
| ((buf & 040) << 12) | ((buf & 020) << 10) | ((buf & 010) << 8) | ((buf & 004) << 6) | ((buf & 002) << 4) | ((buf & 001) << 2));
/* check parity */
if (! (((buf ^ (buf >> 1) ^ (buf >> 2) ^ (buf >> 3) ^ (buf >> 4) ^ (buf >> 5) ^ (buf >> 6) ^ (buf >> 7)) & 1) ^ state->m_magtape.binary_flag))
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_PC);
if (! (((buf ^ (buf >> 1) ^ (buf >> 2) ^ (buf >> 3) ^ (buf >> 4) ^ (buf >> 5) ^ (buf >> 6) ^ (buf >> 7)) & 1) ^ m_magtape.binary_flag))
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_PC);
}
}
else
state->m_magtape.u.read.state = MTRDS_STATE4;
m_magtape.u.read.state = MTRDS_STATE4;
break;
case MTRDS_STATE4:
/* STATE4 -> second byte of gap between data and
@ -1245,10 +1213,10 @@ static void magtape_callback(device_t *device)
{
logerror("tape seems to be corrupt\n");
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
else
state->m_magtape.u.read.state = MTRDS_STATE5;
m_magtape.u.read.state = MTRDS_STATE5;
break;
case MTRDS_STATE5:
@ -1258,126 +1226,126 @@ static void magtape_callback(device_t *device)
{
logerror("tape seems to be corrupt\n");
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
else
state->m_magtape.u.read.state = MTRDS_STATE6;
m_magtape.u.read.state = MTRDS_STATE6;
break;
case MTRDS_STATE6:
/* STATE6 -> longitudinal parity */
/* check parity */
if (state->m_magtape.long_parity)
if (m_magtape.long_parity)
{
logerror("invalid longitudinal parity\n");
/* no idea if the original tx-0 magtape controller
checks parity, but can't harm if we do */
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_PC);
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_PC);
}
/* set EOR and unselect... */
state->m_magtape.state = MTS_UNSELECTING;
device->state().set_state_int(TX0_PF, device->state().state_int(TX0_PF) | PF_EOR);
state->schedule_unselect();
state->m_magtape.irg_pos = MTIRGP_START;
m_magtape.state = MTS_UNSELECTING;
m_maincpu->set_state_int(TX0_PF, m_maincpu->state_int(TX0_PF) | PF_EOR);
schedule_unselect();
m_magtape.irg_pos = MTIRGP_START;
break;
}
if (state->m_magtape.state != MTS_UNSELECTING)
state->m_magtape.timer->adjust(attotime::from_usec(66));
if (m_magtape.state != MTS_UNSELECTING)
m_magtape.timer->adjust(attotime::from_usec(66));
}
break;
case 2: /* rewind */
state->m_magtape.state = MTS_UNSELECTING;
m_magtape.state = MTS_UNSELECTING;
/* we rewind at 10*read speed (I don't know the real value) */
state->m_magtape.timer->adjust((attotime::from_nsec(6600) * state->m_magtape.img->ftell()));
m_magtape.timer->adjust((attotime::from_nsec(6600) * m_magtape.img->ftell()));
//schedule_unselect(state);
state->m_magtape.img->fseek( 0, SEEK_END);
state->m_magtape.irg_pos = MTIRGP_END;
m_magtape.img->fseek( 0, SEEK_END);
m_magtape.irg_pos = MTIRGP_END;
break;
case 3: /* write */
switch (state->m_magtape.u.write.state)
switch (m_magtape.u.write.state)
{
case MTWTS_STATE0:
if (state->m_magtape.u.write.counter != 0)
if (m_magtape.u.write.counter != 0)
{
state->m_magtape.u.write.counter--;
m_magtape.u.write.counter--;
buf = 0;
break;
}
else
{
state->m_magtape.u.write.state = MTWTS_STATE1;
m_magtape.u.write.state = MTWTS_STATE1;
}
case MTWTS_STATE1:
if (state->m_magtape.u.write.counter)
if (m_magtape.u.write.counter)
{
state->m_magtape.u.write.counter--;
lr = device->state().state_int(TX0_LR);
m_magtape.u.write.counter--;
lr = m_maincpu->state_int(TX0_LR);
buf = ((lr >> 10) & 040) | ((lr >> 8) & 020) | ((lr >> 6) & 010) | ((lr >> 4) & 004) | ((lr >> 2) & 002) | (lr & 001);
buf |= ((buf << 1) ^ (buf << 2) ^ (buf << 3) ^ (buf << 4) ^ (buf << 5) ^ (buf << 6) ^ ((!state->m_magtape.binary_flag) << 6)) & 0100;
device->state().set_state_int(TX0_LR, lr >> 1);
buf |= ((buf << 1) ^ (buf << 2) ^ (buf << 3) ^ (buf << 4) ^ (buf << 5) ^ (buf << 6) ^ ((!m_magtape.binary_flag) << 6)) & 0100;
m_maincpu->set_state_int(TX0_LR, lr >> 1);
}
else
{
if (state->m_magtape.cpy_pending)
if (m_magtape.cpy_pending)
{
device->state().set_state_int(TX0_IOS,1);
lr = device->state().state_int(TX0_LR);
m_maincpu->set_state_int(TX0_IOS,1);
lr = m_maincpu->state_int(TX0_LR);
buf = ((lr >> 10) & 040) | ((lr >> 8) & 020) | ((lr >> 6) & 010) | ((lr >> 4) & 004) | ((lr >> 2) & 002) | (lr & 001);
buf |= ((buf << 1) ^ (buf << 2) ^ (buf << 3) ^ (buf << 4) ^ (buf << 5) ^ (buf << 6) ^ ((!state->m_magtape.binary_flag) << 6)) & 0100;
device->state().set_state_int(TX0_LR, lr >> 1);
state->m_magtape.u.write.counter = 2;
buf |= ((buf << 1) ^ (buf << 2) ^ (buf << 3) ^ (buf << 4) ^ (buf << 5) ^ (buf << 6) ^ ((!m_magtape.binary_flag) << 6)) & 0100;
m_maincpu->set_state_int(TX0_LR, lr >> 1);
m_magtape.u.write.counter = 2;
break;
}
else
{
state->m_magtape.u.write.state = MTWTS_STATE2;
state->m_magtape.u.write.counter = 3;
m_magtape.u.write.state = MTWTS_STATE2;
m_magtape.u.write.counter = 3;
}
}
case MTWTS_STATE2:
if (state->m_magtape.u.write.counter != 0)
if (m_magtape.u.write.counter != 0)
{
state->m_magtape.u.write.counter--;
m_magtape.u.write.counter--;
buf = 0;
break;
}
else
{
buf = state->m_magtape.long_parity;
state->m_magtape.state = (state_t)MTWTS_STATE3;
state->m_magtape.u.write.counter = 150;
buf = m_magtape.long_parity;
m_magtape.state = (state_t)MTWTS_STATE3;
m_magtape.u.write.counter = 150;
}
break;
case MTWTS_STATE3:
if (state->m_magtape.u.write.counter != 0)
if (m_magtape.u.write.counter != 0)
{
state->m_magtape.u.write.counter--;
m_magtape.u.write.counter--;
buf = 0;
break;
}
else
{
state->m_magtape.state = MTS_UNSELECTING;
state->schedule_unselect();
state->m_magtape.irg_pos = MTIRGP_END;
m_magtape.state = MTS_UNSELECTING;
schedule_unselect();
m_magtape.irg_pos = MTIRGP_END;
}
break;
}
if (state->m_magtape.state != MTS_UNSELECTING)
if (m_magtape.state != MTS_UNSELECTING)
{ /* write data word */
state->m_magtape.long_parity ^= buf;
if (state->m_magtape.img->fwrite(&buf, 1) != 1)
m_magtape.long_parity ^= buf;
if (m_magtape.img->fwrite(&buf, 1) != 1)
{ /* I/O error */
/* eject tape */
state->m_magtape.img->unload();
m_magtape.img->unload();
}
else
state->m_magtape.timer->adjust(attotime::from_usec(66));
m_magtape.timer->adjust(attotime::from_usec(66));
}
break;
}
@ -1385,42 +1353,40 @@ static void magtape_callback(device_t *device)
}
}
static void tx0_sel(device_t *device)
WRITE_LINE_MEMBER( tx0_state::tx0_sel )
{
tx0_state *state = device->machine().driver_data<tx0_state>();
state->m_magtape.sel_pending = TRUE;
m_magtape.sel_pending = TRUE;
if (state->m_magtape.state == MTS_UNSELECTED)
if (m_magtape.state == MTS_UNSELECTED)
{
if (0)
magtape_callback(device);
state->m_magtape.timer->adjust(attotime::zero);
magtape_callback();
m_magtape.timer->adjust(attotime::zero);
}
}
static void tx0_io_cpy(device_t *device)
WRITE_LINE_MEMBER( tx0_state::tx0_io_cpy )
{
tx0_state *state = device->machine().driver_data<tx0_state>();
switch (state->m_magtape.state)
switch (m_magtape.state)
{
case MTS_UNSELECTED:
case MTS_UNSELECTING:
/* ignore instruction and set rwc flag? */
device->state().set_state_int(TX0_IOS,1);
m_maincpu->io_complete();
break;
case MTS_SELECTING:
case MTS_SELECTED:
switch (state->m_magtape.command)
switch (m_magtape.command)
{
case 0: /* backspace */
case 2: /* rewind */
/* ignore instruction and set rwc flag? */
device->state().set_state_int(TX0_IOS,1);
m_maincpu->io_complete();
break;
case 1: /* read */
case 3: /* write */
state->m_magtape.cpy_pending = TRUE;
m_magtape.cpy_pending = TRUE;
break;
}
break;
@ -1433,21 +1399,20 @@ static void tx0_io_cpy(device_t *device)
IO devices should reset
*/
static void tx0_io_reset_callback(device_t *device)
WRITE_LINE_MEMBER( tx0_state::tx0_io_reset_callback )
{
tx0_state *state = device->machine().driver_data<tx0_state>();
state->m_tape_reader.rcl = state->m_tape_reader.rc = 0;
if (state->m_tape_reader.timer)
state->m_tape_reader.timer->enable(0);
m_tape_reader.rcl = m_tape_reader.rc = 0;
if (m_tape_reader.timer)
m_tape_reader.timer->enable(0);
if (state->m_tape_puncher.timer)
state->m_tape_puncher.timer->enable(0);
if (m_tape_puncher.timer)
m_tape_puncher.timer->enable(0);
if (state->m_typewriter.prt_timer)
state->m_typewriter.prt_timer->enable(0);
if (m_typewriter.prt_timer)
m_typewriter.prt_timer->enable(0);
if (state->m_dis_timer)
state->m_dis_timer->enable(0);
if (m_dis_timer)
m_dis_timer->enable(0);
}
@ -1537,7 +1502,7 @@ INTERRUPT_GEN_MEMBER(tx0_state::tx0_interrupt)
}
if (control_transitions & tx0_read_in)
{ /* set cpu to read instructions from perforated tape */
m_maincpu->set_state_int(TX0_RESET, (UINT64)0);
m_maincpu->pulse_reset();
m_maincpu->set_state_int(TX0_RUN, (UINT64)0);
m_maincpu->set_state_int(TX0_RIM, 1);
}
@ -1600,7 +1565,18 @@ static MACHINE_CONFIG_START( tx0_64kw, tx0_state )
/* basic machine hardware */
/* TX0 CPU @ approx. 167 kHz (no master clock, but the memory cycle time is approximately 6usec) */
MCFG_CPU_ADD("maincpu", TX0_64KW, 166667)
MCFG_CPU_CONFIG(tx0_reset_param)
MCFG_TX0_CONFIG(
WRITELINE( tx0_state, tx0_io_cpy ),
WRITELINE( tx0_state, tx0_io_r1l ),
WRITELINE( tx0_state, tx0_io_dis ),
WRITELINE( tx0_state, tx0_io_r3l ),
WRITELINE( tx0_state, tx0_io_prt ),
NULL,
WRITELINE( tx0_state, tx0_io_p6h ),
WRITELINE( tx0_state, tx0_io_p7h ),
WRITELINE( tx0_state, tx0_sel ),
WRITELINE( tx0_state, tx0_io_reset_callback )
)
MCFG_CPU_PROGRAM_MAP(tx0_64kw_map)
/* dummy interrupt: handles input */
MCFG_CPU_VBLANK_INT_DRIVER("screen", tx0_state, tx0_interrupt)
@ -1632,7 +1608,6 @@ static MACHINE_CONFIG_DERIVED( tx0_8kw, tx0_64kw )
/* TX0 CPU @ approx. 167 kHz (no master clock, but the memory cycle time is
approximately 6usec) */
MCFG_CPU_MODIFY("maincpu")
MCFG_CPU_CONFIG(tx0_reset_param)
MCFG_CPU_PROGRAM_MAP(tx0_8kw_map)
/*MCFG_CPU_PORTS(readport, writeport)*/
MACHINE_CONFIG_END

View File

@ -8,6 +8,7 @@
#define TX0_H_
#include "video/crt.h"
#include "cpu/pdp1/tx0.h"
enum state_t
{
@ -161,7 +162,7 @@ public:
TIMER_CALLBACK_MEMBER(prt_callback);
TIMER_CALLBACK_MEMBER(dis_callback);
void tx0_machine_stop();
required_device<cpu_device> m_maincpu;
required_device<tx0_device> m_maincpu;
inline void tx0_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color);
void tx0_plot(int x, int y);
void tx0_draw_led(bitmap_ind16 &bitmap, int x, int y, int state);
@ -183,6 +184,16 @@ public:
void schedule_select();
void schedule_unselect();
void tx0_keyboard();
DECLARE_WRITE_LINE_MEMBER(tx0_io_cpy);
DECLARE_WRITE_LINE_MEMBER(tx0_io_r1l);
DECLARE_WRITE_LINE_MEMBER(tx0_io_r3l);
DECLARE_WRITE_LINE_MEMBER(tx0_io_p6h);
DECLARE_WRITE_LINE_MEMBER(tx0_io_p7h);
DECLARE_WRITE_LINE_MEMBER(tx0_io_prt);
DECLARE_WRITE_LINE_MEMBER(tx0_io_dis);
DECLARE_WRITE_LINE_MEMBER(tx0_sel);
DECLARE_WRITE_LINE_MEMBER(tx0_io_reset_callback);
void magtape_callback();
};
/* defines for each bit and mask in input port "CSW" */