mirror of
https://github.com/mamedev/mame.git
synced 2024-11-18 10:06:19 +01:00
Merge pull request #893 from felipesanches/patinho_feio
Further improvements to the Patinho Feio driver & CPU [Felipe Sanches]
This commit is contained in:
commit
879c08632c
6 changed files with 561 additions and 218 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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<patinho_feio_cpu_device>;
|
||||
|
||||
|
||||
//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)
|
||||
|
|
|
@ -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<class _Object> static devcb_base &set_rc_read_callback(device_t &device, _Object object) { return downcast<patinho_feio_cpu_device &>(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__ */
|
|
@ -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;
|
||||
|
|
|
@ -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<patinho_feio_cpu_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 */
|
||||
|
|
Loading…
Reference in a new issue