tx0_64kw, tx0_8kw: Fixes and improvements

- Complete rewrite of disassemblers, using standard names for OPRs
- Clear MBR in cycle 1 when AMB is not specified
- Perform AMB before COM (tx0_64kw)
- Fix characters printed on Flexowriter (bit order was incorrectly reversed)
- Modernize logging in CPU device
- Only call the debugger hook once per instruction cycle
This commit is contained in:
AJR 2021-08-12 15:53:43 -04:00
parent d62f1a7afc
commit debdcf365d
3 changed files with 687 additions and 109 deletions

View File

@ -15,8 +15,9 @@
#include "tx0dasm.h"
#include "debugger.h"
#define LOG 0
#define LOG_EXTRA 0
#define LOG_RIM (1 << 1U)
//#define VERBOSE (LOG_RIM)
#include "logmacro.h"
#define READ_TX0_18BIT(A) ((signed)m_program->read_dword(A))
@ -255,9 +256,6 @@ void tx0_64kw_device::execute_run()
{
do
{
debugger_instruction_hook(PC);
if (m_ioh && m_ios)
{
m_ioh = 0;
@ -265,7 +263,10 @@ void tx0_64kw_device::execute_run()
if ((! m_run) && (! m_rim))
{
debugger_instruction_hook(PC);
m_icount = 0; /* if processor is stopped, just burn cycles */
}
else if (m_rim)
{
switch (m_rim_step)
@ -295,6 +296,7 @@ void tx0_64kw_device::execute_run()
m_rim = 0; /* exit read-in mode */
m_run = (IR == 2) ? 1 : 0; /* stop if add instruction */
m_rim_step = 0;
LOGMASKED(LOG_RIM, "RIM %s: PC <- %06o\n", (IR == 2) ? "start" : "stop", PC);
}
else if ((IR == 0) || (IR == 3)) /* sto or opr instruction? */
{
@ -321,6 +323,7 @@ void tx0_64kw_device::execute_run()
{ /* data transfer complete */
m_ios = 0;
LOGMASKED(LOG_RIM, "RIM transfer: %06o <- %06o\n", MAR, AC);
tx0_write(MAR, MBR = AC);
m_rim_step = 0;
@ -332,6 +335,7 @@ void tx0_64kw_device::execute_run()
{
if (m_cycle == 0)
{ /* fetch new instruction */
debugger_instruction_hook(PC);
MBR = tx0_read(MAR = PC);
INCREMENT_PC_64KW;
IR = MBR >> 16; /* basic opcode */
@ -358,9 +362,6 @@ void tx0_8kw_device::execute_run()
{
do
{
debugger_instruction_hook(PC);
if (m_ioh && m_ios)
{
m_ioh = 0;
@ -368,7 +369,10 @@ void tx0_8kw_device::execute_run()
if ((! m_run) && (! m_rim))
{
debugger_instruction_hook(PC);
m_icount = 0; /* if processor is stopped, just burn cycles */
}
else if (m_rim)
{
switch (m_rim_step)
@ -398,6 +402,7 @@ void tx0_8kw_device::execute_run()
m_rim = 0; /* exit read-in mode */
m_run = (IR == 16) ? 1 : 0; /* stop if add instruction */
m_rim_step = 0;
LOGMASKED(LOG_RIM, "RIM %s: PC <- %05o\n", (IR == 16) ? "start" : "stop", PC);
}
else if ((IR == 0) || (IR == 24)) /* sto or opr instruction? */
{
@ -424,6 +429,7 @@ void tx0_8kw_device::execute_run()
{ /* data transfer complete */
m_ios = 0;
LOGMASKED(LOG_RIM, "RIM transfer: %05o <- %06o\n", MAR, AC);
tx0_write(MAR, MBR = AC);
m_rim_step = 0;
@ -435,6 +441,7 @@ void tx0_8kw_device::execute_run()
{
if (m_cycle == 0)
{ /* fetch new instruction */
debugger_instruction_hook(PC);
MBR = tx0_read(MAR = PC);
INCREMENT_PC_8KW;
IR = MBR >> 13; /* basic opcode */
@ -551,6 +558,8 @@ void tx0_64kw_device::execute_instruction_64kw()
break;
case 3: /* OPeRate */
MBR = 0;
if ((MAR & 0000104) == 0000100)
/* (1.1) PEN = Read the light pen flip-flops 1 and 2 into AC(0) and
AC(1). */
@ -560,19 +569,19 @@ void tx0_64kw_device::execute_instruction_64kw()
/* (1.1) TAC = Insert a one in each digital position of the AC
wherever there is a one in the corresponding digital position
of the TAC. */
/*...*/ { }
if (MAR & 0000040)
/* (1.2) COM = Complement every digit in the accumulator */
AC ^= 0777777;
AC |= m_tac;
if ((MAR & 0000003) == 1)
/* (1.2) AMB = Store the contents of the AC in the MBR. */
MBR = AC;
if (MAR & 0000040)
/* (1.2) COM = Complement every digit in the accumulator */
AC ^= 0777777;
if ((MAR & 0000003) == 3)
/* (1.2) TBR = Store the contents of the TBR in the MBR. */
/*...*/ { }
MBR |= m_tbr;
if ((MAR & 0000003) == 2)
/* (1.3) LMB = Store the contents of the LR in the MBR. */
@ -633,8 +642,6 @@ void tx0_device::indexed_address_eval()
{
MAR = MAR + XR;
MAR = (MAR + (MAR >> 14)) & 0037777; /* propagate carry around */
if (MAR & 0020000) /* fix negative (right???) */
MAR = (MAR + 1) & 0017777;
}
/* execute one instruction */
@ -921,6 +928,9 @@ void tx0_8kw_device::execute_instruction_8kw()
/* (1.1) TAC = transfer TAC into ac (inclusive or) */
AC |= m_tac;
if ((IR & 002) == 00)
MBR = 0; // MBR cleared at 1.1
if (((IR & 001) == 00) && ((MAR & 017000) == 002000))
/* (1.2) TBR = transfer TBR into mbr (inclusive or) */
MBR |= m_tbr;
@ -953,8 +963,7 @@ void tx0_8kw_device::execute_instruction_8kw()
break;
default:
if (LOG)
logerror("unrecognized instruction");
LOG("unrecognized instruction\n");
break;
}
}
@ -991,8 +1000,7 @@ void tx0_8kw_device::execute_instruction_8kw()
break;
default:
if (LOG)
logerror("unrecognized instruction");
LOG("unrecognized instruction\n");
break;
}
}

View File

@ -1,5 +1,11 @@
// license:BSD-3-Clause
// copyright-holders:Raphael Nabet
// copyright-holders:AJR
/***************************************************************************
MIT TX-0 disassembler
***************************************************************************/
#include "emu.h"
#include "tx0dasm.h"
@ -8,126 +14,689 @@ u32 tx0_64kw_disassembler::opcode_alignment() const
return 1;
}
offs_t tx0_64kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
{
int md;
int x;
md = opcodes.r32(pc);
x = md & 0177777;
switch (md >> 16)
{
case 0:
util::stream_format(stream, "sto 0%06o", x);
break;
case 1:
util::stream_format(stream, "add 0%06o", x);
break;
case 2:
util::stream_format(stream, "trn 0%06o", x);
break;
case 3:
util::stream_format(stream, "opr 0%06o", x);
break;
}
return 1;
}
u32 tx0_8kw_disassembler::opcode_alignment() const
{
return 1;
}
offs_t tx0_8kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
namespace {
const std::string_view s_addressable_insts[24] =
{
int md;
int x;
"sto", "stx", "sxa", "ado", "slr", "slx", "stz", {},
"add", "adx", "ldx", "aux", "llr", "llx", "lda", "lax",
"trn", "tze", "tsx", "tix", "tra", "trx", "tlv", {}
};
md = opcodes.r32(pc);
const std::string_view s_tape_insts[8] =
{
"bsr", "rtb", "rew", "wtb",
"bsr", "rtd", "rew", "wtd"
};
x = md & 0017777;
switch (md >> 13)
} // anonymous namespace
offs_t tx0_64kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const tx0_64kw_disassembler::data_buffer &opcodes, const tx0_64kw_disassembler::data_buffer &params)
{
u32 inst = opcodes.r32(pc) & 0777777;
if (inst < 0600000)
{
case 0:
util::stream_format(stream, "sto 0%05o", x);
// Addressable instructions (only 3 in this version)
util::stream_format(stream, "%s %06o", s_addressable_insts[(inst & 0600000) >> 13], inst & 0177777);
}
else switch (inst)
{
case 0600012:
stream << "cry";
break;
case 1:
util::stream_format(stream, "stx 0%05o", x);
case 0600022:
stream << "lpd";
break;
case 2:
util::stream_format(stream, "sxa 0%05o", x);
case 0600031:
stream << "cyl";
break;
case 3:
util::stream_format(stream, "ado 0%05o", x);
case 0600032:
stream << "lad";
break;
case 4:
util::stream_format(stream, "slr 0%05o", x);
case 0600040:
stream << "com";
break;
case 5:
util::stream_format(stream, "slx 0%05o", x);
case 0600051:
stream << "amz";
break;
case 6:
util::stream_format(stream, "stz 0%05o", x);
case 0600100:
stream << "pen";
break;
case 8:
util::stream_format(stream, "add 0%05o", x);
case 0600200:
stream << "lro";
break;
case 9:
util::stream_format(stream, "adx 0%05o", x);
case 0600201:
stream << "alr";
break;
case 10:
util::stream_format(stream, "ldx 0%05o", x);
case 0600221:
stream << "ala";
break;
case 11:
util::stream_format(stream, "aux 0%05o", x);
case 0600261:
stream << "alc";
break;
case 12:
util::stream_format(stream, "llr 0%05o", x);
case 0600400:
stream << "shr";
break;
case 13:
util::stream_format(stream, "llx 0%05o", x);
case 0600600:
stream << "cyr";
break;
case 14:
util::stream_format(stream, "lda 0%05o", x);
case 0622000:
stream << "dis";
break;
case 15:
util::stream_format(stream, "lax 0%05o", x);
case 0622021:
stream << "dsa";
break;
case 16:
util::stream_format(stream, "trn 0%05o", x);
case 0622061:
stream << "dsc";
break;
case 17:
util::stream_format(stream, "tze 0%05o", x);
case 0624000:
stream << "prt";
break;
case 18:
util::stream_format(stream, "tsx 0%05o", x);
case 0624021:
stream << "pna";
break;
case 19:
util::stream_format(stream, "tix 0%05o", x);
case 0624061:
stream << "pnc";
break;
case 20:
util::stream_format(stream, "tra 0%05o", x);
case 0624600:
stream << "pnt";
break;
case 21:
util::stream_format(stream, "trx 0%05o", x);
case 0626021: case 0627021:
util::stream_format(stream, "p%da", BIT(inst, 9) ? 7 : 6);
break;
case 22:
util::stream_format(stream, "tlv 0%05o", x);
case 0626600: case 0627600:
util::stream_format(stream, "p%dh", BIT(inst, 9) ? 7 : 6);
break;
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
util::stream_format(stream, "opr 0%06o", md & 0177777);
case 0630000:
stream << "hlt";
break;
case 0640000:
stream << "clr";
break;
case 0666020: case 0667020:
util::stream_format(stream, "p%do", BIT(inst, 9) ? 7 : 6);
break;
case 0700000:
stream << "cll";
break;
case 0740000:
stream << "cla";
break;
case 0740004:
stream << "tac";
break;
case 0740022:
stream << "lac";
break;
case 0740023:
stream << "tbr";
break;
case 0740040:
stream << "clc";
break;
case 0740200:
stream << "cal";
break;
case 0761000:
stream << "r1c";
break;
case 0761031:
stream << "r1l";
break;
case 0761600:
stream << "r1r";
break;
case 0763000:
stream << "r3c";
break;
case 0766000:
stream << "p6s";
break;
default:
util::stream_format(stream, "illegal");
if (inst >= 0760000)
util::stream_format(stream, "ios %o", inst & 017777);
else
util::stream_format(stream, "opr %o", inst & 0177777);
break;
}
return 1;
return 1 | SUPPORTED;
}
offs_t tx0_8kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const tx0_8kw_disassembler::data_buffer &opcodes, const tx0_8kw_disassembler::data_buffer &params)
{
u32 inst = opcodes.r32(pc) & 0777777;
if (inst < 0600000)
{
// Addressable instructions
std::string_view str = s_addressable_insts[(inst & 0760000) >> 13];
if (str.empty())
util::stream_format(stream, "%06o", inst);
else
{
util::stream_format(stream, "%s %05o", str, inst & 017777);
if ((inst & 0760000) == 0440000) // tsx
return 1 | STEP_OVER | SUPPORTED;
else if ((inst & 0760000) == 0520000) // trx
return 1 | STEP_OUT | SUPPORTED;
}
}
else if ((inst & 037000) == 004000)
{
// Select class
if (BIT(inst, 15))
stream << "claU";
util::stream_format(stream, "%s %d", s_tape_insts[BIT(inst, 2, 3)], inst & 3);
}
else
{
if ((inst & 037000) == 02000)
{
stream << "tbr";
if ((inst & 0100757) == 0)
return 1 | SUPPORTED;
stream << 'U';
}
else if (inst == 0706020)
{
stream << "rpf";
return 1 | SUPPORTED;
}
else if ((inst & 037000) == 07000)
{
if (BIT(inst, 14))
stream << "spf";
else
stream << "cpf";
if ((inst & 0100777) == 0)
return 1 | SUPPORTED;
stream << 'U';
}
else if ((inst & 037000) == 020000)
{
stream << "cpy";
if ((inst & 0100777) == 0)
return 1 | SUPPORTED;
stream << 'U';
}
else if ((inst & 037000) == 025000)
{
stream << "typ";
if ((inst & 0100777) == 0)
return 1 | SUPPORTED;
stream << 'U';
}
else if ((inst & 036777) == 026600)
{
util::stream_format(stream, "p%dh", BIT(inst, 9) ? 7 : 6);
return 1 | SUPPORTED;
}
else if ((inst & 076777) == 066020)
{
util::stream_format(stream, "p%do", BIT(inst, 9) ? 7 : 6);
return 1 | SUPPORTED;
}
else if ((inst & 037000) == 030000)
{
// HLT is actually executed last, but normally written first
stream << "hlt";
if ((inst & 0100777) == 0)
return 1 | SUPPORTED;
stream << 'U';
}
else if ((inst & 037000) == 031000)
{
stream << "cll";
if ((inst & 0100777) == 0)
return 1 | SUPPORTED;
stream << 'U';
}
else if ((inst & 037000) == 032000)
{
stream << "clr";
if ((inst & 0100777) == 0)
return 1 | SUPPORTED;
stream << 'U';
}
else if ((inst & 037000) != 0)
{
if (BIT(inst, 15))
{
switch (inst & 037000)
{
case 01000:
stream << "tac";
break;
case 03000:
stream << "claUpen";
break;
case 010000: case 011000: case 012000: case 013000: case 014000: case 015000: case 016000: case 017000:
util::stream_format(stream, "claUex%d", BIT(inst, 9, 3));
break;
case 021000:
if ((inst & 0777) == 0600)
{
stream << "r1r";
return 1 | SUPPORTED;
}
stream << "r1c";
break;
case 022000:
stream << "claUdis";
break;
case 023000:
stream << "r3c";
break;
case 024000:
stream << "claUprt";
break;
case 026000:
if ((inst & 040777) == 040020)
{
stream << "p6b";
return 1 | SUPPORTED;
}
stream << "p6s";
break;
default:
util::stream_format(stream, "opr %o", inst & 0177777);
return 1 | SUPPORTED;
}
if ((inst & 0777) == 0)
return 1 | SUPPORTED;
inst &= 040777;
stream << 'U';
}
else
{
switch (inst & 037000)
{
case 03000:
stream << "pen";
break;
case 010000: case 011000: case 012000: case 013000: case 014000: case 015000: case 016000: case 017000:
util::stream_format(stream, "ex%d", BIT(inst, 9, 3));
break;
case 021000:
stream << "r1l";
break;
case 022000:
if ((inst & 040777) == 040020)
{
stream << "dso";
return 1 | SUPPORTED;
}
stream << "dis";
break;
case 023000:
stream << "r3l";
break;
case 024000:
if ((inst & 040777) == 040020)
{
stream << "pno";
return 1 | SUPPORTED;
}
else if ((inst & 040777) == 040060)
{
stream << "pnc";
return 1 | SUPPORTED;
}
else if ((inst & 0777) == 0600)
{
stream << "pnt";
return 1 | SUPPORTED;
}
stream << "prt";
break;
default:
util::stream_format(stream, "opr %o", inst & 0177777);
return 1 | SUPPORTED;
}
if ((inst & 0777) == 0)
return 1 | SUPPORTED;
stream << 'U';
}
}
else if (inst == 0600000)
{
stream << "nop";
return 1 | SUPPORTED;
}
switch (inst & 0140777)
{
case 0:
break;
case 000001:
stream << "xro";
break;
case 000003:
stream << "lxr";
break;
case 000012:
stream << "cry";
break;
case 000022:
stream << "lpd";
break;
case 000031:
stream << "alx";
break;
case 000032:
stream << "lad";
break;
case 000033:
stream << "ladUxro";
break;
case 000040: case 040040:
stream << "com";
break;
case 000041:
stream << "comUxro";
break;
case 000043:
stream << "comUlxr";
break;
case 000062:
stream << "lpdUcom";
break;
case 000072:
stream << "lcd";
break;
case 000130:
stream << "xad";
break;
case 000170:
stream << "xcd";
break;
case 000200:
stream << "lro";
break;
case 000240:
stream << "comUlro";
break;
case 000272:
stream << "lcdUlro";
break;
case 000300:
stream << "xlr";
break;
case 000303:
stream << "ixl";
break;
case 000400:
stream << "shr";
break;
case 000600:
stream << "cyr";
break;
case 000612:
stream << "cyrUcry"; // M-5001-19 names this 'ran' (random number generator)
break;
case 000640:
stream << "comUcyr";
break;
case 040001:
stream << "axr";
break;
case 040021:
stream << "axo";
break;
case 040030:
stream << "cyl";
break;
case 040031:
stream << "axrUcyl";
break;
case 040050:
stream << "amz";
break;
case 040061:
stream << "axc";
break;
case 040200:
stream << "alr";
break;
case 040201:
stream << "alrUaxr";
break;
case 040203:
stream << "rax";
break;
case 040205:
stream << "orl";
break;
case 040207:
stream << "anl";
break;
case 040220:
stream << "alo";
break;
case 040230:
stream << "all";
break;
case 040231:
stream << "alrUalx";
break;
case 040232:
stream << "iad";
break;
case 040240:
stream << "alrUcom";
break;
case 040247:
stream << "anlUcom";
break;
case 040260:
stream << "alc";
break;
case 040601:
stream << "arx";
break;
case 0100000: case 0140000:
stream << "cla";
break;
case 0100001:
stream << "cax";
break;
case 0100012:
stream << "lal";
break;
case 0100022: case 0140022:
stream << "lac";
break;
case 0100023:
stream << "lacUlxr";
break;
case 0100040: case 0140040:
stream << "clc";
break;
case 0100062:
stream << "lcc";
break;
case 0100072:
stream << "laz";
break;
case 0100110:
stream << "xal";
break;
case 0100120:
stream << "xac";
break;
case 0100160:
stream << "xcc";
break;
case 0100200:
stream << "cal";
break;
case 0100240:
stream << "calUcom";
break;
case 0100322:
stream << "rxa";
break;
case 0100622:
stream << "lar";
break;
case 0140025:
stream << "ora";
break;
case 0140027:
stream << "ana";
break;
case 0140065:
stream << "oraUcom"; // M-5001-19-1 names this 'orc'
break;
case 0140067:
stream << "anaUcom"; // M-5001-19-1 names this 'anc'
break;
case 0140205:
stream << "oro";
break;
case 0140207:
stream << "ano";
break;
case 0140212:
stream << "lalUalr"; // M-5001-19-1 names this 'ill'
break;
case 0140222:
stream << "ial";
break;
case 0140262:
stream << "ialUcom";
break;
default:
util::stream_format(stream, "opr %o", inst & 0140777);
break;
}
}
return 1 | SUPPORTED;
}

View File

@ -406,6 +406,7 @@ public:
// image-level overrides
virtual iodevice_t image_type() const noexcept override { return IO_PUNCHTAPE; }
virtual bool support_command_line_image_creation() const noexcept override { return true; }
virtual bool is_readable() const noexcept override { return false; }
virtual bool is_writeable() const noexcept override { return true; }
@ -764,7 +765,7 @@ WRITE_LINE_MEMBER( tx0_state::tx0_io_prt )
/* read current 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);
ch = bitswap<6>(ac, 15, 12, 9, 6, 3, 0);
typewriter_out(ch);
m_typewriter.prt_timer->adjust(attotime::from_msec(100));