summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/tx1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/tx1.c')
-rw-r--r--src/mame/machine/tx1.c679
1 files changed, 679 insertions, 0 deletions
diff --git a/src/mame/machine/tx1.c b/src/mame/machine/tx1.c
new file mode 100644
index 00000000000..4cf3134049e
--- /dev/null
+++ b/src/mame/machine/tx1.c
@@ -0,0 +1,679 @@
+/*===================================================================*/
+/* TX-1/Buggy Boy (Tatsumi) Hardware */
+/* SN74S516 Arithmetic Unit and Interface Emulation */
+/* VERY PRELIMINARY! */
+/*===================================================================*/
+
+#include "driver.h"
+
+static INT16 AU_DATA;
+static INT16 *AU_PTR = &AU_DATA;
+static UINT16 inst_index;
+
+/* Internal registers and so forth */
+static struct Regs
+{
+ INT16 X; /* Multiplicand and divisor */
+ INT16 X1; /* Previous X */
+ INT16 Y; /* Multiplier */
+
+ INT16 Operand2;
+
+ union /* 32-bit accumulator */
+ {
+ #ifdef LSB_FIRST
+ struct { UINT16 W; INT16 Z;} ZW_16;
+ #else
+ struct { INT16 Z; UINT16 W;} ZW_16;
+ #endif
+ INT32 ZW_32;
+ } acc;
+
+ INT16 ins_seq; /* Instruciton sequence */
+} AU_Regs;
+
+
+/* Main portion of the arithmetic unit emulation. Accessed by AU_R and AU_W */
+/* Only a few instructions implemented currently */
+
+static void MMI_74S516(int ins, UINT16 *data)
+{
+
+ if ((ins!=7) && ((AU_Regs.ins_seq & 0xf)==7)) /* If last instruction was a reading operation, clear sequence. */
+ AU_Regs.ins_seq = 0;
+
+ /* Take INS and append to instruction */
+ AU_Regs.ins_seq <<=4;
+ AU_Regs.ins_seq = AU_Regs.ins_seq | (ins & 0xf);
+
+ switch ( AU_Regs.ins_seq )
+ {
+ /* X1 . Y */
+ case 0x0: AU_Regs.Y = *data;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* -X1 . Y */
+ case 0x1: AU_Regs.Y = *data;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* X1 . Y + Kz.Kw */
+ case 0x2: AU_Regs.Y = *data;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* -X1 . Y + Kz.Kw */
+ case 0x3: AU_Regs.Y = *data;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* Partial: Load X */
+ case 0x5: AU_Regs.X = *data;
+ break;
+ case 0x6: AU_Regs.X = *data;
+ break;
+
+
+ /* X * Y (Fractional) */
+ case 0x50: AU_Regs.Y = *data;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* X * Y (Integer) */ // Ok
+ case 0x60: AU_Regs.Y = *data;
+ AU_Regs.acc.ZW_32 = ((INT16)AU_Regs.X * (INT16)AU_Regs.Y);
+ AU_Regs.X1 = AU_Regs.X;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* -X * Y (Fractional) */
+ case 0x51: AU_Regs.Y = *data;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* -X * Y (Integer) */ // Ok
+ case 0x61: AU_Regs.Y = *data;
+ AU_Regs.acc.ZW_32 = (-(INT16)AU_Regs.X * (INT16)AU_Regs.Y);
+ AU_Regs.X1 = AU_Regs.X;
+ AU_Regs.ins_seq = 0;
+ break;
+
+
+ /* X * Y + Kz.Kw (Fractional) */
+ case 0x52: AU_Regs.Y = *data;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* X * Y + Kz.Kw (Integer) */ // Ok
+ case 0x62: AU_Regs.Y = *data;
+ AU_Regs.acc.ZW_32 += ((INT16)AU_Regs.X * (INT16)AU_Regs.Y);
+ AU_Regs.X1 = AU_Regs.X;
+ AU_Regs.ins_seq = 0;
+ break;
+
+
+ /* -X * Y + Kz.Kw (Fractional) */
+ case 0x53: AU_Regs.Y = *data;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* -X * Y + Kz.Kw (Integer) */ // Ok
+ case 0x63: AU_Regs.Y = *data;
+ AU_Regs.acc.ZW_32 += (-(INT16)AU_Regs.X * (INT16)AU_Regs.Y);
+ AU_Regs.X1 = AU_Regs.X;
+ AU_Regs.ins_seq = 0;
+ break;
+
+
+
+ /* Kw / X (Fractional) Nothing Loaded */
+ case 0x54: AU_Regs.ins_seq = 0;
+ break;
+
+ /* Kw / X (Integer) Nothing Loaded */
+ case 0x64: AU_Regs.acc.ZW_32 /= (INT16)AU_Regs.X;
+ AU_Regs.X1 = AU_Regs.X;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ /* Kz / X (Fractional) Nothing Loaded */
+ case 0x55: AU_Regs.ins_seq = 0;
+ break;
+
+
+ /* Kz / X (Integer) Nothing Loaded */
+ case 0x65: AU_Regs.acc.ZW_32=AU_Regs.ins_seq;
+ AU_Regs.ins_seq=0;
+ break;
+
+
+ /* This can either load Z,Nothing or 0? */
+ case 0x56: AU_Regs.Operand2 = *data;
+ break;
+
+
+ case 0x560: AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x561: AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x562: AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x563: AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x564: AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x565: AU_Regs.ins_seq = 0;
+ break;
+
+ // Not complete instruction
+ case 0x566:
+ AU_Regs.ins_seq = 0;
+ break;
+
+
+ case 0x660: AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x661: AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x662: AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x663: AU_Regs.ins_seq = 0;
+ break;
+
+ /* Z,W /X */
+ // result in Z, remainder in W
+ case 0x664: AU_Regs.acc.ZW_16.W = *data;
+ AU_Regs.acc.ZW_16.Z = AU_Regs.Operand2;
+ AU_Regs.acc.ZW_16.Z = (INT16)((INT32)AU_Regs.acc.ZW_32 / (INT16)AU_Regs.X); // wrong :(
+ AU_Regs.acc.ZW_16.W = (INT16)((INT32)AU_Regs.acc.ZW_32 % (INT16)AU_Regs.X); //correct!
+ AU_Regs.X1 = AU_Regs.X;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x665: AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x5660:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x5661:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x5662:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x5663:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x5664:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x5665:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x5666:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x5667:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x6660:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x6661:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x6662:AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x6663:AU_Regs.ins_seq = 0;
+ break;
+
+ /* W/X */
+ case 0x6664:AU_Regs.acc.ZW_32 = (INT16)AU_Regs.acc.ZW_16.W / (INT16)AU_Regs.X;
+ AU_Regs.X1 = AU_Regs.X;
+ AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x6665:
+ AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x6666:
+ AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x6667:
+ AU_Regs.ins_seq = 0;
+ break;
+
+ case 0x66: AU_Regs.Operand2 = *data;
+ break;
+
+ case 0x4: AU_Regs.ins_seq = 0;
+ break;
+
+ /* Reading Operations */
+
+ case 0x7: *data = AU_Regs.acc.ZW_16.Z;
+ break;
+
+ case 0x77: *data = AU_Regs.acc.ZW_16.W;
+ break;
+
+ case 0x777: *data = AU_Regs.acc.ZW_16.Z;
+ break;
+
+ case 0x7777: *data = AU_Regs.acc.ZW_16.W;
+ break;
+
+ default: break;
+ }
+
+}
+
+
+
+/******************************************************/
+/* */
+/* MMI SN74S516T Arithmetic Unit and Interface */
+/* */
+/******************************************************/
+
+/*
+The arithmetic unit is used extensively to calculate both object and road attributes in both games.
+It can take instructions directly from slave address bus A1-A3 or from a pair of PROMS (BB1.163 and BB2.162).
+Two 16KB function data ROMs are accessible by the chip and the slave CPU (via a hardware index and pointer).
+
+The interface between the arithmetic unit and the slave CPU is different between Buggy Boy and TX-1.
+
+In the case of an Buggy Boy PCB:
+Without AU: No objects visible, road is unchanging in direction.
+Without instruction PROMS: Hand/Go is displayed correctly as well as the end of race animation sequence (buggy spins and goes up in smoke).
+
+Therfore, once enough simple instructions are implemented, it should be possible do display some objects correctly.
+
+/MLPCS = !A10.!A11.A12.A13.!A14.!A15
+/DPRCS = A10.A11.A12.A13.!A14.!A15
+/INSALD = /AT3RD.!AT3WDRART + !AT3WDRART.A15 + !AT3WDRART.!A13 + !AT3WDRART.A14 + !AT3WDRART.!A12 + !A8
+/CNTST = /AT3RD.!AT3WDRART + !AT3WDRART.A15 + !AT3WDRART.!A13 + !AT3WDRART.A14 + !AT3WDRART.!A12 + !A7
+/SPCS = !A15.!A14.!A13.A12 + A14.!A13.!A12 + !A14.A12.A9 + !A14.A13.!A12 + !A14.!A11 + A15
+
+3000-31ff = Direct instruction input (AAB1-AAB3 connect to I0-2 of AU).
+
+3c00-3cff
+3d00-3dff
+3e00-3eff
+3f00-3fff = DATA ROM output enable.
+
+/SPCS = 0800-0fff
+ 3800-39ff
+ 3c00-3dff
+ 5000-7fff
+
+
+When CPU A8=1, the counters are loaded with an address (e.g. [3754] and [3120]).
+
+The counters are enabled on:
+
+* A7=1 (e.g. [3680] and [3A80]).
+* Read access to locations asserting /SPCS (e.g. [7a72] - those ROM mirror accesses have some significance afterall!)
+* BB2.162 bit 7 = 0 (/CUDEN).
+
+Writes to [36XX] and [37XX] load a value into the AU ROM address shift-registers .
+Reads from [36XX] (and [37xx] presumably) returns this value.
+Writes to [3A00] loads a shift value/direction.
+
+The AU ROM address shifting is governed by DSEL0-1 (BB2.162):
+
+00 = Invalid
+01 = >> 4
+10 = << 4
+11 = Shift direction and magnitude specified by 4-bit data value written to [3A00]:
+ A13-11 = 000 -> << by A10-7
+ A13-11 != 000 -> >> by A13-11 (LSB=0)
+
+ The shift magnitude is specified by the number of number of 0s between the LSB (inclusive) and the '1'. Shifting is circular.
+
+Examples:
+
+13 [3754] <- 2DB5
+ [3A00] <- 0100
+ [3600] == B6D4 ? // 0x2DB5 << 2 == 0xB6D4
+
+14 [3600] <- 2DB5
+ [3A00] <- 0200
+ [3600] == 5B6A ? // 0x2DB5 << 1 == 0x5B6A
+
+15 [3600] <- 2DB5
+ [3A00] <- 0400
+ [3600] == 2DB5 // No shift.
+
+16 [3600] <- 2DB5
+ [3A00] <- 0800
+ [3600] == 96DA ? // 0x2DB5 >> 1 == 0x96DA
+
+17 [3600] <- 2DB5
+ [3A00] <- 1000
+ [3600] = 4B6D ? // 0x2DB5 >> 2 == 0x4B6D
+
+18 [3600] <- 2DB5
+ [3A00] <- 2000
+ [3600] = A5B6 ? // 0x2DB5 >> 3 == 0xA5B6
+
+19 [3600] <- 1568
+ [3A00] <- 2000
+ [3E00] = 1BF2 ? // 0x1568 >> 3 == 0x02AD -> AU_ROM[0x02AD] == 0x1BF2
+
+
+The 14-bit AU ROM address is formed from:
+
+A13-11 = TFAD13-11 (BB2.162 D4-2)
+A10-8 = If RADCHG = 1: AU PROM address bits 7-5
+ If RADCHG = 0: Bits 10-8 of shift registers
+A7-0 = Bits 7-0 of shift registers.
+
+The current implementation of accessing the AU ROM is wrong (it's based on software behaviour rather than the actual hardware )
+
+Here's the full list of AU tests performed during test mode:
+
+ST
+ [300C] <- AA55
+ [3000] <- 55AA
+04 [300E] = E355 ?
+04 [300E] = 5572 ?
+
+ [300C] <- AA55
+ [3002] <- 55AA
+05 [300E] = 1CAA ?
+05 [300E] = AA8E ?
+
+ [300C] <- 5A5A
+ [3004] <- A5A5
+06 [300E] = FCC6 ?
+06 [300E] = E890 ?
+
+ [300C] <- AA55
+ [3006] <- 55AA
+07 [300E] = 1971 ?
+07 [300E] = 931E ?
+
+ [300C] <- 1000
+ [300C] <- 5678
+ [3008] <- 8765
+08 [300E] = ff88 ?
+08 [300E] = 0765 ?
+
+ [300C] <- 0200
+ [300C] <- FFFF
+ [300C] <- 55AA
+ [3008] <- FFFF
+09 [300E] = 002a ?
+09 [300E] = 01aa ?
+
+ [3752] <- AA55
+10 [3600] = AA55 ?
+
+ [3600] <- 55AA
+10 [3680] = 55AA ?
+
+11 [3680] = A55A ?
+12 [3600] = 55AA ?
+
+ [3754] <- 2DB5
+ [3A00] <- 0100
+13 [3600] = B6D4 ?
+
+ [3600] <- 2DB5
+ [3A00] <- 0200
+14 [3600] = 5B6A ?
+
+15 [3600] <- 2DB5
+ [3A00] <- 0400
+ [3600] = 2DB5 ?
+
+16 [3600] <- 2DB5
+ [3A00] <- 0800
+ [3600] = 96DA ?
+
+17 [3600] <- 2DB5
+ [3A00] <- 1000
+ [3600] = 4B6D ?
+
+18 [3600] <- 2DB5
+ [3A00] <- 2000
+ [3600] = A5B6 ?
+
+19 [3600] <- 1568
+ [3A00] <- 2000
+ [3E00] = 1BF2 ?
+
+1A [7A68] = 0000 ?
+
+1B [3680] <- AA55
+ [7A6A] = 55AA ?
+
+1C [3200] <- AA55
+ [300E] = E355 ?
+
+1D [3754] <- AA55
+ [7A6A] = 55AA ?
+
+1E [3680] <- AA55
+ [7A6A] = 55AA ?
+
+1F [7A6C] = AA55 ?
+
+20 [300E] = 1CAA ?
+
+21 [300C] <- 55AA
+ [3200] <- AA55
+ [300E] = E355 ?
+
+22 [3E00] = 14D5 ?
+23 [308C] <- 55AA
+ [7A70] = 15AA ?
+
+24 [7A6E] = 2000 ?
+25 [3600] = 42B5 ?
+26 [3E80] = 1CC2 ?
+27 [308E] = 099F ?
+28 [3680] = 4099 ?
+29 [3680] = 2D40 ?
+2A [3C00] = 5Cf4 ?
+2B [3600] = 5Cf4 ?
+2C [300C] <- 55AA
+ [3A80] = FFFF ?
+2D [300E] = FFFF ?
+2E [300E] = AA56 ?
+ [3600] <- 0000
+2F [4000] = 00BC ?
+30 [3600] = 0000 ?
+
+ [310C] <- 0078
+ [308C] <- 3F70
+40 [3680] = 0087 ?
+
+ [3600] <- 0020
+41 [3680] = 0100 ?
+
+ [3680] <- 533f
+42 [300e] = 0058 ?
+
+ [315c] <- 0020
+43 [7a72] = 0087 ?
+
+44 [3700] = 0080 ?
+
+ [300c] <- 00cc
+ [3000] <- 0074
+45 [308e] = 0000 ?
+
+46 [7a74] = 0078 ?
+ [308c] <- 0000
+47 [300e] = 00c5 ?
+
+ [300c] <- 0074
+ [3000] <- 008c
+48 [311e] = 0000 ?
+
+ [300c] <- 0224
+ [308c] <- 0000
+49 [300e] = 001c ?
+
+ [3724] <- 000c
+ [3000] <- 0078
+4a [300e] = 007c
+
+ [3728] <- 0023
+4b [3e80] = 0055 ?
+4c [3e00] = 0045 ?
+
+ [3600] <- fca2
+ [313c] <- 0118
+ [308c] <- ff42
+4d [300e] = 007e ?
+
+ [312c] <- 0040
+ [308c] <- 00f8
+4e [300e] = 0080 ?
+
+ [300c] <- 0261
+ [3130] <- 2000
+4f [3680] = 004c ?
+
+ [300c] <- 000f
+ [3008] <- e440
+50 [300e] = 0111 ?
+
+51 [7a7a] = 41fd ?
+ [3740] <- 010e
+
+52 [7a76] = 4000 ?
+53 [7a78] = 03a9 ?
+
+ [3280] <- 0800
+54 [3e00] = ff52 ?
+
+ [3680] <- 001e
+55 [3680] = ffcd ?
+
+56 [3600] = fff0 ?
+
+ [314c] <- 0091
+ [3680] <- 0300
+
+57 [3680] = 015e ?
+
+ [3680] <- 00d5
+ [3704] <- 0002
+58 [3600] = 0015 ?
+
+ [3600] <- 0086
+ [317c] <- 0013
+59 [300e] = 09f2 ?
+
+ [300c] <- 0010
+ [3120] <- 011c
+5a [300e] = 11c0 ?
+
+*/
+
+READ16_HANDLER(BB_AU_R)
+{
+UINT8 *AU_instr = (UINT8 *)memory_region(REGION_USER1);
+//UINT8 *AU_PROM1 = (UINT8 *)memory_region(REGION_PROMS) + 0x1700;
+//UINT8 *AU_PROM2 = (UINT8 *)memory_region(REGION_PROMS) + 0x1900;
+
+INT16 value = 0;
+
+ switch (offset)
+ {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7: MMI_74S516(offset, (UINT16*)AU_PTR); /* Typically Instruction 7 - read result(s) */
+ value = *AU_PTR;
+ break;
+
+ case 0x0e00/2: value = AU_instr[inst_index] | (AU_instr[inst_index] << 8);
+ break;
+
+ case 0x0680/2:
+ break; /* Use to change upper ROM address portion? */
+
+ case 0x0726/2:
+ break;
+
+ default: value = 0;
+ break;
+ }
+
+ return value;
+
+}
+
+WRITE16_HANDLER(BB_AU_W)
+{
+//UINT8 *AU_PROM1 = (UINT8 *)memory_region(REGION_PROMS) + 0x1700;
+//UINT8 *AU_PROM2 = (UINT8 *)memory_region(REGION_PROMS) + 0x1900;
+
+ switch (offset)
+ {
+
+ case 0x0: COMBINE_DATA(AU_PTR);
+ MMI_74S516(offset, (UINT16*)AU_PTR); /* Load values */
+ break;
+
+ case 0x1: COMBINE_DATA(AU_PTR);
+ MMI_74S516(offset, (UINT16*)AU_PTR);
+ break;
+
+ case 0x2: COMBINE_DATA(AU_PTR);
+ MMI_74S516(offset, (UINT16*)AU_PTR);
+ break;
+
+ case 0x3: COMBINE_DATA(AU_PTR);
+ MMI_74S516(offset, (UINT16*)AU_PTR);
+ break;
+
+ case 0x4: COMBINE_DATA(AU_PTR);
+ MMI_74S516(offset, (UINT16*)AU_PTR);
+ break;
+
+ case 0x5: COMBINE_DATA(AU_PTR);
+ MMI_74S516(offset, (UINT16*)AU_PTR);
+ break;
+
+ case 0x6: COMBINE_DATA(AU_PTR);
+ MMI_74S516(offset, (UINT16*)AU_PTR);
+ break;
+
+ case 0x7: COMBINE_DATA(AU_PTR);
+ MMI_74S516(offset, (UINT16*)AU_PTR);
+ break;
+
+ /* Accessing FN ROMs */
+ case 0x0600/2:
+ COMBINE_DATA(&inst_index);
+ break;
+
+
+ case 0x0680/2: break; /* Increment instruction PROM address */
+ case 0x0726/2: break;
+ }
+}
+