trunk/src/emu/cpu/tms0980/tms0980.c
| r242266 | r242267 | |
| 91 | 91 | #define M_STSL 0x00080000 /* STATUS to Status Latch */ |
| 92 | 92 | #define M_YTP 0x00100000 /* Y to +ALU */ |
| 93 | 93 | |
| 94 | #define M_RSTR 0x00200000 /* -> F_RSTR */ |
| 95 | |
| 94 | 96 | /* Standard/fixed instructions - these are documented more in their specific handlers below */ |
| 95 | 97 | #define F_BR 0x00000001 |
| 96 | 98 | #define F_CALL 0x00000002 |
| r242266 | r242267 | |
| 115 | 117 | |
| 116 | 118 | |
| 117 | 119 | // supported types: |
| 118 | | // note: dice information assumes the orientation is pictured with RAM at the bottom-left |
| 120 | // note: dice information assumes the orientation is pictured with RAM at the bottom-left, except where noted |
| 119 | 121 | |
| 120 | 122 | // TMS1000 |
| 121 | 123 | // - 64x4bit RAM array at the bottom-left |
| r242266 | r242267 | |
| 127 | 129 | // - 20-term output PLA(opla) at the top-left |
| 128 | 130 | // - the ALU is between the opla and mpla |
| 129 | 131 | const device_type TMS1000 = &device_creator<tms1000_cpu_device>; // 28-pin DIP, 11 R pins |
| 132 | const device_type TMS1070 = &device_creator<tms1070_cpu_device>; // same as tms1000, just supports higher voltage |
| 130 | 133 | const device_type TMS1200 = &device_creator<tms1200_cpu_device>; // 40-pin DIP, 13 R pins |
| 131 | | const device_type TMS1070 = &device_creator<tms1070_cpu_device>; // same as tms1000, just supports higher voltage |
| 132 | 134 | // TMS1270 has 10 O pins, how does that work? |
| 133 | 135 | |
| 134 | 136 | // TMS1100 is nearly the same as TMS1000, some different opcodes, and with double the RAM and ROM |
| r242266 | r242267 | |
| 140 | 142 | // - 2048x9bit ROM array at the bottom-left |
| 141 | 143 | // - main instructions PLA at the top half, to the right of the midline |
| 142 | 144 | // - 64-term microinstructions PLA between the RAM and ROM, supporting 20 microinstructions |
| 143 | | // - 16-term output PLA and segment PLA above the RAM |
| 144 | | const device_type TMS0980 = &device_creator<tms0980_cpu_device>; // 28-pin DIP, 9 R pins |
| 145 | // - 16-term output PLA and segment PLA above the RAM (rotate opla 90 degrees) |
| 146 | const device_type TMS0980 = &device_creator<tms0980_cpu_device>; // 28-pin DIP, 9 R pins, 5 K pins |
| 145 | 147 | |
| 146 | 148 | // TMS0970 is a stripped-down version of the TMS0980, itself acting more like a TMS1000 |
| 147 | | // - 64x4bit RAM array at the bottom-left |
| 148 | | // - 1024x8bit ROM array at the bottom-right |
| 149 | // - RAM and ROM is exactly the same as TMS1000 |
| 149 | 150 | // - main instructions PLA at the top half, to the right of the midline |
| 150 | 151 | // - 32-term microinstructions PLA between the RAM and ROM, supporting 15 microinstructions |
| 151 | | // - 16-term output PLA and segment PLA above the RAM |
| 152 | // - 16-term output PLA and segment PLA above the RAM (rotate opla 90 degrees) |
| 152 | 153 | const device_type TMS0970 = &device_creator<tms0970_cpu_device>; // 28-pin DIP, 11 R pins |
| 153 | 154 | |
| 155 | // TMC0270 on the other hand, is a TMS0980 with earrings and a new hat. The new changes look like a quick afterthought, almost hacky |
| 156 | // - RAM, ROM, and main instructions PLA is exactly the same as TMS0980 |
| 157 | // - 64-term microinstructions PLA between the RAM and ROM, supporting 20 microinstructions plus optional separate lines for custom opcode handling |
| 158 | // - 48-term output PLA above the RAM (rotate opla 90 degrees) |
| 159 | const device_type TMC0270 = &device_creator<tmc0270_cpu_device>; // 40-pin DIP, 16 O pins, 8 R pins (the other R pins are internally hooked up to support more I/O) |
| 160 | // TMC0260 is same? except opla is 32 instead of 48 terms |
| 154 | 161 | |
| 162 | |
| 155 | 163 | static ADDRESS_MAP_START(program_11bit_9, AS_PROGRAM, 16, tms1xxx_cpu_device) |
| 156 | 164 | AM_RANGE(0x000, 0xfff) AM_ROM |
| 157 | 165 | ADDRESS_MAP_END |
| r242266 | r242267 | |
| 232 | 240 | { |
| 233 | 241 | } |
| 234 | 242 | |
| 243 | tms0980_cpu_device::tms0980_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 k_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) |
| 244 | : tms0970_cpu_device(mconfig, type, name, tag, owner, clock, o_pins, r_pins, k_pins, pc_bits, byte_bits, x_bits, prgwidth, program, datawidth, data, shortname, source) |
| 245 | { |
| 246 | } |
| 235 | 247 | |
| 236 | 248 | |
| 249 | tmc0270_cpu_device::tmc0270_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 250 | : tms0980_cpu_device(mconfig, TMC0270, "TMC0270", tag, owner, clock, 16, 8, 4, 7, 9, 4, 12, ADDRESS_MAP_NAME(program_11bit_9), 8, ADDRESS_MAP_NAME(data_64x9_as4), "tmc0270", __FILE__) |
| 251 | { |
| 252 | } |
| 253 | |
| 254 | |
| 255 | |
| 237 | 256 | static MACHINE_CONFIG_FRAGMENT(tms1000) |
| 238 | 257 | |
| 239 | 258 | // microinstructions PLA, output PLA |
| r242266 | r242267 | |
| 287 | 306 | } |
| 288 | 307 | |
| 289 | 308 | |
| 309 | static MACHINE_CONFIG_FRAGMENT(tmc0270) |
| 290 | 310 | |
| 311 | // main opcodes PLA, microinstructions PLA, output PLA |
| 312 | MCFG_PLA_ADD("ipla", 9, 22, 24) |
| 313 | MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) |
| 314 | MCFG_PLA_ADD("mpla", 6, 21, 64) |
| 315 | MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) |
| 316 | MCFG_PLA_ADD("opla", 6, 16, 48) |
| 317 | MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) |
| 318 | MACHINE_CONFIG_END |
| 319 | |
| 320 | machine_config_constructor tmc0270_cpu_device::device_mconfig_additions() const |
| 321 | { |
| 322 | return MACHINE_CONFIG_NAME(tmc0270); |
| 323 | } |
| 324 | |
| 325 | |
| 326 | |
| 291 | 327 | offs_t tms1000_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) |
| 292 | 328 | { |
| 293 | 329 | extern CPU_DISASSEMBLE(tms1000); |
| r242266 | r242267 | |
| 357 | 393 | m_cs = 0; |
| 358 | 394 | m_r = 0; |
| 359 | 395 | m_o = 0; |
| 396 | m_o_latch = 0; |
| 360 | 397 | m_cki_bus = 0; |
| 361 | 398 | m_c4 = 0; |
| 362 | 399 | m_p = 0; |
| r242266 | r242267 | |
| 370 | 407 | m_clatch = 0; |
| 371 | 408 | m_add = 0; |
| 372 | 409 | m_bl = 0; |
| 373 | | |
| 410 | |
| 374 | 411 | m_ram_in = 0; |
| 375 | 412 | m_dam_in = 0; |
| 376 | 413 | m_ram_out = 0; |
| r242266 | r242267 | |
| 381 | 418 | m_micro = 0; |
| 382 | 419 | m_subcycle = 0; |
| 383 | 420 | |
| 421 | m_a_prev = m_a; |
| 422 | m_r_prev = m_r; |
| 423 | m_o_prev = m_o; |
| 424 | |
| 384 | 425 | // register for savestates |
| 385 | 426 | save_item(NAME(m_pc)); |
| 386 | 427 | save_item(NAME(m_sr)); |
| r242266 | r242267 | |
| 394 | 435 | save_item(NAME(m_cs)); |
| 395 | 436 | save_item(NAME(m_r)); |
| 396 | 437 | save_item(NAME(m_o)); |
| 438 | save_item(NAME(m_o_latch)); |
| 397 | 439 | save_item(NAME(m_cki_bus)); |
| 398 | 440 | save_item(NAME(m_c4)); |
| 399 | 441 | save_item(NAME(m_p)); |
| r242266 | r242267 | |
| 418 | 460 | save_item(NAME(m_micro)); |
| 419 | 461 | save_item(NAME(m_subcycle)); |
| 420 | 462 | |
| 463 | save_item(NAME(m_a_prev)); |
| 464 | save_item(NAME(m_r_prev)); |
| 465 | save_item(NAME(m_o_prev)); |
| 466 | |
| 421 | 467 | // register state for debugger |
| 422 | 468 | state_add(TMS0980_PC, "PC", m_pc ).formatstr("%02X"); |
| 423 | 469 | state_add(TMS0980_SR, "SR", m_sr ).formatstr("%01X"); |
| r242266 | r242267 | |
| 570 | 616 | sel = BITSWAP8(sel,7,6,0,1,2,3,4,5); // lines are reversed |
| 571 | 617 | UINT32 mask = m_mpla->read(sel); |
| 572 | 618 | mask ^= 0x43fc3; // invert active-negative |
| 573 | | |
| 619 | |
| 620 | // note: M_RSTR is specific to TMC02x0, it redirects to F_RSTR |
| 574 | 621 | // _______ ______ _____ _____ _____ _____ ______ _____ ______ _____ _____ |
| 575 | | const UINT32 md[20] = { M_NDMTP, M_DMTP, M_AUTY, M_AUTA, M_CKM, M_SSE, M_CKP, M_YTP, M_MTP, M_ATN, M_NATN, M_MTN, M_15TN, M_CKN, M_NE, M_C8, M_SSS, M_CME, M_CIN, M_STO }; |
| 622 | const UINT32 md[21] = { M_NDMTP, M_DMTP, M_AUTY, M_AUTA, M_CKM, M_SSE, M_CKP, M_YTP, M_MTP, M_ATN, M_NATN, M_MTN, M_15TN, M_CKN, M_NE, M_C8, M_SSS, M_CME, M_CIN, M_STO, M_RSTR }; |
| 576 | 623 | |
| 577 | | for (int bit = 0; bit < 20; bit++) |
| 624 | for (int bit = 0; bit < 21 && bit < m_mpla->outputs(); bit++) |
| 578 | 625 | if (mask & (1 << bit)) |
| 579 | 626 | decode |= md[bit]; |
| 580 | 627 | |
| r242266 | r242267 | |
| 619 | 666 | |
| 620 | 667 | |
| 621 | 668 | |
| 669 | //------------------------------------------------- |
| 670 | // program counter/opcode decode |
| 671 | //------------------------------------------------- |
| 622 | 672 | |
| 623 | | |
| 624 | 673 | void tms1xxx_cpu_device::next_pc() |
| 625 | 674 | { |
| 626 | 675 | // The program counter is a LFSR. To put it simply, the feedback bit is a XOR of the two highest bits, |
| r242266 | r242267 | |
| 666 | 715 | next_pc(); |
| 667 | 716 | } |
| 668 | 717 | |
| 718 | void tmc0270_cpu_device::read_opcode() |
| 719 | { |
| 720 | tms0980_cpu_device::read_opcode(); |
| 721 | |
| 722 | // RSTR is on the mpla |
| 723 | if (m_micro & M_RSTR) |
| 724 | m_fixed |= F_RSTR; |
| 725 | } |
| 669 | 726 | |
| 727 | |
| 728 | |
| 729 | //------------------------------------------------- |
| 730 | // i/o handling |
| 731 | //------------------------------------------------- |
| 732 | |
| 670 | 733 | void tms1xxx_cpu_device::write_o_output(UINT8 data) |
| 671 | 734 | { |
| 672 | 735 | // a hardcoded table is supported if the output pla is unknown |
| r242266 | r242267 | |
| 684 | 747 | m_write_o(0, m_o & m_o_mask, 0xffff); |
| 685 | 748 | } |
| 686 | 749 | |
| 750 | |
| 751 | void tmc0270_cpu_device::dynamic_output() |
| 752 | { |
| 753 | // TODO.. |
| 754 | |
| 755 | m_a_prev = m_a; |
| 756 | m_r_prev = m_r; |
| 757 | m_o_prev = m_o; |
| 758 | } |
| 759 | |
| 760 | |
| 687 | 761 | UINT8 tms1xxx_cpu_device::read_k_input() |
| 688 | 762 | { |
| 689 | 763 | // K1,2,4,8,3 (KC test pin is not emulated) |
| r242266 | r242267 | |
| 692 | 766 | return (k & 0xf) | k3; |
| 693 | 767 | } |
| 694 | 768 | |
| 769 | UINT8 tmc0270_cpu_device::read_k_input() |
| 770 | { |
| 771 | // TODO.. |
| 772 | |
| 773 | return tms1xxx_cpu_device::read_k_input(); |
| 774 | } |
| 695 | 775 | |
| 776 | |
| 696 | 777 | void tms1xxx_cpu_device::set_cki_bus() |
| 697 | 778 | { |
| 698 | 779 | switch (m_opcode & 0xf8) |
| r242266 | r242267 | |
| 746 | 827 | } |
| 747 | 828 | |
| 748 | 829 | |
| 749 | | // fixed opcode set |
| 750 | 830 | |
| 831 | //------------------------------------------------- |
| 832 | // fixed opcode set |
| 833 | //------------------------------------------------- |
| 834 | |
| 751 | 835 | // TMS1000/common: |
| 752 | 836 | |
| 753 | 837 | void tms1xxx_cpu_device::op_sbit() |
| r242266 | r242267 | |
| 841 | 925 | } |
| 842 | 926 | |
| 843 | 927 | |
| 844 | | // TMS09x0-specific |
| 928 | // TMS0970-specific (and possibly child classes) |
| 845 | 929 | void tms0970_cpu_device::op_setr() |
| 846 | 930 | { |
| 847 | 931 | // SETR: set output register |
| r242266 | r242267 | |
| 858 | 942 | } |
| 859 | 943 | |
| 860 | 944 | |
| 861 | | // TMS0980-specific |
| 945 | // TMS0980-specific (and possibly child classes) |
| 862 | 946 | void tms0980_cpu_device::op_comx() |
| 863 | 947 | { |
| 864 | 948 | // COMX: complement X register, but not the MSB |
| r242266 | r242267 | |
| 904 | 988 | } |
| 905 | 989 | |
| 906 | 990 | |
| 907 | | void tms1xxx_cpu_device::execute_fixed_opcode() |
| 991 | // TMC0270-specific |
| 992 | void tmc0270_cpu_device::op_tdo() |
| 908 | 993 | { |
| 909 | | switch (m_fixed) |
| 910 | | { |
| 911 | | case F_SBIT: op_sbit(); break; |
| 912 | | case F_RBIT: op_rbit(); break; |
| 913 | | case F_SETR: op_setr(); break; |
| 914 | | case F_RSTR: op_rstr(); break; |
| 915 | | case F_TDO: op_tdo(); break; |
| 916 | | case F_CLO: op_clo(); break; |
| 917 | | case F_LDX: op_ldx(); break; |
| 918 | | case F_COMX: op_comx(); break; |
| 919 | | case F_COMX8:op_comx8();break; |
| 920 | | case F_LDP: op_ldp(); break; |
| 921 | | case F_COMC: op_comc(); break; |
| 922 | | case F_OFF: op_off(); break; |
| 923 | | case F_SEAC: op_seac(); break; |
| 924 | | case F_REAC: op_reac(); break; |
| 925 | | case F_SAL: op_sal(); break; |
| 926 | | case F_SBL: op_sbl(); break; |
| 927 | | case F_XDA: op_xda(); break; |
| 928 | | |
| 929 | | default: |
| 930 | | // BR, CALL, RETN are handled in execute_run |
| 931 | | if (m_fixed & ~(F_BR | F_CALL | F_RETN)) |
| 932 | | fatalerror("%s unsupported fixed opcode %03X %04X!\n", tag(), m_opcode, m_fixed); |
| 933 | | break; |
| 934 | | } |
| 994 | // TDO: transfer data out |
| 995 | if (m_status) |
| 996 | m_o_latch = m_a; |
| 997 | else |
| 998 | m_o = m_o_latch | (m_a << 4 & 0x30); |
| 999 | |
| 1000 | // handled further in dynamic_output |
| 935 | 1001 | } |
| 936 | 1002 | |
| 937 | 1003 | |
| 938 | 1004 | |
| 1005 | //------------------------------------------------- |
| 1006 | // execute_run |
| 1007 | //------------------------------------------------- |
| 1008 | |
| 939 | 1009 | void tms1xxx_cpu_device::execute_run() |
| 940 | 1010 | { |
| 941 | 1011 | do |
| r242266 | r242267 | |
| 995 | 1065 | |
| 996 | 1066 | // execute: k input valid, read ram, clear alu inputs |
| 997 | 1067 | set_cki_bus(); |
| 1068 | dynamic_output(); |
| 998 | 1069 | m_ram_in = m_data->read_byte(m_ram_address) & 0xf; |
| 999 | 1070 | m_dam_in = m_data->read_byte(m_ram_address | (0x10 << (m_x_bits-1))) & 0xf; |
| 1000 | 1071 | m_ram_out = -1; |
| r242266 | r242267 | |
| 1056 | 1127 | if (m_micro & M_STO || (m_micro & M_CME && m_eac == m_add)) |
| 1057 | 1128 | m_ram_out = m_a; |
| 1058 | 1129 | |
| 1059 | | // handle the fixed opcodes here |
| 1060 | | execute_fixed_opcode(); |
| 1130 | // handle the other fixed opcodes here |
| 1131 | if (m_fixed & F_SBIT) op_sbit(); |
| 1132 | if (m_fixed & F_RBIT) op_rbit(); |
| 1133 | if (m_fixed & F_SETR) op_setr(); |
| 1134 | if (m_fixed & F_RSTR) op_rstr(); |
| 1135 | if (m_fixed & F_TDO) op_tdo(); |
| 1136 | if (m_fixed & F_CLO) op_clo(); |
| 1137 | if (m_fixed & F_LDX) op_ldx(); |
| 1138 | if (m_fixed & F_COMX) op_comx(); |
| 1139 | if (m_fixed & F_COMX8) op_comx8(); |
| 1140 | if (m_fixed & F_LDP) op_ldp(); |
| 1141 | if (m_fixed & F_COMC) op_comc(); |
| 1142 | if (m_fixed & F_OFF) op_off(); |
| 1143 | if (m_fixed & F_SEAC) op_seac(); |
| 1144 | if (m_fixed & F_REAC) op_reac(); |
| 1145 | if (m_fixed & F_SAL) op_sal(); |
| 1146 | if (m_fixed & F_SBL) op_sbl(); |
| 1147 | if (m_fixed & F_XDA) op_xda(); |
| 1061 | 1148 | |
| 1062 | 1149 | // execute: write ram |
| 1063 | 1150 | if (m_ram_out != -1) |
trunk/src/emu/cpu/tms0980/tms0980.h
| r242266 | r242267 | |
| 83 | 83 | void state_string_export(const device_state_entry &entry, astring &string); |
| 84 | 84 | |
| 85 | 85 | void next_pc(); |
| 86 | | void execute_fixed_opcode(); |
| 87 | | |
| 86 | |
| 88 | 87 | virtual void write_o_output(UINT8 data); |
| 89 | 88 | virtual UINT8 read_k_input(); |
| 90 | 89 | virtual void set_cki_bus(); |
| 90 | virtual void dynamic_output() { ; } // not used by default |
| 91 | 91 | virtual void read_opcode(); |
| 92 | 92 | |
| 93 | 93 | virtual void op_sbit(); |
| r242266 | r242267 | |
| 122 | 122 | UINT8 m_pa; // 4-bit page address register |
| 123 | 123 | UINT8 m_pb; // 4-bit page buffer register |
| 124 | 124 | UINT8 m_a; // 4-bit accumulator |
| 125 | UINT8 m_a_prev; |
| 125 | 126 | UINT8 m_x; // 2,3,or 4-bit RAM X register |
| 126 | 127 | UINT8 m_y; // 4-bit RAM Y register |
| 127 | 128 | UINT8 m_ca; // chapter address bit |
| 128 | 129 | UINT8 m_cb; // chapter buffer bit |
| 129 | 130 | UINT8 m_cs; // chapter subroutine bit |
| 130 | 131 | UINT16 m_r; |
| 132 | UINT16 m_r_prev; |
| 131 | 133 | UINT16 m_o; |
| 134 | UINT16 m_o_prev; |
| 135 | UINT16 m_o_latch; // TMC0270 hold latch |
| 132 | 136 | UINT8 m_cki_bus; |
| 133 | 137 | UINT8 m_c4; |
| 134 | 138 | UINT8 m_p; // 4-bit adder p(lus)-input |
| r242266 | r242267 | |
| 258 | 262 | { |
| 259 | 263 | public: |
| 260 | 264 | tms0980_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 265 | tms0980_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 k_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source); |
| 261 | 266 | |
| 262 | 267 | protected: |
| 263 | 268 | // overrides |
| r242266 | r242267 | |
| 273 | 278 | virtual void read_opcode(); |
| 274 | 279 | |
| 275 | 280 | virtual void op_comx(); |
| 276 | | private: |
| 281 | |
| 277 | 282 | UINT32 decode_micro(UINT8 sel); |
| 278 | 283 | }; |
| 279 | 284 | |
| 280 | 285 | |
| 286 | class tmc0270_cpu_device : public tms0980_cpu_device |
| 287 | { |
| 288 | public: |
| 289 | tmc0270_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 281 | 290 | |
| 291 | protected: |
| 292 | // overrides |
| 293 | virtual machine_config_constructor device_mconfig_additions() const; |
| 294 | |
| 295 | virtual void write_o_output(UINT8 data) { tms1xxx_cpu_device::write_o_output(data); } |
| 296 | virtual UINT8 read_k_input(); |
| 297 | virtual void dynamic_output(); |
| 298 | virtual void read_opcode(); |
| 299 | |
| 300 | virtual void op_setr() { tms1xxx_cpu_device::op_setr(); } |
| 301 | virtual void op_rstr() { tms1xxx_cpu_device::op_rstr(); } |
| 302 | virtual void op_tdo(); |
| 303 | }; |
| 304 | |
| 305 | |
| 306 | |
| 282 | 307 | extern const device_type TMS1000; |
| 283 | 308 | extern const device_type TMS1070; |
| 284 | 309 | extern const device_type TMS1200; |
| r242266 | r242267 | |
| 286 | 311 | extern const device_type TMS1300; |
| 287 | 312 | extern const device_type TMS0970; |
| 288 | 313 | extern const device_type TMS0980; |
| 314 | extern const device_type TMC0270; |
| 289 | 315 | |
| 290 | 316 | |
| 291 | 317 | #endif /* _TMS0980_H_ */ |