summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/tms32082/tms32082.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/tms32082/tms32082.c')
-rw-r--r--src/devices/cpu/tms32082/tms32082.c597
1 files changed, 597 insertions, 0 deletions
diff --git a/src/devices/cpu/tms32082/tms32082.c b/src/devices/cpu/tms32082/tms32082.c
new file mode 100644
index 00000000000..6ce5a2e2c80
--- /dev/null
+++ b/src/devices/cpu/tms32082/tms32082.c
@@ -0,0 +1,597 @@
+// license:BSD-3-Clause
+// copyright-holders:Ville Linde
+/*
+ Texas Instruments TMS320C82 DSP Emulator
+
+ Written by Ville Linde
+
+*/
+
+#include "emu.h"
+#include "debugger.h"
+#include "tms32082.h"
+
+extern CPU_DISASSEMBLE(tms32082_mp);
+extern CPU_DISASSEMBLE(tms32082_pp);
+
+const device_type TMS32082_MP = &device_creator<tms32082_mp_device>;
+const device_type TMS32082_PP = &device_creator<tms32082_pp_device>;
+
+
+
+
+// Master Processor
+
+// internal memory map
+static ADDRESS_MAP_START(mp_internal_map, AS_PROGRAM, 32, tms32082_mp_device)
+ AM_RANGE(0x00000000, 0x00000fff) AM_RAM AM_SHARE("pp0_data0")
+ AM_RANGE(0x00001000, 0x00001fff) AM_RAM AM_SHARE("pp1_data0")
+ AM_RANGE(0x00008000, 0x00008fff) AM_RAM AM_SHARE("pp0_data1")
+ AM_RANGE(0x00009000, 0x00009fff) AM_RAM AM_SHARE("pp1_data1")
+ AM_RANGE(0x01000000, 0x01000fff) AM_RAM AM_SHARE("pp0_param")
+ AM_RANGE(0x01001000, 0x01001fff) AM_RAM AM_SHARE("pp1_param")
+ AM_RANGE(0x01010000, 0x010107ff) AM_READWRITE(mp_param_r, mp_param_w)
+ADDRESS_MAP_END
+
+const UINT32 tms32082_mp_device::SHIFT_MASK[] =
+{
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
+ 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
+ 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+ 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+ 0xffffffff
+};
+
+
+
+tms32082_mp_device::tms32082_mp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : cpu_device(mconfig, TMS32082_MP, "TMS32082 MP", tag, owner, clock, "tms32082_mp", __FILE__)
+ , m_program_config("program", ENDIANNESS_BIG, 32, 32, 0, ADDRESS_MAP_NAME(mp_internal_map))
+{
+}
+
+
+offs_t tms32082_mp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ return CPU_DISASSEMBLE_NAME(tms32082_mp)(this, buffer, pc, oprom, opram, options);
+}
+
+
+
+READ32_MEMBER(tms32082_mp_device::mp_param_r)
+{
+ //printf("mp_param_w: %08X, %08X\n", offset, mem_mask);
+ return m_param_ram[offset];
+}
+
+WRITE32_MEMBER(tms32082_mp_device::mp_param_w)
+{
+ //printf("mp_param_w: %08X, %08X, %08X\n", offset, data, mem_mask);
+
+ COMBINE_DATA(&m_param_ram[offset]);
+
+ if (offset == 0x3f)
+ {
+ // initiate Transfer Controller operation
+ // TODO: move TC functionality to separate device
+ UINT32 address = data;
+
+ UINT32 next_entry = m_program->read_dword(address + 0);
+ UINT32 pt_options = m_program->read_dword(address + 4);
+ UINT32 src_addr = m_program->read_dword(address + 8);
+ UINT32 dst_addr = m_program->read_dword(address + 12);
+ UINT32 src_b_count = m_program->read_word(address + 16);
+ UINT32 src_a_count = m_program->read_word(address + 18);
+ UINT32 dst_b_count = m_program->read_word(address + 20);
+ UINT32 dst_a_count = m_program->read_word(address + 22);
+ UINT32 src_c_count = m_program->read_dword(address + 24);
+ UINT32 dst_c_count = m_program->read_dword(address + 28);
+ UINT32 src_b_pitch = m_program->read_dword(address + 32);
+ UINT32 dst_b_pitch = m_program->read_dword(address + 36);
+ UINT32 src_c_pitch = m_program->read_dword(address + 40);
+ UINT32 dst_c_pitch = m_program->read_dword(address + 44);
+
+ printf("TC operation:\n");
+ printf(" Next entry: %08X\n", next_entry);
+ printf(" PT options: %08X\n", pt_options);
+ printf(" SRC addr: %08X\n", src_addr);
+ printf(" DST addr: %08X\n", dst_addr);
+ printf(" SRC count A: %04X, B: %04X\n", src_a_count, src_b_count);
+ printf(" DST count A: %04X, B: %04X\n", dst_a_count, dst_b_count);
+ printf(" SRC count C: %08X\n", src_c_count);
+ printf(" DST count C: %08X\n", dst_c_count);
+ printf(" SRC B pitch: %08X\n", src_b_pitch);
+ printf(" DST B pitch: %08X\n", dst_b_pitch);
+ printf(" SRC C pitch: %08X\n", src_c_pitch);
+ printf(" DST C pitch: %08X\n", dst_c_pitch);
+
+ if (pt_options != 0x80000000)
+ fatalerror("TC transfer, options = %08X\n", pt_options);
+
+ for (int ic = 0; ic <= src_c_count; ic++)
+ {
+ UINT32 c_src_offset = ic * src_c_pitch;
+ UINT32 c_dst_offset = ic * dst_c_pitch;
+
+ for (int ib = 0; ib <= src_b_count; ib++)
+ {
+ UINT32 b_src_offset = ib * src_b_pitch;
+ UINT32 b_dst_offset = ib * dst_b_pitch;
+
+ for (int ia = 0; ia < src_a_count; ia++)
+ {
+ UINT32 src = src_addr + c_src_offset + b_src_offset + ia;
+ UINT32 dst = dst_addr + c_dst_offset + b_dst_offset + ia;
+
+ UINT32 data = m_program->read_byte(src);
+ m_program->write_byte(dst, data);
+
+ //printf("%08X: %02X -> %08X\n", src, data, dst);
+ }
+ }
+ }
+ }
+}
+
+
+
+void tms32082_mp_device::device_start()
+{
+ m_program = &space(AS_PROGRAM);
+
+ save_item(NAME(m_pc));
+ save_item(NAME(m_fetchpc));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_acc));
+
+ save_item(NAME(m_in0p));
+ save_item(NAME(m_in1p));
+ save_item(NAME(m_outp));
+ save_item(NAME(m_ie));
+ save_item(NAME(m_intpen));
+
+ // Register state for debugger
+ state_add(MP_PC, "pc", m_pc).formatstr("%08X");
+
+ state_add(MP_R0, "r0", m_reg[0]).formatstr("%08X");
+ state_add(MP_R1, "r1", m_reg[1]).formatstr("%08X");
+ state_add(MP_R2, "r2", m_reg[2]).formatstr("%08X");
+ state_add(MP_R3, "r3", m_reg[3]).formatstr("%08X");
+ state_add(MP_R4, "r4", m_reg[4]).formatstr("%08X");
+ state_add(MP_R5, "r5", m_reg[5]).formatstr("%08X");
+ state_add(MP_R6, "r6", m_reg[6]).formatstr("%08X");
+ state_add(MP_R7, "r7", m_reg[7]).formatstr("%08X");
+ state_add(MP_R8, "r8", m_reg[8]).formatstr("%08X");
+ state_add(MP_R9, "r9", m_reg[9]).formatstr("%08X");
+ state_add(MP_R10, "r10", m_reg[10]).formatstr("%08X");
+ state_add(MP_R11, "r11", m_reg[11]).formatstr("%08X");
+ state_add(MP_R12, "r12", m_reg[12]).formatstr("%08X");
+ state_add(MP_R13, "r13", m_reg[13]).formatstr("%08X");
+ state_add(MP_R14, "r14", m_reg[14]).formatstr("%08X");
+ state_add(MP_R15, "r15", m_reg[15]).formatstr("%08X");
+ state_add(MP_R16, "r16", m_reg[16]).formatstr("%08X");
+ state_add(MP_R17, "r17", m_reg[17]).formatstr("%08X");
+ state_add(MP_R18, "r18", m_reg[18]).formatstr("%08X");
+ state_add(MP_R19, "r19", m_reg[19]).formatstr("%08X");
+ state_add(MP_R20, "r20", m_reg[20]).formatstr("%08X");
+ state_add(MP_R21, "r21", m_reg[21]).formatstr("%08X");
+ state_add(MP_R22, "r22", m_reg[22]).formatstr("%08X");
+ state_add(MP_R23, "r23", m_reg[23]).formatstr("%08X");
+ state_add(MP_R24, "r24", m_reg[24]).formatstr("%08X");
+ state_add(MP_R25, "r25", m_reg[25]).formatstr("%08X");
+ state_add(MP_R26, "r26", m_reg[26]).formatstr("%08X");
+ state_add(MP_R27, "r27", m_reg[27]).formatstr("%08X");
+ state_add(MP_R28, "r28", m_reg[28]).formatstr("%08X");
+ state_add(MP_R29, "r29", m_reg[29]).formatstr("%08X");
+ state_add(MP_R30, "r30", m_reg[30]).formatstr("%08X");
+ state_add(MP_R31, "r31", m_reg[31]).formatstr("%08X");
+
+ state_add(MP_ACC0, "acc0", m_acc[0]).formatstr("%016X");
+ state_add(MP_ACC1, "acc1", m_acc[1]).formatstr("%016X");
+ state_add(MP_ACC2, "acc2", m_acc[2]).formatstr("%016X");
+ state_add(MP_ACC3, "acc3", m_acc[3]).formatstr("%016X");
+
+ state_add(MP_IN0P, "in0p", m_in0p).formatstr("%08X");
+ state_add(MP_IN1P, "in1p", m_in1p).formatstr("%08X");
+ state_add(MP_OUTP, "outp", m_outp).formatstr("%08X");
+ state_add(MP_IE, "ie", m_ie).formatstr("%08X");
+ state_add(MP_INTPEN, "intpen", m_intpen).formatstr("%08X");
+
+ state_add(MP_TCOUNT, "tcount", m_tcount).formatstr("%08X");
+ state_add(MP_TSCALE, "tscale", m_tscale).formatstr("%08X");
+
+ state_add(STATE_GENPC, "curpc", m_pc).noshow();
+
+ m_program = &space(AS_PROGRAM);
+ m_direct = &m_program->direct();
+
+ m_icountptr = &m_icount;
+}
+
+void tms32082_mp_device::state_string_export(const device_state_entry &entry, std::string &str)
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ strprintf(str, "?");
+ break;
+ }
+}
+
+void tms32082_mp_device::device_reset()
+{
+ m_pc = 0;
+ m_fetchpc = 0xfffffff8;
+
+ for (int i=0; i < 32; i++)
+ {
+ m_reg[i] = 0;
+ }
+
+ m_acc[0] = 0;
+ m_acc[1] = 0;
+ m_acc[2] = 0;
+ m_acc[3] = 0;
+
+ m_in0p = 0;
+ m_in1p = 0;
+ m_outp = 0;
+
+ m_intpen = 0;
+ m_ie = 0;
+}
+
+void tms32082_mp_device::processor_command(UINT32 command)
+{
+ printf("MP CMND %08X: ", command);
+
+ if (command & 0x80000000)
+ printf("Reset ");
+ if (command & 0x40000000)
+ printf("Halt ");
+ if (command & 0x20000000)
+ printf("Unhalt ");
+ if (command & 0x10000000)
+ printf("ICR ");
+ if (command & 0x08000000)
+ printf("DCR ");
+ if (command & 0x00004000)
+ printf("Task ");
+ if (command & 0x00002000)
+ printf("Msg ");
+
+ printf("to: ");
+
+ if (command & 0x00000400)
+ printf("VC ");
+ if (command & 0x00000200)
+ printf("TC ");
+ if (command & 0x00000100)
+ printf("MP ");
+ if (command & 0x00000008)
+ printf("PP3 ");
+ if (command & 0x00000004)
+ printf("PP2 ");
+ if (command & 0x00000002)
+ printf("PP1 ");
+ if (command & 0x00000001)
+ printf("PP0 ");
+
+ printf("\n");
+
+ // PP0
+ if (command & 1)
+ {
+ if (command & 0x00004000)
+ {
+ // simulate PP behavior for now...
+ m_program->write_dword(0x00000084, 3);
+
+ UINT32 num = m_program->read_dword(0x90);
+
+ printf("PP num %d\n", num);
+
+ /*
+ UINT32 ra = 0x1000280;
+
+ printf("FIFO push:\n");
+
+ for (int i=0; i < num; i++)
+ {
+ printf("Entry %d:\n", i);
+ for (int k=0; k < 6; k++)
+ {
+ for (int l=0; l < 4; l++)
+ {
+ UINT32 dd = m_program->read_dword(ra);
+ ra += 4;
+
+ printf("%08X(%f) ", dd, u2f(dd));
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+ */
+
+ UINT32 ra = 0x1000280;
+
+ int oldnum = m_program->read_dword(0x600ffffc);
+ UINT32 rb = 0x60000000 + (oldnum * 0x60);
+
+ for (int i=0; i < num; i++)
+ {
+ for (int k=0; k < 24; k++)
+ {
+ UINT32 dd = m_program->read_dword(ra);
+ ra += 4;
+
+ m_program->write_dword(rb, dd);
+ rb += 4;
+ }
+ }
+ m_program->write_dword(0x600ffffc, oldnum+num);
+
+ m_program->write_dword(0x00000090, 0);
+ m_program->write_dword(0x00000094, num);
+
+ }
+ }
+ // PP1
+ if (command & 2)
+ {
+ if (command & 0x00004000)
+ {
+ // simulate PP behavior for now...
+ m_program->write_dword(0x00001014, 3);
+ }
+ }
+}
+
+UINT32 tms32082_mp_device::read_creg(int reg)
+{
+ switch (reg)
+ {
+ case 0x0: // EPC
+ return m_epc;
+
+ case 0x1: // EIP
+ return m_eip;
+
+ case 0x4: // INTPEN
+ return m_intpen;
+
+ case 0x6: // IE
+ return m_ie;
+
+ case 0xa: // PPERROR
+ return 0xe0000;
+
+ case 0xe: // TCOUNT
+ return m_tcount;
+
+ case 0x4000: // IN0P
+ return m_in0p;
+
+ case 0x4001: // IN1P
+ return m_in1p;
+
+ case 0x4002: // OUTP
+ return m_outp;
+
+ default:
+ printf("read_creg(): %08X\n", reg);
+ break;
+ }
+ return 0;
+}
+
+void tms32082_mp_device::write_creg(int reg, UINT32 data)
+{
+ switch (reg)
+ {
+ case 0x0: // EPC
+ m_epc = data;
+ break;
+
+ case 0x1: // EIP
+ m_eip = data;
+ break;
+
+ case 0x4: // INTPEN
+ {
+ for (int i=0; i < 32; i++)
+ {
+ if (data & (1 << i))
+ m_intpen &= ~(1 << i);
+ }
+ break;
+ }
+
+ case 0x6: // IE
+ m_ie = data;
+ printf("IE = %08X\n", data);
+ break;
+
+ case 0xe: // TCOUNT
+ m_tcount = data;
+ break;
+
+ case 0x4000: // IN0P
+ m_in0p = data;
+ break;
+
+ case 0x4001: // IN1P
+ m_in1p = data;
+ break;
+
+ case 0x4002: // OUTP
+ m_outp = data;
+ break;
+
+ default:
+ printf("write_creg(): %08X, %08X\n", reg, data);
+ break;
+ }
+}
+
+void tms32082_mp_device::check_interrupts()
+{
+ if (m_ie & 1) // global interrupt mask
+ {
+ for (int i=1; i < 32; i++)
+ {
+ if (m_ie & m_intpen & (1 << i))
+ {
+ m_epc = (m_fetchpc & ~3);
+ m_epc |= (m_ie & 1); // save global interrupt mask
+ // TODO: user mode bit to EPC
+
+ m_eip = m_pc;
+
+ m_ie &= ~1; // clear global interrupt mask
+
+ // get new pc from vector table
+ m_fetchpc = m_pc = m_program->read_dword(0x01010180 + (i * 4));
+ return;
+ }
+ }
+ }
+}
+
+void tms32082_mp_device::execute_set_input(int inputnum, int state)
+{
+ if (state == ASSERT_LINE)
+ {
+ switch (inputnum)
+ {
+ case INPUT_X1:
+ m_intpen |= (1 << 11);
+ break;
+ case INPUT_X2:
+ m_intpen |= (1 << 12);
+ break;
+ case INPUT_X3:
+ m_intpen |= (1 << 29);
+ break;
+ case INPUT_X4:
+ m_intpen |= (1 << 30);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+UINT32 tms32082_mp_device::fetch()
+{
+ UINT32 w = m_direct->read_dword(m_fetchpc);
+ m_fetchpc += 4;
+ return w;
+}
+
+void tms32082_mp_device::delay_slot()
+{
+ debugger_instruction_hook(this, m_pc);
+ m_ir = fetch();
+ execute();
+
+ m_icount--;
+}
+
+void tms32082_mp_device::execute_run()
+{
+ while (m_icount > 0)
+ {
+ m_pc = m_fetchpc;
+
+ check_interrupts();
+
+ debugger_instruction_hook(this, m_pc);
+
+ m_ir = fetch();
+ execute();
+
+ m_tcount--;
+ if (m_tcount < 0)
+ {
+ // TODO: timer interrupt
+ m_tcount = m_tscale;
+ }
+
+ m_icount--;
+ };
+
+ return;
+}
+
+
+
+
+// Parallel Processor
+
+// internal memory map
+static ADDRESS_MAP_START(pp_internal_map, AS_PROGRAM, 32, tms32082_pp_device)
+ AM_RANGE(0x00000000, 0x00000fff) AM_RAM AM_SHARE("pp0_data0")
+ AM_RANGE(0x00001000, 0x00001fff) AM_RAM AM_SHARE("pp1_data0")
+ AM_RANGE(0x00008000, 0x00008fff) AM_RAM AM_SHARE("pp0_data1")
+ AM_RANGE(0x00009000, 0x00009fff) AM_RAM AM_SHARE("pp1_data1")
+ AM_RANGE(0x01000000, 0x01000fff) AM_RAM AM_SHARE("pp0_param")
+ AM_RANGE(0x01001000, 0x01001fff) AM_RAM AM_SHARE("pp1_param")
+ADDRESS_MAP_END
+
+tms32082_pp_device::tms32082_pp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : cpu_device(mconfig, TMS32082_PP, "TMS32082 PP", tag, owner, clock, "tms32082_pp", __FILE__)
+ , m_program_config("program", ENDIANNESS_BIG, 32, 32, 0, ADDRESS_MAP_NAME(pp_internal_map))
+{
+}
+
+
+offs_t tms32082_pp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ return CPU_DISASSEMBLE_NAME(tms32082_pp)(this, buffer, pc, oprom, opram, options);
+}
+
+void tms32082_pp_device::device_start()
+{
+ m_program = &space(AS_PROGRAM);
+
+ save_item(NAME(m_pc));
+ save_item(NAME(m_fetchpc));
+
+ // Register state for debugger
+ state_add(PP_PC, "pc", m_pc).formatstr("%08X");
+
+ state_add(STATE_GENPC, "curpc", m_pc).noshow();
+
+ m_program = &space(AS_PROGRAM);
+ m_direct = &m_program->direct();
+
+ m_icountptr = &m_icount;
+}
+
+void tms32082_pp_device::state_string_export(const device_state_entry &entry, std::string &str)
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ strprintf(str, "?");
+ break;
+ }
+}
+
+void tms32082_pp_device::device_reset()
+{
+ m_pc = 0;
+ m_fetchpc = 0x400010a0;
+}
+
+void tms32082_pp_device::execute_run()
+{
+ m_pc = m_fetchpc;
+ debugger_instruction_hook(this, m_pc);
+
+ m_icount = 0;
+
+ return;
+}