summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/cpu/patinhofeio/patinho_feio.cpp
blob: a040d24391670abbdee9e4fecb323594245b6e28 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                   

                                   
                                                                                          



                     

                                 
 
                                                                                                 
                      
                      
                                           



                                             
 
                                                      

                                                            

                                                                                
                                                 
                                                                       
 


                                                                               
                                
                                                          
 




                                                               
         
 
 






                                                                           

 
                                                                           
 

                                                                           
                                                               

               
                                                                                                                               


                                                                                                             





                                                                                                                                                 


 
                                                           



                                       
 
                    

 





                                                                                            
                                            
 

                                       


                                                                     
                                                 


                                            
                                                                            




                                                                  

                               
                               


                                 

                                  




                                                                                   
                                                                                  









                                                                                   










                                                      
                                

 
                                            
 



                                                    
                 

                                         

                                 
                      

                                          



                                                                                                                               
 
 
                                                           




























                                                                                                                                                                                        

                                                                                       




                                              

 
                             
                                                   
 


                                               
                                         







                                                 
                          














                                                                                             

                                                                                                                   

                                                     
































































































                                                                                                  


                                                                        
                                                                     













                                                                         
                                                                     













                                                                        
                                                                     













                                                                         
                                                                     











                                                                        
                                                                            
                                                                           
                                                           


                                                     
                                                            
                                                                                                    


                                                                               
                               



























































































































                                                                                                                      
                                                                                                                    






                                                               
                                 

                                                       
                                                                                                  
                                        
                                    


                                                                         
                                                                             

                                                 

                                                               


                                                                                                           
                                                                                                  
                                        
                                                        


                                                                                                                             
                                                                             

                                                 

                                                               


                                                                                                         
                                                                                                  
                                        
                                                        


                                                                                                                         
                                                                             

                                                 

                                                               


                                                                                                     
                                                                                                  
                                        
                                                         



                                                                                                                       
                                                                             

                                                 

                                                               



                                                                                                   
                                                                                                  

                                                  
                                            


                                                                                               
                                                                                                  

                                        
                                            





                                                      
                                                  


                                                



                                                                                                         
                                                                                                          































                                                                                                          
                                                                                                         

























                                                                                                         
                                                                                                       












                                                                                                                                  
                                                                                                                                




                                                                                                                                    



                                                                                        
                                                                                             


                                                        
                                                                                                        

                                                              



                                                                                                


                                                                            



                                                                                                    









                                                                            


                                                                                                                   

                                              





                                                                                                                            





                                                                                                                
                                                                                                  
                                        
                                                          
                                       
                                                                    








                                                                               
                                                                                                  
                                        


                                                                     

                               
                                                           

 
                                                                                                                                   
 

                                                                                           
 
// license:GPL-2.0+
// copyright-holders:Felipe Sanches
/*
    CPU emulation for Patinho Feio, the first computer designed and manufactured in Brazil
*/

#include "emu.h"
#include "debugger.h"
#include "patinhofeio_cpu.h"
#include "includes/patinhofeio.h"

#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

#define V 0x01 // V = "Vai um" (Carry)
#define T 0x02 // T = "Transbordo" (Overflow)

#define READ_BYTE_PATINHO(A) (m_program->read_byte(A))
#define WRITE_BYTE_PATINHO(A,V) (m_program->write_byte(A,V))

#define READ_WORD_PATINHO(A) (READ_BYTE_PATINHO(A+1)*256 + READ_BYTE_PATINHO(A))

#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)

void patinho_feio_cpu_device::set_flag(UINT8 flag, bool state){
	if (state){
		FLAGS |= flag;
	} else {
		FLAGS &= ~flag;
	}
}

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")
ADDRESS_MAP_END

patinho_feio_cpu_device::patinho_feio_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
	: 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_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}
{
}

