From deb38446ea9d79dfa07ad390047daaff447edfeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Corr=C3=AAa=20da=20Silva=20Sanches?= Date: Sun, 22 May 2016 20:48:12 -0300 Subject: [PATCH] Further improvements to the Patinho Feio driver & CPU --- scripts/src/cpu.lua | 2 +- scripts/target/mame/mess.lua | 1 + src/devices/cpu/patinhofeio/patinho_feio.cpp | 386 ++++++++++++++---- src/devices/cpu/patinhofeio/patinho_feio.h | 107 ----- .../cpu/patinhofeio/patinho_feio_dasm.cpp | 8 +- src/devices/cpu/patinhofeio/patinhofeio_cpu.h | 144 +++++++ src/mame/drivers/patinho_feio.cpp | 275 +++++++++++-- src/mame/includes/patinhofeio.h | 50 +++ 8 files changed, 755 insertions(+), 218 deletions(-) delete mode 100644 src/devices/cpu/patinhofeio/patinho_feio.h create mode 100644 src/devices/cpu/patinhofeio/patinhofeio_cpu.h create mode 100644 src/mame/includes/patinhofeio.h diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index bb630af1e5c..1b746fb59bc 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -1452,7 +1452,7 @@ end if (CPUS["PATINHOFEIO"]~=null) then files { MAME_DIR .. "src/devices/cpu/patinhofeio/patinho_feio.cpp", - MAME_DIR .. "src/devices/cpu/patinhofeio/patinho_feio.h", + MAME_DIR .. "src/devices/cpu/patinhofeio/patinhofeio_cpu.h", } end diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 13898021fd6..415a39f1897 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -2894,6 +2894,7 @@ files { createMESSProjects(_target, _subtarget, "usp") files { MAME_DIR .. "src/mame/drivers/patinho_feio.cpp", + MAME_DIR .. "src/mame/includes/patinho_feio.h", } createMESSProjects(_target, _subtarget, "veb") diff --git a/src/devices/cpu/patinhofeio/patinho_feio.cpp b/src/devices/cpu/patinhofeio/patinho_feio.cpp index 78fc92a8270..8482db59c41 100644 --- a/src/devices/cpu/patinhofeio/patinho_feio.cpp +++ b/src/devices/cpu/patinhofeio/patinho_feio.cpp @@ -1,15 +1,17 @@ // license:GPL-2.0+ // copyright-holders:Felipe Sanches /* - CPU emulation for Patinho Feio, the first computer designed and manufactured in Brazil + CPU emulation for Patinho Feio, the first computer designed and manufactured in Brazil */ #include "emu.h" #include "debugger.h" -#include "patinho_feio.h" +#include "patinhofeio_cpu.h" +#include "includes/patinhofeio.h" -#define PC m_pc //The program counter is called "contador de instrucoes" in portuguese +#define PC m_pc //The program counter is called "contador de instrucoes" (IC) in portuguese #define ACC m_acc +#define EXT m_ext #define RC read_panel_keys_register() #define FLAGS m_flags @@ -24,23 +26,31 @@ #define READ_INDEX_REG() READ_BYTE_PATINHO(0x000) #define WRITE_INDEX_REG(V) { WRITE_BYTE_PATINHO(0x000, V); m_idx = V; } +#define READ_ACC_EXTENSION_REG() READ_BYTE_PATINHO(0x001) +#define WRITE_ACC_EXTENSION_REG(V) { WRITE_BYTE_PATINHO(0x001, V); m_ext = V; } + #define ADDRESS_MASK_4K 0xFFF #define INCREMENT_PC_4K (PC = (PC+1) & ADDRESS_MASK_4K) -unsigned int patinho_feio_cpu_device::compute_effective_address(unsigned int addr){ - unsigned int retval = addr; - if (m_indirect_addressing){ - retval = READ_WORD_PATINHO(addr); - if (retval & 0x1000) - return compute_effective_address(retval & 0xFFF); +void patinho_feio_cpu_device::set_flag(UINT8 flag, bool state){ + if (state){ + FLAGS |= flag; + } else { + FLAGS &= ~flag; } +} - return retval; +void patinho_feio_cpu_device::compute_effective_address(unsigned int addr){ + m_addr = addr; + if (m_indirect_addressing){ + m_addr = READ_WORD_PATINHO(m_addr); + if (m_addr & 0x1000) + compute_effective_address(m_addr & 0xFFF); + } } const device_type PATINHO_FEIO = &device_creator; - //Internal 4kbytes of RAM static ADDRESS_MAP_START(prog_8bit, AS_PROGRAM, 8, patinho_feio_cpu_device) AM_RANGE(0x0000, 0x0fff) AM_RAM AM_SHARE("internalram") @@ -50,7 +60,12 @@ patinho_feio_cpu_device::patinho_feio_cpu_device(const machine_config &mconfig, : cpu_device(mconfig, PATINHO_FEIO, "PATINHO FEIO", tag, owner, clock, "patinho_feio_cpu", __FILE__), m_program_config("program", ENDIANNESS_LITTLE, 8, 12, 0, ADDRESS_MAP_NAME(prog_8bit)), m_icount(0), - m_rc_read_cb(*this) + m_rc_read_cb(*this), + m_buttons_read_cb(*this), + /* These arrays of *this are very ugly. I wonder if there's a better way of coding this... */ + m_iodev_read_cb{*this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this}, + m_iodev_write_cb{*this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this}, + m_iodev_status_cb{*this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this} { } @@ -63,20 +78,43 @@ UINT16 patinho_feio_cpu_device::read_panel_keys_register(){ return m_rc; } +void patinho_feio_cpu_device::transfer_byte_from_external_device(UINT8 channel, UINT8 data){ + m_iodev_incoming_byte[channel] = data; + m_iodev_status[channel] = IODEV_READY; + m_iodev_control[channel] = NO_REQUEST; +} + void patinho_feio_cpu_device::device_start() { m_program = &space(AS_PROGRAM); +//TODO: implement handling of these special purpose registers +// which are also mapped to the first few main memory positions: +// +// ERI: "Endereço de Retorno de Interrupção" +// "Interrupt Return Address" +// stored at addresses 002 and 003 +// +// ETI: "início de uma rotina de tratamento de interrupção (se houver)" +// "start of an interrupt service routine (if any)" +// stored at address 004 (and 005 as well?) +// +// It seems that the general purpose memory starts at address 006. + save_item(NAME(m_pc)); save_item(NAME(m_acc)); + save_item(NAME(m_ext)); save_item(NAME(m_rc)); save_item(NAME(m_idx)); save_item(NAME(m_flags)); + save_item(NAME(m_addr)); + save_item(NAME(m_opcode)); // Register state for debugger state_add( PATINHO_FEIO_CI, "CI", m_pc ).mask(0xFFF); state_add( PATINHO_FEIO_RC, "RC", m_rc ).mask(0xFFF); state_add( PATINHO_FEIO_ACC, "ACC", m_acc ).mask(0xFF); + state_add( PATINHO_FEIO_EXT, "EXT", m_ext ).mask(0xFF); state_add( PATINHO_FEIO_IDX, "IDX", m_idx ).mask(0xFF); state_add(STATE_GENPC, "GENPC", m_pc).formatstr("0%06O").noshow(); state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).noshow().formatstr("%8s"); @@ -87,32 +125,72 @@ void patinho_feio_cpu_device::device_start() m_rc_read_cb.resolve(); } + if (!m_buttons_read_cb.isnull()){ + m_buttons_read_cb.resolve(); + } + + for (int i=0; i<16; i++){ + if (!m_iodev_read_cb[i].isnull()) + m_iodev_read_cb[i].resolve(); + if (!m_iodev_write_cb[i].isnull()) + m_iodev_write_cb[i].resolve(); + } + m_icountptr = &m_icount; } void patinho_feio_cpu_device::device_reset() { - m_pc = 0x006; - m_acc = 0; + m_pc = 0; + //m_pc = 0x006; //"PATINHO FEIO" hello-world + //m_pc = 0x010; //micro-pre-loader + //m_pc = 0xE00; //HEXAM m_rc = 0; + m_acc = 0; + m_ext = READ_ACC_EXTENSION_REG(); m_idx = READ_INDEX_REG(); m_flags = 0; - m_run = true; + m_run = false; m_scheduled_IND_bit_reset = false; m_indirect_addressing = false; + m_addr = 0; + m_opcode = 0; + m_mode = ADDRESSING_MODE; + ((patinho_feio_state*) owner())->update_panel(ACC, m_opcode, READ_BYTE_PATINHO(m_addr), m_addr, PC, FLAGS, RC, m_mode); } /* execute instructions on this CPU until icount expires */ -void patinho_feio_cpu_device::execute_run() -{ - do - { - if ((! m_run)){ +void patinho_feio_cpu_device::execute_run() { + do { + read_panel_keys_register(); + m_ext = READ_ACC_EXTENSION_REG(); + m_idx = READ_INDEX_REG(); + ((patinho_feio_state*) owner())->update_panel(ACC, READ_BYTE_PATINHO(PC), READ_BYTE_PATINHO(m_addr), m_addr, PC, FLAGS, RC, m_mode); + debugger_instruction_hook(this, PC); + + if (!m_run){ + if (!m_buttons_read_cb.isnull()){ + UINT16 buttons = m_buttons_read_cb(0); + if (buttons & BUTTON_PARTIDA){ + /* "startup" button */ + switch (m_mode){ + case ADDRESSING_MODE: PC = RC; break; + case NORMAL_MODE: m_run = true; break; + case DATA_STORE_MODE: WRITE_BYTE_PATINHO(PC, RC & 0xFF); break; //TODO: we also need RE (address register, instead of using PC directly) + /*TODO: case DATA_VIEW_MODE: RD = READ_BYTE_PATINHO(RC); break; //we need to implement RD (the 'data register') */ + default: break; + } + } + if (buttons & BUTTON_NORMAL) m_mode = NORMAL_MODE; + if (buttons & BUTTON_ENDERECAMENTO) m_mode = ADDRESSING_MODE; + if (buttons & BUTTON_EXPOSICAO) m_mode = DATA_VIEW_MODE; + if (buttons & BUTTON_ARMAZENAMENTO) m_mode = DATA_STORE_MODE; + if (buttons & BUTTON_CICLO_UNICO) m_mode = CYCLE_STEP_MODE; + if (buttons & BUTTON_INSTRUCAO_UNICA) m_mode = INSTRUCTION_STEP_MODE; + if (buttons & BUTTON_PREPARACAO) device_reset(); + } m_icount = 0; /* if processor is stopped, just burn cycles */ } else { - m_idx = READ_INDEX_REG(); - read_panel_keys_register(); - execute_instruction(); m_icount --; } @@ -123,12 +201,10 @@ void patinho_feio_cpu_device::execute_run() /* execute one instruction */ void patinho_feio_cpu_device::execute_instruction() { - debugger_instruction_hook(this, PC); - offs_t addr; bool skip; unsigned int tmp; unsigned char value, channel, function; - unsigned char opcode = READ_BYTE_PATINHO(PC); + m_opcode = READ_BYTE_PATINHO(PC); INCREMENT_PC_4K; if (m_scheduled_IND_bit_reset) @@ -137,7 +213,7 @@ void patinho_feio_cpu_device::execute_instruction() if (m_indirect_addressing) m_scheduled_IND_bit_reset = true; - switch (opcode){ + switch (m_opcode){ case 0xD2: //XOR: Computes the bitwise XOR of an immediate into the accumulator ACC ^= READ_BYTE_PATINHO(PC); @@ -153,9 +229,10 @@ void patinho_feio_cpu_device::execute_instruction() case 0xD8: //SOMI="Soma Imediato": // Add an immediate into the accumulator + set_flag(V, ((((INT16) ACC) + ((INT16) READ_BYTE_PATINHO(PC))) >> 8)); + set_flag(T, ((((INT8) (ACC & 0x7F)) + ((INT8) (READ_BYTE_PATINHO(PC) & 0x7F))) >> 7) == V); ACC += READ_BYTE_PATINHO(PC); INCREMENT_PC_4K; - //TODO: update T and V flags return; case 0xDA: //CARI="Carrega Imediato": @@ -253,6 +330,79 @@ void patinho_feio_cpu_device::execute_instruction() ACC = (RC & 0xFF); FLAGS = V; return; + case 0x90: + //ST 0 = "Se T=0, Pula" + // If T is zero, skip the next instruction + if ((FLAGS & T) == 0) + INCREMENT_PC_4K; //skip + return; + case 0x91: + //STM 0 = "Se T=0, Pula e muda" + // If T is zero, skip the next instruction + // and toggle T. + if ((FLAGS & T) == 0){ + INCREMENT_PC_4K; //skip + FLAGS |= T; //set T=1 + } + return; + case 0x92: + //ST 1 = "Se T=1, Pula" + // If T is one, skip the next instruction + if ((FLAGS & T) == 1) + INCREMENT_PC_4K; //skip + return; + case 0x93: + //STM 1 = "Se T=1, Pula e muda" + // If T is one, skip the next instruction + // and toggle T. + if ((FLAGS & T) == 1){ + INCREMENT_PC_4K; //skip + FLAGS &= ~T; //set T=0 + } + return; + case 0x94: + //SV 0 = "Se V=0, Pula" + // If V is zero, skip the next instruction + if ((FLAGS & V) == 0) + INCREMENT_PC_4K; //skip + return; + case 0x95: + //SVM 0 = "Se V=0, Pula e muda" + // If V is zero, skip the next instruction + // and toggle V. + if ((FLAGS & V) == 0){ + INCREMENT_PC_4K; //skip + FLAGS |= V; //set V=1 + } + return; + case 0x96: + //SV 1 = "Se V=1, Pula" + // If V is one, skip the next instruction + if ((FLAGS & V) == 1) + INCREMENT_PC_4K; //skip + return; + case 0x97: + //SVM 1 = "Se V=1, Pula e muda" + // If V is one, skip the next instruction + // and toggle V. + if ((FLAGS & V) == 1){ + INCREMENT_PC_4K; //skip + FLAGS &= ~V; //set V=0 + } + return; + case 0x98: + //PUL="Pula para /002 a limpa estado de interrupção" + // Jump to address /002 and disables interrupts + PC = 0x002; + m_interrupts_enabled = false; + return; + case 0x99: + //TRE="Troca conteúdos de ACC e EXT" + // Exchange the value of the accumulator with the ACC extension register + value = ACC; + ACC = READ_ACC_EXTENSION_REG(); + WRITE_ACC_EXTENSION_REG(value); + return; case 0x9A: //INIB="Inibe" // disables interrupts @@ -377,7 +527,7 @@ void patinho_feio_cpu_device::execute_instruction() ACC = (ACC & (1 << 7)) | ACC >> 1; break; default: - printf("Illegal instruction: %02X %02X\n", opcode, value); + printf("Illegal instruction: %02X %02X\n", m_opcode, value); return; } } @@ -385,105 +535,194 @@ void patinho_feio_cpu_device::execute_instruction() return; } - switch (opcode & 0xF0){ + switch (m_opcode & 0xF0){ case 0x00: //PLA = "Pula": Jump to address - addr = compute_effective_address((opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); + compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); INCREMENT_PC_4K; - PC = addr; + PC = m_addr; return; case 0x10: //PLAX = "Pula indexado": Jump to indexed address - tmp = (opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC); + tmp = (m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC); INCREMENT_PC_4K; m_idx = READ_INDEX_REG(); - PC = compute_effective_address(m_idx + tmp); + compute_effective_address(m_idx + tmp); + PC = m_addr; return; case 0x20: //ARM = "Armazena": Store the value of the accumulator into a given memory position - addr = compute_effective_address((opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); + compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); INCREMENT_PC_4K; - WRITE_BYTE_PATINHO(addr, ACC); + WRITE_BYTE_PATINHO(m_addr, ACC); return; case 0x30: //ARMX = "Armazena indexado": Store the value of the accumulator into a given indexed memory position - tmp = (opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC); + tmp = (m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC); INCREMENT_PC_4K; m_idx = READ_INDEX_REG(); - addr = compute_effective_address(m_idx + tmp); - WRITE_BYTE_PATINHO(addr, ACC); + compute_effective_address(m_idx + tmp); + WRITE_BYTE_PATINHO(m_addr, ACC); return; case 0x40: //CAR = "Carrega": Load a value from a given memory position into the accumulator - addr = compute_effective_address((opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); + compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); INCREMENT_PC_4K; - ACC = READ_BYTE_PATINHO(addr); + ACC = READ_BYTE_PATINHO(m_addr); return; case 0x50: //CARX = "Carga indexada": Load a value from a given indexed memory position into the accumulator - tmp = (opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC); + tmp = (m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC); INCREMENT_PC_4K; m_idx = READ_INDEX_REG(); - addr = compute_effective_address(m_idx + tmp); - ACC = READ_BYTE_PATINHO(addr); + compute_effective_address(m_idx + tmp); + ACC = READ_BYTE_PATINHO(m_addr); return; case 0x60: //SOM = "Soma": Add a value from a given memory position into the accumulator - addr = compute_effective_address((opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); + compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); INCREMENT_PC_4K; - ACC += READ_BYTE_PATINHO(addr); + ACC += READ_BYTE_PATINHO(m_addr); //TODO: update V and T flags return; case 0x70: //SOMX = "Soma indexada": Add a value from a given indexed memory position into the accumulator - tmp = (opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC); + tmp = (m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC); INCREMENT_PC_4K; m_idx = READ_INDEX_REG(); - addr = compute_effective_address(m_idx + tmp); - ACC += READ_BYTE_PATINHO(addr); + compute_effective_address(m_idx + tmp); + ACC += READ_BYTE_PATINHO(m_addr); //TODO: update V and T flags return; case 0xA0: //PLAN = "Pula se ACC negativo": Jump to a given address if ACC is negative - addr = compute_effective_address((opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); + compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); INCREMENT_PC_4K; if ((signed char) ACC < 0) - PC = addr; + PC = m_addr; return; case 0xB0: //PLAZ = "Pula se ACC for zero": Jump to a given address if ACC is zero - addr = compute_effective_address((opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); + compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); INCREMENT_PC_4K; if (ACC == 0) - PC = addr; + PC = m_addr; return; case 0xC0: //Executes I/O functions //TODO: Implement-me! value = READ_BYTE_PATINHO(PC); INCREMENT_PC_4K; - channel = opcode & 0x0F; + channel = m_opcode & 0x0F; function = value & 0x0F; switch(value & 0xF0){ case 0x10: - printf("Unimplemented FNC /%X%X instruction\n", channel, function); + switch(function) + { + case 0: + // FNC /n0: Desliga flip-flop PERMITE/IMPEDE para + // o dispositivo n (isto é, impede inter- + // -rupcao do dispositivo n). + // + // Turns off the interrupt ENABLE/DISABLE + // flip-flop for channel n. + //TODO: Implement-me! + break; + case 1: + // FNC /n1: Desliga flip-flop de ESTADO do dispo- + // -sitivo n ( ESTADO = "busy" ). + // + // Turns off STATUS flip-flop for + // channel n ( STATUS = "busy" ). + m_iodev_status[channel] = IODEV_BUSY; + break; + case 2: + // FNC /n2: Liga flip-flop de ESTADO do dispo- + // -sitivo n ( ESTADO = "ready" ). + // + // Turns on STATUS flip-flop for + // channel n ( STATUS = "ready" ). + m_iodev_status[channel] = IODEV_READY; + break; + case 4: + // FNC /n4: Desliga flip-flop de PEDIDO de inter- + // rupcao do dispositivo n. + // + // Turns off the interrupt REQUEST + // flip-flop for channel n. + //TODO: Implement-me! + break; + case 5: + // FNC /n5: Liga flip-flop PERMITE/IMPEDE para o + // dispositivo n (isto é, permite inter- + // -rupcao do dispositivo n). + // + // Turns on the interrupt ENABLE/DISABLE + // flip-flop for channel n. + //TODO: Implement-me! + break; + case 6: + // FNC /n6: Liga flip-flop de CONTROLE e desliga + // flip-flop de ESTADO (ESTADO = "BUSY") + // do dispositivo n . + // + // Turns on the CONTROL flip-flop and + // turns off the STATUS flip-flop for + // channel n ( STATUS = "BUSY"). + m_iodev_control[channel] = REQUEST; + m_iodev_status[channel] = IODEV_BUSY; + break; + case 7: + // FNC /n7: Desliga flip-flop de CONTROLE do dis- + // positivo n. + // + // Turns off the CONTROL flip-flop for + // for channel n. + m_iodev_control[channel] = NO_REQUEST; + break; + case 8: + // FNC /n8: Só funciona na leitora de fita, ca- + // nal /E. Ignora todos os "feed-fra- + // -mes" ("bytes" nulos) da fita, ate' a + // proxima perfuracao (1o "byte" nao + // nulo). + // + // Only works with the punched tape reader, + // device on channel /E. Ignores all + // "feed-frames" (null 'bytes') of the tape, + // until the first punch (1st non-zero 'byte'). + if (channel==0xE){ + //TODO: Implement-me! + } else { + printf("Function 8 of the /FNC instruction can only be used with"\ + "the papertape reader device at channel /E.\n"); + } + break; + default: + printf("Invalid function (#%d) specified in /FNC instruction.\n", function); + } break; case 0x20: //SAL="Salta" // Skips a couple bytes if a condition is met - skip = false; + skip = false; switch(function) { case 1: - if (m_peripherals[channel].io_status == DEVICE_READY) - skip = true; + skip = (m_iodev_status[channel] == IODEV_READY); break; case 2: - if (m_peripherals[channel].device_is_ok) + /* TODO: + skip = false; + if (! m_iodev_is_ok_cb[channel].isnull() + && m_iodev_is_ok_cb[channel](0)) */ skip = true; break; case 4: - if (m_peripherals[channel].IRQ_request == true) + /*TODO: + skip =false; + if (! m_iodev_IRQ_cb[channel].isnull() + && m_iodev_IRQ_cb[channel](0) == true)*/ skip = true; break; } @@ -494,21 +733,28 @@ void patinho_feio_cpu_device::execute_instruction() } break; case 0x40: - printf("Unimplemented ENTR /%X0 instruction\n", channel); + /* ENTR = "Input data from I/O device" */ + ACC = m_iodev_incoming_byte[channel]; + m_iodev_control[channel] = NO_REQUEST; //TODO: <-- check if this is correct break; case 0x80: - printf("Unimplemented SAI /%X0 instruction (ACC = 0x%02X '%c')\n", channel, ACC, ACC); + /* SAI = "Output data to I/O device" */ + if (m_iodev_write_cb[channel].isnull()){ + printf("Warning: There's no device hooked up at I/O address 0x%X", channel); + } else { + m_iodev_write_cb[channel](ACC); + } break; } return; case 0xE0: //SUS = "Subtrai um ou Salta": Subtract one from the data in the given address // or, if the data is zero, then simply skip a couple bytes. - addr = compute_effective_address((opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); + compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); INCREMENT_PC_4K; - value = READ_BYTE_PATINHO(addr); + value = READ_BYTE_PATINHO(m_addr); if (value > 0){ - WRITE_BYTE_PATINHO(addr, value-1); + WRITE_BYTE_PATINHO(m_addr, value-1); } else { INCREMENT_PC_4K; INCREMENT_PC_4K; @@ -518,14 +764,14 @@ void patinho_feio_cpu_device::execute_instruction() //PUG = "Pula e guarda": Jump and store. // It stores the return address to addr and addr+1 // And then jumps to addr+2 - addr = compute_effective_address((opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); + compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC)); INCREMENT_PC_4K; - WRITE_BYTE_PATINHO(addr, (PC >> 8) & 0x0F); - WRITE_BYTE_PATINHO(addr+1, PC & 0xFF); - PC = addr+2; + WRITE_BYTE_PATINHO(m_addr, (PC >> 8) & 0x0F); + WRITE_BYTE_PATINHO(m_addr+1, PC & 0xFF); + PC = m_addr+2; return; } - printf("unimplemented opcode: 0x%02X\n", opcode); + printf("unimplemented opcode: 0x%02X\n", m_opcode); } offs_t patinho_feio_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) diff --git a/src/devices/cpu/patinhofeio/patinho_feio.h b/src/devices/cpu/patinhofeio/patinho_feio.h deleted file mode 100644 index 7057d318c30..00000000000 --- a/src/devices/cpu/patinhofeio/patinho_feio.h +++ /dev/null @@ -1,107 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Felipe Sanches -#pragma once - -#ifndef __PATINHOFEIO_H__ -#define __PATINHOFEIO_H__ - -#define MCFG_PATINHO_RC_READ_CB(_devcb) \ - devcb = &patinho_feio_cpu_device::set_rc_read_callback(*device, DEVCB_##_devcb); - -/* register IDs */ -enum -{ - PATINHO_FEIO_CI=1, PATINHO_FEIO_ACC, PATINHO_FEIO_IDX, PATINHO_FEIO_RC -}; - -enum { - DEVICE_BUSY=0, - DEVICE_READY=1 -}; - -class patinho_feio_peripheral -{ -public: - patinho_feio_peripheral() - : io_status(DEVICE_READY) - , device_is_ok(true) - , IRQ_request(false) - { }; - - int io_status; - bool device_is_ok; - bool IRQ_request; -}; - -class patinho_feio_cpu_device : public cpu_device -{ -public: - // construction/destruction - patinho_feio_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); - - template static devcb_base &set_rc_read_callback(device_t &device, _Object object) { return downcast(device).m_rc_read_cb.set_callback(object); } - -protected: - - virtual void execute_run() override; - virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) override; - - address_space_config m_program_config; - - /* processor registers */ - unsigned char m_acc; /* accumulator (8 bits) */ - unsigned int m_pc; /* program counter (12 bits) - * Actual register name is CI, which - * stands for "Contador de Instrucao" - * or "instructions counter". - */ - unsigned int m_rc; /* RC = "Registrador de Chaves" (Keys Register) - * It represents the 12 bits of input data - * from toggle switches in the computer panel - */ - unsigned char m_idx; - - /* processor state flip-flops */ - bool m_run; /* processor is running */ - bool m_wait_for_interrupt; - bool m_interrupts_enabled; - bool m_scheduled_IND_bit_reset; - bool m_indirect_addressing; - - int m_flags; - // V = "Vai um" (Carry flag) - // T = "Transbordo" (Overflow flag) - - patinho_feio_peripheral m_peripherals[16]; - - int m_address_mask; /* address mask */ - int m_icount; - - address_space *m_program; - - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - - // device_execute_interface overrides - virtual UINT32 execute_min_cycles() const override { return 1; } - virtual UINT32 execute_max_cycles() const override { return 2; } - - // device_memory_interface overrides - virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const override { return (spacenum == AS_PROGRAM) ? &m_program_config : nullptr; } - - // device_disasm_interface overrides - virtual UINT32 disasm_min_opcode_bytes() const override { return 1; } - virtual UINT32 disasm_max_opcode_bytes() const override { return 2; } - -private: - void execute_instruction(); - unsigned int compute_effective_address(unsigned int addr); - UINT16 read_panel_keys_register(); - devcb_read16 m_rc_read_cb; -}; - - -extern const device_type PATINHO_FEIO; - -#endif /* __PATINHOFEIO_H__ */ diff --git a/src/devices/cpu/patinhofeio/patinho_feio_dasm.cpp b/src/devices/cpu/patinhofeio/patinho_feio_dasm.cpp index f2f2899af6e..9365a1c0c76 100644 --- a/src/devices/cpu/patinhofeio/patinho_feio_dasm.cpp +++ b/src/devices/cpu/patinhofeio/patinho_feio_dasm.cpp @@ -1,14 +1,13 @@ // license:GPL-2.0+ // copyright-holders:Felipe Sanches #include "emu.h" -#include "cpu/patinhofeio/patinho_feio.h" +#include "cpu/patinhofeio/patinhofeio_cpu.h" CPU_DISASSEMBLE( patinho_feio ) { int addr, value, n, f; - switch (oprom[0] & 0xF0) - { + switch (oprom[0] & 0xF0) { case 0x00: //PLA = "Pula": Unconditionally JUMP to effective address addr = (oprom[0] & 0x0F) << 8 | oprom[1]; @@ -124,8 +123,7 @@ CPU_DISASSEMBLE( patinho_feio ) return 2; } - switch (oprom[0]) - { + switch (oprom[0]) { case 0x80: sprintf (buffer, "LIMPO"); return 1; case 0x81: sprintf (buffer, "UM"); return 1; case 0x82: sprintf (buffer, "CMP1"); return 1; diff --git a/src/devices/cpu/patinhofeio/patinhofeio_cpu.h b/src/devices/cpu/patinhofeio/patinhofeio_cpu.h new file mode 100644 index 00000000000..b8e6919273d --- /dev/null +++ b/src/devices/cpu/patinhofeio/patinhofeio_cpu.h @@ -0,0 +1,144 @@ +// license:GPL-2.0+ +// copyright-holders:Felipe Sanches +#pragma once + +#ifndef __PATINHOFEIO_H__ +#define __PATINHOFEIO_H__ + +#define MCFG_PATINHO_RC_READ_CB(_devcb) \ + devcb = &patinho_feio_cpu_device::set_rc_read_callback(*device, DEVCB_##_devcb); +#define MCFG_PATINHO_BUTTONS_READ_CB(_devcb) \ + devcb = &patinho_feio_cpu_device::set_buttons_read_callback(*device, DEVCB_##_devcb); +#define MCFG_PATINHO_IODEV_READ_CB(devnumber, _devcb) \ + devcb = &patinho_feio_cpu_device::set_iodev_read_callback(*device, devnumber, DEVCB_##_devcb); +#define MCFG_PATINHO_IODEV_WRITE_CB(devnumber, _devcb) \ + devcb = &patinho_feio_cpu_device::set_iodev_write_callback(*device, devnumber, DEVCB_##_devcb); + +/* register IDs */ +enum +{ + PATINHO_FEIO_CI=1, PATINHO_FEIO_ACC, PATINHO_FEIO_EXT, PATINHO_FEIO_IDX, PATINHO_FEIO_RC +}; + +enum +{ + NORMAL_MODE, + CYCLE_STEP_MODE, + INSTRUCTION_STEP_MODE, + ADDRESSING_MODE, + DATA_STORE_MODE, + DATA_VIEW_MODE +}; + +#define IODEV_READY true +#define IODEV_BUSY false +#define REQUEST true +#define NO_REQUEST false + +#define BUTTON_NORMAL (1 << 0) /* normal CPU execution */ +#define BUTTON_CICLO_UNICO (1 << 1) /* single-cycle step */ +#define BUTTON_INSTRUCAO_UNICA (1 << 2) /* single-instruction step */ +#define BUTTON_ENDERECAMENTO (1 << 3) /* addressing action */ +#define BUTTON_ARMAZENAMENTO (1 << 4) /* storage action */ +#define BUTTON_EXPOSICAO (1 << 5) /* memory viewing action */ +#define BUTTON_ESPERA (1 << 6) /* wait */ +#define BUTTON_INTERRUPCAO (1 << 7) /* interrupt */ +#define BUTTON_PARTIDA (1 << 8) /* startup */ +#define BUTTON_PREPARACAO (1 << 9) /* reset */ +#define BUTTON_TIPO_DE_ENDERECAMENTO (1 << 10) /* Addressing mode (0: Fixed / 1: Sequential) */ +#define BUTTON_PROTECAO_DE_MEMORIA (1 << 11) /* Memory protection (in the address range 0xF80-0xFFF (1: write-only / 0: read-write) */ + +class patinho_feio_cpu_device : public cpu_device { +public: + // construction/destruction + patinho_feio_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + template static devcb_base &set_rc_read_callback(device_t &device, _Object object) { return downcast(device).m_rc_read_cb.set_callback(object); } + template static devcb_base &set_buttons_read_callback(device_t &device, _Object object) { return downcast(device).m_buttons_read_cb.set_callback(object); } + template static devcb_base &set_iodev_read_callback(device_t &device, int devnumber, _Object object) { return downcast(device).m_iodev_read_cb[devnumber].set_callback(object); } + template static devcb_base &set_iodev_write_callback(device_t &device, int devnumber, _Object object) { return downcast(device).m_iodev_write_cb[devnumber].set_callback(object); } + template static devcb_base &set_iodev_status_callback(device_t &device, int devnumber, _Object object) { return downcast(device).m_iodev_status_cb[devnumber].set_callback(object); } + + void transfer_byte_from_external_device(UINT8 channel, UINT8 data); + void set_iodev_status(UINT8 channel, bool status) { + m_iodev_status[channel] = status; + } +protected: + + virtual void execute_run() override; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) override; + + address_space_config m_program_config; + + offs_t m_addr; + unsigned char m_opcode; + + /* processor registers */ + unsigned char m_acc; /* accumulator (8 bits) */ + unsigned int m_pc; /* program counter (12 bits) + * Actual register name is CI, which + * stands for "Contador de Instrucao" + * or "instructions counter". + */ + unsigned int m_rc; /* RC = "Registrador de Chaves" (Keys Register) + * It represents the 12 bits of input data + * from toggle switches in the computer panel + */ + unsigned char m_idx; /* IDX = Index Register */ + unsigned char m_ext; /* EXT = Accumulator Extension Register */ + + /* processor state flip-flops */ + bool m_run; /* processor is running */ + bool m_wait_for_interrupt; + bool m_interrupts_enabled; + bool m_scheduled_IND_bit_reset; + bool m_indirect_addressing; + bool m_iodev_control[16]; + bool m_iodev_status[16]; + + /* 8-bit registers for receiving data from peripherals */ + UINT8 m_iodev_incoming_byte[16]; + + /* 8-bit registers for sending data to peripherals */ + UINT8 m_iodev_outgoing_byte[16]; + + int m_flags; + // V = "Vai um" (Carry flag) + // T = "Transbordo" (Overflow flag) + + int m_address_mask; /* address mask */ + int m_icount; + + address_space *m_program; + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const override { return 1; } + virtual UINT32 execute_max_cycles() const override { return 2; } + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const override { return (spacenum == AS_PROGRAM) ? &m_program_config : nullptr; } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const override { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const override { return 2; } + +private: + void execute_instruction(); + void compute_effective_address(unsigned int addr); + void set_flag(UINT8 flag, bool state); + UINT16 read_panel_keys_register(); + devcb_read16 m_rc_read_cb; + devcb_read16 m_buttons_read_cb; + devcb_read8 m_iodev_read_cb[16]; + devcb_write8 m_iodev_write_cb[16]; + devcb_read8 m_iodev_status_cb[16]; + UINT8 m_mode; +}; + +extern const device_type PATINHO_FEIO; + +#endif /* __PATINHOFEIO_H__ */ diff --git a/src/mame/drivers/patinho_feio.cpp b/src/mame/drivers/patinho_feio.cpp index e40274c884a..65a1e5309ec 100644 --- a/src/mame/drivers/patinho_feio.cpp +++ b/src/mame/drivers/patinho_feio.cpp @@ -5,37 +5,157 @@ */ #include "emu.h" -#include "cpu/patinhofeio/patinho_feio.h" - -class patinho_feio_state : public driver_device -{ -public: - patinho_feio_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag) - //,m_maincpu(*this, "maincpu") - { } - - DECLARE_DRIVER_INIT(patinho_feio); - DECLARE_READ16_MEMBER(rc_r); - void load_tape(const char* name); - void load_raw_data(const char* name, unsigned int start_address, unsigned int data_length); - virtual void machine_start() override; -// virtual void machine_reset(); -// required_device m_maincpu; -}; +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" +#include "softlist.h" +#include "cpu/patinhofeio/patinhofeio_cpu.h" +#include "includes/patinhofeio.h" +#include "patinho.lh" /* driver init function */ DRIVER_INIT_MEMBER(patinho_feio_state, patinho_feio) { + m_out = &output(); + m_prev_ACC = 0; + m_prev_opcode = 0; + m_prev_mem_data = 0; + m_prev_mem_addr = 0; + m_prev_PC = 0; + m_prev_FLAGS = 0; + m_prev_RC = 0; } READ16_MEMBER(patinho_feio_state::rc_r) { - return ioport("RC_HIGH")->read() << 8 | ioport("RC_LOW")->read(); + return ioport("RC")->read(); } +READ16_MEMBER(patinho_feio_state::buttons_r) +{ + return ioport("BUTTONS")->read(); +} + +void patinho_feio_state::update_panel(UINT8 ACC, UINT8 opcode, UINT8 mem_data, UINT16 mem_addr, UINT16 PC, UINT8 FLAGS, UINT16 RC, UINT8 mode){ + char lamp_id[11]; + const char* button_names[] = { + "NORMAL", + "CICLOUNICO", + "INSTRUCAOUNICA", + "ENDERECAMENTO", + "ARMAZENAMENTO", + "EXPOSICAO" + }; + + for (int i=0; i<6; i++){ + m_out->set_value(button_names[i], (mode == i) ? 1 : 0); + } + + for (int i=0; i<8; i++){ + if ((m_prev_ACC ^ ACC) & (1 << i)){ + sprintf(lamp_id, "acc%d", i); + m_out->set_value(lamp_id, (ACC >> i) & 1); + } + if ((m_prev_opcode ^ opcode) & (1 << i)){ + sprintf(lamp_id, "opcode%d", i); + m_out->set_value(lamp_id, (opcode >> i) & 1); + } + if ((m_prev_mem_data ^ mem_data) & (1 << i)){ + sprintf(lamp_id, "mem_data%d", i); + m_out->set_value(lamp_id, (mem_data >> i) & 1); + } + } + m_prev_ACC = ACC; + m_prev_opcode = opcode; + m_prev_mem_data = mem_data; + + for (int i=0; i<12; i++){ + if ((m_prev_mem_addr ^ mem_addr) & (1 << i)){ + sprintf(lamp_id, "mem_addr%d", i); + m_out->set_value(lamp_id, (mem_addr >> i) & 1); + } + if ((m_prev_PC ^ PC) & (1 << i)){ + sprintf(lamp_id, "pc%d", i); + m_out->set_value(lamp_id, (PC >> i) & 1); + } + if ((m_prev_RC ^ RC) & (1 << i)){ + sprintf(lamp_id, "rc%d", i); + m_out->set_value(lamp_id, (RC >> i) & 1); + } + } + m_prev_mem_addr = mem_addr; + m_prev_PC = PC; + m_prev_RC = RC; + + if ((m_prev_FLAGS ^ FLAGS) & (1 << 0)) m_out->set_value("flags0", (FLAGS >> 0) & 1); + if ((m_prev_FLAGS ^ FLAGS) & (1 << 1)) m_out->set_value("flags1", (FLAGS >> 1) & 1); + m_prev_FLAGS = FLAGS; +} + +WRITE8_MEMBER(patinho_feio_state::decwriter_data_w) +{ + m_decwriter->write(space, 0, data); + + m_maincpu->set_iodev_status(0xA, IODEV_BUSY); + + if (data == 0x0D){ + m_decwriter_timer->adjust(attotime::from_hz(1/0.700)); //carriage return takes 700 msecs + } else { + m_decwriter_timer->adjust(attotime::from_hz(10)); //10 characters per second + } + m_decwriter_timer->enable(1); //start the timer +} + +/* + timer callback to generate decwriter char print completion signal +*/ +TIMER_CALLBACK_MEMBER(patinho_feio_state::decwriter_callback) +{ + m_maincpu->set_iodev_status(0xA, IODEV_READY); + m_decwriter_timer->enable(0); //stop the timer +} + +WRITE8_MEMBER(patinho_feio_state::decwriter_kbd_input) +{ + m_maincpu->transfer_byte_from_external_device(0xA, ~data); +} + +WRITE8_MEMBER(patinho_feio_state::teletype_data_w) +{ + m_tty->write(space, 0, data); + + m_maincpu->set_iodev_status(0xB, IODEV_READY); + m_teletype_timer->adjust(attotime::from_hz(10)); //10 characters per second + m_teletype_timer->enable(1); //start the timer +} + +/* + timer callback to generate teletype char print completion signal +*/ +TIMER_CALLBACK_MEMBER(patinho_feio_state::teletype_callback) +{ + m_maincpu->set_iodev_status(0xB, IODEV_READY); + m_teletype_timer->enable(0); //stop the timer +} + +WRITE8_MEMBER(patinho_feio_state::teletype_kbd_input) +{ + //I figured out that the data is provided inverted (2's complement) + //based on a comment in the source code listing of the HEXAM program. + //It is not clear though, if all I/O devices complement the data when + //communicating with the computer, or if this behavious is a particular + //caracteristics of the teletype. + + m_maincpu->transfer_byte_from_external_device(0xB, ~data); +} + +/* The hardware does not perform this checking. + This is implemented here only for debugging purposes. + + Also, proper punched paper tape emulation does + not use this function at all. +*/ void patinho_feio_state::load_tape(const char* name){ UINT8 *RAM = (UINT8 *) memshare("maincpu:internalram")->ptr(); UINT8 *data = memregion(name)->base(); @@ -50,7 +170,7 @@ void patinho_feio_state::load_tape(const char* name){ if (checksum != expected_checksum){ printf("[WARNING] Tape \"%s\": checksum = 0x%02X (expected 0x%02X)\n", - name, (unsigned char) checksum, (unsigned char) expected_checksum); + name, (unsigned char) checksum, (unsigned char) expected_checksum); } memcpy(&RAM[start_address], &data[3], data_length); @@ -63,7 +183,21 @@ void patinho_feio_state::load_raw_data(const char* name, unsigned int start_addr memcpy(&RAM[start_address], data, data_length); } +DEVICE_IMAGE_LOAD_MEMBER( patinho_feio_state, patinho_tape ) +{ + if (image.software_entry() != nullptr){ + paper_tape_length = image.get_software_region_length("rom"); + paper_tape_data = image.get_software_region("rom"); + paper_tape_address = 0; + } + + return IMAGE_INIT_PASS; +} + void patinho_feio_state::machine_start(){ + m_teletype_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(patinho_feio_state::teletype_callback),this)); + m_decwriter_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(patinho_feio_state::decwriter_callback),this)); + // Copy some programs directly into RAM. // This is a hack for setting up the computer // while we don't support loading programs @@ -77,24 +211,43 @@ void patinho_feio_state::machine_start(){ // Allows users to load programs from the // console into the computer memory. load_raw_data("hexam", 0xE00, 0x0D5); + + load_raw_data("loader", 0xF80, 0x080); + //load_raw_data("micro_pre_loader", 0x000, 0x02A); //this is still experimental } static INPUT_PORTS_START( patinho_feio ) - PORT_START("RC_LOW") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 0") PORT_CODE(KEYCODE_EQUALS) PORT_TOGGLE - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 1") PORT_CODE(KEYCODE_MINUS) PORT_TOGGLE - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 2") PORT_CODE(KEYCODE_0) PORT_TOGGLE - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 3") PORT_CODE(KEYCODE_9) PORT_TOGGLE - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 4") PORT_CODE(KEYCODE_8) PORT_TOGGLE - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 5") PORT_CODE(KEYCODE_7) PORT_TOGGLE - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 6") PORT_CODE(KEYCODE_6) PORT_TOGGLE - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 7") PORT_CODE(KEYCODE_5) PORT_TOGGLE + PORT_START("RC") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 0") PORT_CODE(KEYCODE_EQUALS) PORT_TOGGLE + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 1") PORT_CODE(KEYCODE_MINUS) PORT_TOGGLE + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 2") PORT_CODE(KEYCODE_0) PORT_TOGGLE + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 3") PORT_CODE(KEYCODE_9) PORT_TOGGLE + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 4") PORT_CODE(KEYCODE_8) PORT_TOGGLE + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 5") PORT_CODE(KEYCODE_7) PORT_TOGGLE + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 6") PORT_CODE(KEYCODE_6) PORT_TOGGLE + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 7") PORT_CODE(KEYCODE_5) PORT_TOGGLE + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 8") PORT_CODE(KEYCODE_4) PORT_TOGGLE + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 7") PORT_CODE(KEYCODE_3) PORT_TOGGLE + PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 10") PORT_CODE(KEYCODE_2) PORT_TOGGLE + PORT_BIT(0x800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 11") PORT_CODE(KEYCODE_1) PORT_TOGGLE - PORT_START("RC_HIGH") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 8") PORT_CODE(KEYCODE_4) PORT_TOGGLE - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 7") PORT_CODE(KEYCODE_3) PORT_TOGGLE - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 10") PORT_CODE(KEYCODE_2) PORT_TOGGLE - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RC bit 11") PORT_CODE(KEYCODE_1) PORT_TOGGLE + PORT_START("BUTTONS") + /* Modo de Operação: EXECUÇÃO */ + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("NORMAL") PORT_CODE(KEYCODE_A) + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CICLO ÚNICO") PORT_CODE(KEYCODE_S) + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("INSTRUÇÃO ÚNICA") PORT_CODE(KEYCODE_D) + /* Modo de Operação: MEMÓRIA */ + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENDEREÇAMENTO") PORT_CODE(KEYCODE_Z) + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ARMAZENAMENTO") PORT_CODE(KEYCODE_X) + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("EXPOSIÇÃO") PORT_CODE(KEYCODE_C) + /* Comando: */ + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ESPERA") PORT_CODE(KEYCODE_Q) + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("INTERRUPÇÃO") PORT_CODE(KEYCODE_W) + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("PARTIDA") PORT_CODE(KEYCODE_E) + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("PREPARAÇÃO") PORT_CODE(KEYCODE_R) + /* Switches */ + PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENDEREÇAMENTO (Fixo/Sequencial)") PORT_CODE(KEYCODE_N) PORT_TOGGLE + PORT_BIT(0x800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("MEMÓRIA (Liberada/Protegida)") PORT_CODE(KEYCODE_M) PORT_TOGGLE INPUT_PORTS_END static MACHINE_CONFIG_START( patinho_feio, patinho_feio_state ) @@ -102,14 +255,66 @@ static MACHINE_CONFIG_START( patinho_feio, patinho_feio_state ) /* CPU @ approx. 500 kHz (memory cycle time is 2usec) */ MCFG_CPU_ADD("maincpu", PATINHO_FEIO, 500000) MCFG_PATINHO_RC_READ_CB(READ16(patinho_feio_state, rc_r)) + MCFG_PATINHO_BUTTONS_READ_CB(READ16(patinho_feio_state, buttons_r)) + + /* Printer */ +// MCFG_PATINHO_IODEV_WRITE_CB(0x5, WRITE8(patinho_feio_state, printer_data_w)) + + /* Papertape Puncher */ +// MCFG_PATINHO_IODEV_WRITE_CB(0x8, WRITE8(patinho_feio_state, papertape_punch_data_w)) + + /* Card Reader */ +// MCFG_PATINHO_IODEV_READ_CB(0x9, READ8(patinho_feio_state, cardreader_data_r)) + + /* DECWRITER + (max. speed: ?) */ + MCFG_PATINHO_IODEV_WRITE_CB(0xA, WRITE8(patinho_feio_state, decwriter_data_w)) + + /* Teleprinter + TeleType ASR33 + (max. speed: 10 characteres per second) + with paper tape reading (and optionally punching) capabilities */ + MCFG_PATINHO_IODEV_WRITE_CB(0xB, WRITE8(patinho_feio_state, teletype_data_w)) + + /* Papertape Reader + Hewlett-Packard HP-2737-A + Optical Papertape Reader (max. speed: 300 characteres per second) */ +// MCFG_PATINHO_IODEV_READ_CB(0xE, READ8(patinho_feio_state, papertapereader_data_r)) + + /* DECWRITER */ + MCFG_DEVICE_ADD("decwriter", TELEPRINTER, 0) + MCFG_GENERIC_TELEPRINTER_KEYBOARD_CB(WRITE8(patinho_feio_state, decwriter_kbd_input)) + + /* Teletype */ + MCFG_DEVICE_ADD("teletype", TELEPRINTER, 1) + MCFG_GENERIC_TELEPRINTER_KEYBOARD_CB(WRITE8(patinho_feio_state, teletype_kbd_input)) + + /* punched tape */ + MCFG_GENERIC_CARTSLOT_ADD("cartslot", generic_plain_slot, "patinho_tape") + MCFG_GENERIC_EXTENSIONS("bin") + MCFG_GENERIC_LOAD(patinho_feio_state, patinho_tape) + + MCFG_DEFAULT_LAYOUT(layout_patinho) + + // software lists +// MCFG_SOFTWARE_LIST_ADD("tape_list", "patinho") MACHINE_CONFIG_END ROM_START( patinho ) ROM_REGION( 0x0d5, "hexam", 0 ) - ROM_LOAD( "apendice_g__hexam.bin", 0x000, 0x0d5, CRC(c6addc59) SHA1(126bc97247eac45c58708eaac216c2438e9e4af9) ) + ROM_LOAD( "apendice_g__hexam.bin", 0x000, 0x0d5, CRC(e608f6d3) SHA1(3f76b5f91d9b2573e70919539d47752e7623e40a) ) ROM_REGION( 0x0d5, "exemplo_16.7", 0 ) ROM_LOAD( "exemplo_16.7.bin", 0x000, 0x028, CRC(0a87ac8d) SHA1(7c35ac3eed9ed239f2ef56c26e6f0c59f635e1ac) ) + + ROM_REGION( 0x080, "loader", 0 ) + ROM_LOAD( "loader.bin", 0x000, 0x080, BAD_DUMP CRC(c2a8fa9d) SHA1(0ae4f711ef5d6e9d26c611fd2c8c8ac45ecbf9e7) ) + + /* Micro pre-loader: + This was re-created by professor Joao Jose Neto based on his vague + recollection of sequences of opcode values from almost 40 years ago :-) */ + ROM_REGION( 0x02a, "micro_pre_loader", 0 ) + ROM_LOAD( "micro-pre-loader.bin", 0x000, 0x02a, CRC(1921feab) SHA1(bb063102e44e9ab963f95b45710141dc2c5046b0) ) ROM_END /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ diff --git a/src/mame/includes/patinhofeio.h b/src/mame/includes/patinhofeio.h new file mode 100644 index 00000000000..c2b5693a8a9 --- /dev/null +++ b/src/mame/includes/patinhofeio.h @@ -0,0 +1,50 @@ +// license:GPL2+ +// copyright-holders:Felipe Sanches +#include "machine/teleprinter.h" + +class patinho_feio_state : public driver_device { +public: + patinho_feio_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_decwriter(*this, "decwriter") + , m_tty(*this, "teletype") + { } + + DECLARE_DRIVER_INIT(patinho_feio); + DECLARE_READ16_MEMBER(rc_r); + DECLARE_READ16_MEMBER(buttons_r); + + DECLARE_WRITE8_MEMBER(decwriter_data_w); + DECLARE_WRITE8_MEMBER(decwriter_kbd_input); + TIMER_CALLBACK_MEMBER(decwriter_callback); + + DECLARE_WRITE8_MEMBER(teletype_data_w); + DECLARE_WRITE8_MEMBER(teletype_kbd_input); + TIMER_CALLBACK_MEMBER(teletype_callback); + + DECLARE_DEVICE_IMAGE_LOAD_MEMBER( patinho_tape ); + void load_tape(const char* name); + void load_raw_data(const char* name, unsigned int start_address, unsigned int data_length); + void update_panel(UINT8 ACC, UINT8 opcode, UINT8 mem_data, UINT16 mem_addr, UINT16 PC, UINT8 FLAGS, UINT16 RC, UINT8 mode); + virtual void machine_start() override; + + required_device m_maincpu; + required_device m_decwriter; + required_device m_tty; +private: + UINT8* paper_tape_data; + UINT32 paper_tape_length; + UINT32 paper_tape_address; + + emu_timer *m_decwriter_timer; + emu_timer *m_teletype_timer; + output_manager *m_out; + UINT8 m_prev_ACC; + UINT8 m_prev_opcode; + UINT8 m_prev_mem_data; + UINT16 m_prev_mem_addr; + UINT16 m_prev_PC; + UINT8 m_prev_FLAGS; + UINT16 m_prev_RC; +};