UINT16 patinho_feio_cpu_device::read_panel_keys_register(){
	if (!m_rc_read_cb.isnull())
		m_rc = m_rc_read_cb(0);
	else
		m_rc = 0;

	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: "Endereco de Retorno de Interrupcao"
//           "Interrupt Return Address"
//           stored at addresses 002 and 003
//
//      ETI: "inicio de uma rotina de tratamento de interrupcao (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");

	if (m_rc_read_cb.isnull()){
		fatalerror("Panel keys register not found!");
	} else {
		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 = 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 = 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 {
		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 {
			execute_instruction();
			m_icount --;
		}
	}
	while (m_icount > 0);
}

/* execute one instruction */
void patinho_feio_cpu_device::execute_instruction()
{
	bool skip;
	unsigned int tmp;
	unsigned char value, channel, function;
	m_opcode = READ_BYTE_PATINHO(PC);
	INCREMENT_PC_4K;

	if (m_scheduled_IND_bit_reset)
		m_indirect_addressing = false;

	if (m_indirect_addressing)
		m_scheduled_IND_bit_reset = true;

	switch (m_opcode){
		case 0xD2:
			//XOR: Computes the bitwise XOR of an immediate into the accumulator
			ACC ^= READ_BYTE_PATINHO(PC);
			INCREMENT_PC_4K;
			//TODO: update T and V flags
			return;
		case 0xD4:
			//NAND: Computes the bitwise XOR of an immediate into the accumulator
			ACC = ~(ACC & READ_BYTE_PATINHO(PC));
			INCREMENT_PC_4K;
			//TODO: update T and V flags
			return;
		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;
			return;
		case 0xDA:
			//CARI="Carrega Imediato":
			//     Load an immediate into the accumulator
			ACC = READ_BYTE_PATINHO(PC);
			INCREMENT_PC_4K;
			return;
		case 0x80:
			//LIMPO:
			//    Clear accumulator and flags
			ACC = 0;
			FLAGS = 0;
			return;
		case 0x81:
			//UM="One":
			//    Load 1 into accumulator
			//    and clear the flags
			ACC = 1;
			FLAGS = 0;
			return;
		case 0x82:
			//CMP1:
			// Compute One's complement of the accumulator
			//    and clear the flags
			ACC = ~ACC;
			FLAGS = 0;
			return;
		case 0x83:
			//CMP2:
			// Compute Two's complement of the accumulator
			//    and updates flags according to the result of the operation
			ACC = ~ACC + 1;
			FLAGS = 0; //TODO: fix-me (I'm not sure yet how to compute the flags here)
			return;
		case 0x84:
			//LIM="Limpa":
			// Clear flags
			FLAGS = 0;
			return;
		case 0x85:
			//INC:
			// Increment accumulator
			ACC++;
			FLAGS = 0; //TODO: fix-me (I'm not sure yet how to compute the flags here)
			return;
		case 0x86:
			//UNEG="Um Negativo":
			// Load -1 into accumulator and clear flags
			ACC = -1;
			FLAGS = 0;
			return;
		case 0x87:
			//LIMP1:
			//    Clear accumulator, reset T and set V
			ACC = 0;
			FLAGS = V;
			return;
		case 0x88:
			//PNL 0:
			ACC = (RC & 0xFF);
			FLAGS = 0;
			return;
		case 0x89:
			//PNL 1:
			ACC = (RC & 0xFF) + 1;
			//TODO: FLAGS = ?;
			return;
		case 0x8A:
			//PNL 2:
			ACC = (RC & 0xFF) - ACC - 1;
			//TODO: FLAGS = ?;
			return;
		case 0x8B:
			//PNL 3:
			ACC = (RC & 0xFF) - ACC;
			//TODO: FLAGS = ?;
			return;
		case 0x8C:
			//PNL 4:
			ACC = (RC & 0xFF) + ACC;
			//TODO: FLAGS = ?;
			return;
		case 0x8D:
			//PNL 5:
			ACC = (RC & 0xFF) + ACC + 1;
			//TODO: FLAGS = ?;
			return;
		case 0x8E:
			//PNL 6:
			ACC = (RC & 0xFF) - 1;
			//TODO: FLAGS = ?;
			return;
		case 0x8F:
			//PNL 7:
			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 interrupcao"
			//     Jump to address /002 and disables interrupts
						PC = 0x002;
			m_interrupts_enabled = false;
			return;
		case 0x99:
			//TRE="Troca conteudos 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
			m_interrupts_enabled = false;
			return;
		case 0x9B:
			//PERM="Permite"
			//     enables interrupts
			m_interrupts_enabled = true;
			return;
		case 0x9C:
			//ESP="Espera":
			//    Holds execution and waits for an interrupt to occur.
			m_run = false;
			m_wait_for_interrupt = true;
			return;
		case 0x9D:
			//PARE="Pare":
			//    Holds execution. This can only be recovered by
			//    manually triggering execution again by
			//    pressing the "Partida" (start) button in the panel
			m_run = false;
			m_wait_for_interrupt = false;
			return;
		case 0x9E:
			//TRI="Troca com Indexador":
			//     Exchange the value of the accumulator with the index register
			value = ACC;
			ACC = READ_INDEX_REG();
			WRITE_INDEX_REG(value);
			return;
		case 0x9F:
			//IND="Enderecamento indireto":
			//     Sets memory addressing for the next instruction to be indirect.
			m_indirect_addressing = true;
			m_scheduled_IND_bit_reset = false; //the next instruction execution will schedule it.
			return;
		case 0xD1:
			//Bit-Shift/Bit-Rotate instructions
			value = READ_BYTE_PATINHO(PC);
			INCREMENT_PC_4K;
			for (int i=0; i<4; i++){
				if (value & (1<<i)){
					/* The number of shifts or rotations is determined by the
					   ammount of 1 bits in the lower 4 bits of 'value' */
					switch(value & 0xF0)
					{
						case 0x00:
							//DD="Deslocamento para a Direita"
							//    Shift right
							FLAGS &= ~V;
							if (ACC & 1)
								FLAGS |= V;

							ACC >>= 1;
							break;
						case 0x20:
							//GD="Giro para a Direita"
							//    Rotate right
							FLAGS &= ~V;
							if (ACC & 1)
								FLAGS |= V;

							ACC = ((ACC & 1) << 7) | (ACC >> 1);
							break;
						case 0x10: //DDV="Deslocamento para a Direita com Vai-um"
								//     Shift right with Carry
						case 0x30: //GDV="Giro para a Direita com Vai-um"
								//     Rotate right with Carry

							//both instructions are equivalent
							if (FLAGS & V)
								tmp = 0x100 | ACC;
							else
								tmp = ACC;

							FLAGS &= ~V;
							if (ACC & 1)
								FLAGS |= V;

							ACC = tmp >> 1;
							break;
						case 0x40: //DE="Deslocamento para a Esquerda"
								//    Shift left
							FLAGS &= ~V;
							if (ACC & (1<<7))
								FLAGS |= V;

							ACC <<= 1;
							break;
						case 0x60: //GE="Giro para a Esquerda"
								//    Rotate left
							FLAGS &= ~V;
							if (ACC & (1<<7))
								FLAGS |= V;

							ACC = (ACC << 1) | ((ACC >> 7) & 1);
							break;
						case 0x50: //DEV="Deslocamento para a Esquerda com Vai-um"
								//     Shift left with Carry
						case 0x70: //GEV="Giro para a Esquerda com Vai-um"
								//     Rotate left with Carry

							//both instructions are equivalent
							if (FLAGS & V)
								tmp = (ACC << 1) | 1;
							else
								tmp = (ACC << 1);

							FLAGS &= ~V;
							if (tmp & (1<<8))
								FLAGS |= V;

							ACC = tmp & 0xFF;
							break;
						case 0x80: //DDS="Deslocamento para a Direita com duplicacao de Sinal"
								//     Rotate right with signal duplication
							FLAGS &= ~V;
							if (ACC & 1)
								FLAGS |= V;

							ACC = (ACC & (1 << 7)) | ACC >> 1;
							break;
						default:
							printf("Illegal instruction: %02X %02X\n", m_opcode, value);
							return;
					}
				}
			}
			return;
	}

	switch (m_opcode & 0xF0){
		case 0x00:
			//PLA = "Pula": Jump to address
			compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC));
			INCREMENT_PC_4K;
			PC = m_addr;
			return;
		case 0x10:
			//PLAX = "Pula indexado": Jump to indexed address
			tmp = (m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC);
			INCREMENT_PC_4K;
			m_idx = READ_INDEX_REG();
			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
			compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC));
			INCREMENT_PC_4K;
			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 = (m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC);
			INCREMENT_PC_4K;
			m_idx = READ_INDEX_REG();
			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
			compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC));
			INCREMENT_PC_4K;
			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 = (m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC);
			INCREMENT_PC_4K;
			m_idx = READ_INDEX_REG();
			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
			compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC));
			INCREMENT_PC_4K;
			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 = (m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC);
			INCREMENT_PC_4K;
			m_idx = READ_INDEX_REG();
			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
			compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC));
			INCREMENT_PC_4K;
			if ((signed char) ACC < 0)
				PC = m_addr;
			return;
		case 0xB0:
			//PLAZ = "Pula se ACC for zero": Jump to a given address if ACC is zero
			compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC));
			INCREMENT_PC_4K;
			if (ACC == 0)
				PC = m_addr;
			return;
		case 0xC0:
			//Executes I/O functions
			//TODO: Implement-me!
			value = READ_BYTE_PATINHO(PC);
			INCREMENT_PC_4K;
			channel = m_opcode & 0x0F;
			function = value & 0x0F;
			switch(value & 0xF0){
				case 0x10:
					switch(function)
					{
						case 0:
							// FNC /n0: Desliga flip-flop PERMITE/IMPEDE para
							//          o dispositivo n (isto e, 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 e, 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: So 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;
					switch(function)
					{
						case 1:
							skip = (m_iodev_status[channel] == IODEV_READY);
							break;
						case 2:
							/* TODO:
							skip = false;
							if (! m_iodev_is_ok_cb[channel].isnull()
							    && m_iodev_is_ok_cb[channel](0)) */
								skip = true;
							break;
						case 4:
							/*TODO:
							skip =false;
							if (! m_iodev_IRQ_cb[channel].isnull()
							    && m_iodev_IRQ_cb[channel](0) == true)*/
								skip = true;
							break;
					}

					if (skip){
						INCREMENT_PC_4K;
						INCREMENT_PC_4K;
					}
					break;
				case 0x40:
					/* 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:
					/* 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.
			compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC));
			INCREMENT_PC_4K;
			value = READ_BYTE_PATINHO(m_addr);
			if (value > 0){
				WRITE_BYTE_PATINHO(m_addr, value-1);
			} else {
				INCREMENT_PC_4K;
				INCREMENT_PC_4K;
			}
			return;
		case 0xF0:
			//PUG = "Pula e guarda": Jump and store.
			//      It stores the return address to addr and addr+1
			//      And then jumps to addr+2
			compute_effective_address((m_opcode & 0x0F) << 8 | READ_BYTE_PATINHO(PC));
			INCREMENT_PC_4K;
			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", m_opcode);
}

offs_t patinho_feio_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
{
	extern CPU_DISASSEMBLE( patinho_feio );
	return CPU_DISASSEMBLE_NAME(patinho_feio)(this, buffer, pc, oprom, opram, options);
}