2024-01-06 19:33:56 +00:00
# include <stdio.h>
2024-01-07 12:32:22 +00:00
# include <stdlib.h>
2024-01-06 19:33:56 +00:00
# include <stdint.h> // for the uintx_t's
2024-01-07 12:32:22 +00:00
# include <unistd.h> // for sleep
2024-01-13 21:38:02 +00:00
# include <gtk/gtk.h>
2024-01-15 19:44:19 +00:00
# include <pthread.h>
2024-01-06 21:23:36 +00:00
2024-01-15 19:44:19 +00:00
// gcc emulator_shell.c `pkg-config --cflags --libs gtk+-3.0` -lpthread -o emulator
2024-01-13 21:38:02 +00:00
2024-01-14 12:26:06 +00:00
//===== EMULATOR SETUP =====
2024-01-15 13:06:04 +00:00
//GLOBAL VARIABLES
uint8_t in_port ;
char which_interrupt ;
2024-01-19 21:45:49 +00:00
uint8_t upscaleFactor = 2 ;
2024-01-14 21:35:01 +00:00
//GLOBAL GRAPHICS
2024-01-20 18:06:47 +00:00
uint8_t * bitmap = NULL ;
2024-01-15 13:06:04 +00:00
2024-01-14 16:50:35 +00:00
2024-01-14 12:26:06 +00:00
typedef struct ConditionCodes {
//bitfields for condition codes
//the number following the variables sets the number of bits
uint8_t z : 1 ;
uint8_t s : 1 ;
uint8_t p : 1 ;
uint8_t cy : 1 ;
uint8_t ac : 1 ;
uint8_t pad : 3 ;
} ConditionCodes ;
typedef struct State8080 {
uint8_t a ;
uint8_t b ;
uint8_t c ;
uint8_t d ;
uint8_t e ;
uint8_t h ;
uint8_t l ;
uint16_t sp ;
uint16_t pc ;
uint8_t * memory ;
ConditionCodes cc ;
uint8_t int_enable ;
uint8_t shift_offset ;
uint8_t shift0 ;
uint8_t shift1 ;
} State8080 ;
unsigned char cycles8080 [ ] = {
4 , 10 , 7 , 5 , 5 , 5 , 7 , 4 , 4 , 10 , 7 , 5 , 5 , 5 , 7 , 4 , //0x00..0x0f
4 , 10 , 7 , 5 , 5 , 5 , 7 , 4 , 4 , 10 , 7 , 5 , 5 , 5 , 7 , 4 , //0x10..0x1f
4 , 10 , 16 , 5 , 5 , 5 , 7 , 4 , 4 , 10 , 16 , 5 , 5 , 5 , 7 , 4 , //etc
4 , 10 , 13 , 5 , 10 , 10 , 10 , 4 , 4 , 10 , 13 , 5 , 5 , 5 , 7 , 4 ,
5 , 5 , 5 , 5 , 5 , 5 , 7 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 7 , 5 , //0x40..0x4f
5 , 5 , 5 , 5 , 5 , 5 , 7 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 7 , 5 ,
5 , 5 , 5 , 5 , 5 , 5 , 7 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 7 , 5 ,
7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 5 , 5 , 5 , 5 , 5 , 5 , 7 , 5 ,
4 , 4 , 4 , 4 , 4 , 4 , 7 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 7 , 4 , //0x80..8x4f
4 , 4 , 4 , 4 , 4 , 4 , 7 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 7 , 4 ,
4 , 4 , 4 , 4 , 4 , 4 , 7 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 7 , 4 ,
4 , 4 , 4 , 4 , 4 , 4 , 7 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 7 , 4 ,
11 , 10 , 10 , 10 , 17 , 11 , 7 , 11 , 11 , 10 , 10 , 10 , 10 , 17 , 7 , 11 , //0xc0..0xcf
11 , 10 , 10 , 10 , 17 , 11 , 7 , 11 , 11 , 10 , 10 , 10 , 10 , 17 , 7 , 11 ,
11 , 10 , 10 , 18 , 17 , 11 , 7 , 11 , 11 , 5 , 10 , 5 , 17 , 17 , 7 , 11 ,
11 , 10 , 10 , 4 , 17 , 11 , 7 , 11 , 11 , 5 , 10 , 4 , 17 , 17 , 7 , 11 ,
} ;
2024-01-20 18:06:47 +00:00
//===== GTK SETUP =====
void keyDown ( uint8_t key )
{
switch ( key ) {
case 0 : // COIN
in_port | = 0x1 ;
break ;
case 1 : // LEFT
in_port | = 0x20 ;
break ;
case 2 : // RIGHT
in_port | = 0x40 ;
break ;
case 3 : // FIRE
in_port | = 0x10 ;
break ;
case 4 : // START
in_port | = 0x04 ;
break ;
}
}
void keyUp ( uint8_t key )
{
switch ( key ) {
case 0 : // COIN
in_port & = ~ 0x1 ;
break ;
case 1 : // LEFT
in_port & = ~ 0x20 ;
break ;
case 2 : // RIGHT
in_port & = ~ 0x40 ;
break ;
case 3 : // FIRE
in_port & = ~ 0x10 ;
break ;
case 4 : // START
in_port & = ~ 0x04 ;
break ;
}
}
static gboolean on_key_press ( GtkWidget * widget , GdkEventKey * event , gpointer user_data )
{
switch ( event - > keyval )
{
case GDK_KEY_a :
// Code to be executed when the left arrow key is pressed down
g_print ( " Left arrow key pressed down \n " ) ;
keyDown ( 1 ) ;
break ;
case GDK_KEY_d :
// Code to be executed when the right arrow key is pressed down
g_print ( " Right arrow key pressed down \n " ) ;
keyDown ( 2 ) ;
break ;
case GDK_KEY_w :
// Code to be executed when the space bar is pressed down
g_print ( " w down \n " ) ;
keyDown ( 3 ) ;
break ;
case GDK_KEY_c :
// Code to be executed when the 'c' key is pressed down
g_print ( " 'c' key pressed down \n " ) ;
keyDown ( 0 ) ;
break ;
case GDK_KEY_s :
// Code to be executed when the 's' key is pressed down
g_print ( " 's' key pressed down \n " ) ;
keyDown ( 4 ) ;
break ;
}
return FALSE ;
}
static gboolean on_key_release ( GtkWidget * widget , GdkEventKey * event , gpointer user_data )
{
switch ( event - > keyval )
{
case GDK_KEY_a :
// Code to be executed when the left arrow key is released
g_print ( " Left arrow key released \n " ) ;
keyUp ( 1 ) ;
break ;
case GDK_KEY_d :
// Code to be executed when the right arrow key is released
g_print ( " Right arrow key released \n " ) ;
keyUp ( 2 ) ;
break ;
case GDK_KEY_w :
// Code to be executed when the space bar is pressed down
g_print ( " w released \n " ) ;
keyUp ( 3 ) ;
break ;
case GDK_KEY_c :
// Code to be executed when the 'c' key is pressed down
g_print ( " 'c' key released \n " ) ;
keyUp ( 0 ) ;
break ;
case GDK_KEY_s :
// Code to be executed when the 's' key is pressed down
g_print ( " 's' key released \n " ) ;
keyUp ( 4 ) ;
break ;
}
return FALSE ;
}
2024-01-14 12:26:06 +00:00
//===== EMULATOR FUNCTIONS =====
2024-01-08 17:07:28 +00:00
int disassemble8080 ( unsigned char * code ) {
2024-01-07 12:32:22 +00:00
int opbytes = 1 ;
switch ( * code ) {
case 0x00 : printf ( " NOP " ) ; break ;
case 0x01 : printf ( " LXI B,#$%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0x02 : printf ( " STAX B " ) ; break ;
case 0x03 : printf ( " INX B " ) ; break ;
case 0x04 : printf ( " INR B " ) ; break ;
case 0x05 : printf ( " DCR B " ) ; break ;
case 0x06 : printf ( " MVI B,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0x07 : printf ( " RLC " ) ; break ;
case 0x08 : printf ( " NOP " ) ; break ;
case 0x09 : printf ( " DAD B " ) ; break ;
case 0x0a : printf ( " LDAX B " ) ; break ;
case 0x0b : printf ( " DCX B " ) ; break ;
case 0x0c : printf ( " INR C " ) ; break ;
case 0x0d : printf ( " DCR C " ) ; break ;
case 0x0e : printf ( " MVI C,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0x0f : printf ( " RRC " ) ; break ;
case 0x10 : printf ( " NOP " ) ; break ;
case 0x11 : printf ( " LXI D,#$%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0x12 : printf ( " STAX D " ) ; break ;
case 0x13 : printf ( " INX D " ) ; break ;
case 0x14 : printf ( " INR D " ) ; break ;
case 0x15 : printf ( " DCR D " ) ; break ;
case 0x16 : printf ( " MVI D,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0x17 : printf ( " RAL " ) ; break ;
case 0x18 : printf ( " NOP " ) ; break ;
case 0x19 : printf ( " DAD D " ) ; break ;
case 0x1a : printf ( " LDAX D " ) ; break ;
case 0x1b : printf ( " DCX D " ) ; break ;
case 0x1c : printf ( " INR E " ) ; break ;
case 0x1d : printf ( " DCR E " ) ; break ;
case 0x1e : printf ( " MVI E,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0x1f : printf ( " RAR " ) ; break ;
case 0x20 : printf ( " NOP " ) ; break ;
case 0x21 : printf ( " LXI H,#$%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0x22 : printf ( " SHLD $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0x23 : printf ( " INX H " ) ; break ;
case 0x24 : printf ( " INR H " ) ; break ;
case 0x25 : printf ( " DCR H " ) ; break ;
case 0x26 : printf ( " MVI H,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0x27 : printf ( " DAA " ) ; break ;
case 0x28 : printf ( " NOP " ) ; break ;
case 0x29 : printf ( " DAD H " ) ; break ;
case 0x2a : printf ( " LHLD $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0x2b : printf ( " DCX H " ) ; break ;
case 0x2c : printf ( " INR L " ) ; break ;
case 0x2d : printf ( " DCR L " ) ; break ;
case 0x2e : printf ( " MVI L,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0x2f : printf ( " CMA " ) ; break ;
case 0x30 : printf ( " NOP " ) ; break ;
case 0x31 : printf ( " LXI SP,#$%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0x32 : printf ( " STA $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0x33 : printf ( " INX SP " ) ; break ;
case 0x34 : printf ( " INR M " ) ; break ;
case 0x35 : printf ( " DCR M " ) ; break ;
case 0x36 : printf ( " MVI M,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0x37 : printf ( " STC " ) ; break ;
case 0x38 : printf ( " NOP " ) ; break ;
case 0x39 : printf ( " DAD SP " ) ; break ;
case 0x3a : printf ( " LDA $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0x3b : printf ( " DCX SP " ) ; break ;
case 0x3c : printf ( " INR A " ) ; break ;
case 0x3d : printf ( " DCR A " ) ; break ;
case 0x3e : printf ( " MVI A,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0x3f : printf ( " CMC " ) ; break ;
case 0x40 : printf ( " MOV B,B " ) ; break ;
case 0x41 : printf ( " MOV B,C " ) ; break ;
case 0x42 : printf ( " MOV B,D " ) ; break ;
case 0x43 : printf ( " MOV B,E " ) ; break ;
case 0x44 : printf ( " MOV B,H " ) ; break ;
case 0x45 : printf ( " MOV B,L " ) ; break ;
case 0x46 : printf ( " MOV B,M " ) ; break ;
case 0x47 : printf ( " MOV B,A " ) ; break ;
case 0x48 : printf ( " MOV C,B " ) ; break ;
case 0x49 : printf ( " MOV C,C " ) ; break ;
case 0x4a : printf ( " MOV C,D " ) ; break ;
case 0x4b : printf ( " MOV C,E " ) ; break ;
case 0x4c : printf ( " MOV C,H " ) ; break ;
case 0x4d : printf ( " MOV C,L " ) ; break ;
case 0x4e : printf ( " MOV C,M " ) ; break ;
case 0x4f : printf ( " MOV C,A " ) ; break ;
case 0x50 : printf ( " MOV D,B " ) ; break ;
case 0x51 : printf ( " MOV D,C " ) ; break ;
case 0x52 : printf ( " MOV D,D " ) ; break ;
case 0x53 : printf ( " MOV D,E " ) ; break ;
case 0x54 : printf ( " MOV D,H " ) ; break ;
case 0x55 : printf ( " MOV D,L " ) ; break ;
case 0x56 : printf ( " MOV D,M " ) ; break ;
case 0x57 : printf ( " MOV D,A " ) ; break ;
case 0x58 : printf ( " MOV E,B " ) ; break ;
case 0x59 : printf ( " MOV E,C " ) ; break ;
case 0x5a : printf ( " MOV E,D " ) ; break ;
case 0x5b : printf ( " MOV E,E " ) ; break ;
case 0x5c : printf ( " MOV E,H " ) ; break ;
case 0x5d : printf ( " MOV E,L " ) ; break ;
case 0x5e : printf ( " MOV E,M " ) ; break ;
case 0x5f : printf ( " MOV E,A " ) ; break ;
case 0x60 : printf ( " MOV H,B " ) ; break ;
case 0x61 : printf ( " MOV H,C " ) ; break ;
case 0x62 : printf ( " MOV H,D " ) ; break ;
case 0x63 : printf ( " MOV H,E " ) ; break ;
case 0x64 : printf ( " MOV H,H " ) ; break ;
case 0x65 : printf ( " MOV H,L " ) ; break ;
case 0x66 : printf ( " MOV H,M " ) ; break ;
case 0x67 : printf ( " MOV H,A " ) ; break ;
case 0x68 : printf ( " MOV L,B " ) ; break ;
case 0x69 : printf ( " MOV L,C " ) ; break ;
case 0x6a : printf ( " MOV L,D " ) ; break ;
case 0x6b : printf ( " MOV L,E " ) ; break ;
case 0x6c : printf ( " MOV L,H " ) ; break ;
case 0x6d : printf ( " MOV L,L " ) ; break ;
case 0x6e : printf ( " MOV L,M " ) ; break ;
case 0x6f : printf ( " MOV L,A " ) ; break ;
case 0x70 : printf ( " MOV M,B " ) ; break ;
case 0x71 : printf ( " MOV M,C " ) ; break ;
case 0x72 : printf ( " MOV M,D " ) ; break ;
case 0x73 : printf ( " MOV M,E " ) ; break ;
case 0x74 : printf ( " MOV M,H " ) ; break ;
case 0x75 : printf ( " MOV M,L " ) ; break ;
case 0x76 : printf ( " HLT " ) ; break ;
case 0x77 : printf ( " MOV M,A " ) ; break ;
case 0x78 : printf ( " MOV A,B " ) ; break ;
case 0x79 : printf ( " MOV A,C " ) ; break ;
case 0x7a : printf ( " MOV A,D " ) ; break ;
case 0x7b : printf ( " MOV A,E " ) ; break ;
case 0x7c : printf ( " MOV A,H " ) ; break ;
case 0x7d : printf ( " MOV A,L " ) ; break ;
case 0x7e : printf ( " MOV A,M " ) ; break ;
case 0x7f : printf ( " MOV A,A " ) ; break ;
case 0x80 : printf ( " ADD B " ) ; break ;
case 0x81 : printf ( " ADD C " ) ; break ;
case 0x82 : printf ( " ADD D " ) ; break ;
case 0x83 : printf ( " ADD E " ) ; break ;
case 0x84 : printf ( " ADD H " ) ; break ;
case 0x85 : printf ( " ADD L " ) ; break ;
case 0x86 : printf ( " ADD M " ) ; break ;
case 0x87 : printf ( " ADD A " ) ; break ;
case 0x88 : printf ( " ADC B " ) ; break ;
case 0x89 : printf ( " ADC C " ) ; break ;
case 0x8a : printf ( " ADC D " ) ; break ;
case 0x8b : printf ( " ADC E " ) ; break ;
case 0x8c : printf ( " ADC H " ) ; break ;
case 0x8d : printf ( " ADC L " ) ; break ;
case 0x8e : printf ( " ADC M " ) ; break ;
case 0x8f : printf ( " ADC A " ) ; break ;
case 0x90 : printf ( " SUB B " ) ; break ;
case 0x91 : printf ( " SUB C " ) ; break ;
case 0x92 : printf ( " SUB D " ) ; break ;
case 0x93 : printf ( " SUB E " ) ; break ;
case 0x94 : printf ( " SUB H " ) ; break ;
case 0x95 : printf ( " SUB L " ) ; break ;
case 0x96 : printf ( " SUB M " ) ; break ;
case 0x97 : printf ( " SUB A " ) ; break ;
case 0x98 : printf ( " SBB B " ) ; break ;
case 0x99 : printf ( " SBB C " ) ; break ;
case 0x9a : printf ( " SBB D " ) ; break ;
case 0x9b : printf ( " SBB E " ) ; break ;
case 0x9c : printf ( " SBB H " ) ; break ;
case 0x9d : printf ( " SBB L " ) ; break ;
case 0x9e : printf ( " SBB M " ) ; break ;
case 0x9f : printf ( " SBB A " ) ; break ;
case 0xa0 : printf ( " ANA B " ) ; break ;
case 0xa1 : printf ( " ANA C " ) ; break ;
case 0xa2 : printf ( " ANA D " ) ; break ;
case 0xa3 : printf ( " ANA E " ) ; break ;
case 0xa4 : printf ( " ANA H " ) ; break ;
case 0xa5 : printf ( " ANA L " ) ; break ;
case 0xa6 : printf ( " ANA M " ) ; break ;
case 0xa7 : printf ( " ANA A " ) ; break ;
case 0xa8 : printf ( " XRA B " ) ; break ;
case 0xa9 : printf ( " XRA C " ) ; break ;
case 0xaa : printf ( " XRA D " ) ; break ;
case 0xab : printf ( " XRA E " ) ; break ;
case 0xac : printf ( " XRA H " ) ; break ;
case 0xad : printf ( " XRA L " ) ; break ;
case 0xae : printf ( " XRA M " ) ; break ;
case 0xaf : printf ( " XRA A " ) ; break ;
case 0xb0 : printf ( " ORA B " ) ; break ;
case 0xb1 : printf ( " ORA C " ) ; break ;
case 0xb2 : printf ( " ORA D " ) ; break ;
case 0xb3 : printf ( " ORA E " ) ; break ;
case 0xb4 : printf ( " ORA H " ) ; break ;
case 0xb5 : printf ( " ORA L " ) ; break ;
case 0xb6 : printf ( " ORA M " ) ; break ;
case 0xb7 : printf ( " ORA A " ) ; break ;
case 0xb8 : printf ( " CMP B " ) ; break ;
case 0xb9 : printf ( " CMP C " ) ; break ;
case 0xba : printf ( " CMP D " ) ; break ;
case 0xbb : printf ( " CMP E " ) ; break ;
case 0xbc : printf ( " CMP H " ) ; break ;
case 0xbd : printf ( " CMP L " ) ; break ;
case 0xbe : printf ( " CMP M " ) ; break ;
case 0xbf : printf ( " CMP A " ) ; break ;
case 0xc0 : printf ( " RNZ " ) ; break ;
case 0xc1 : printf ( " POP B " ) ; break ;
case 0xc2 : printf ( " JNZ $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xc3 : printf ( " JMP $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xc4 : printf ( " CNZ $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xc5 : printf ( " PUSH B " ) ; break ;
case 0xc6 : printf ( " ADI,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xc7 : printf ( " RST 0 " ) ; break ;
case 0xc8 : printf ( " RZ " ) ; break ;
case 0xc9 : printf ( " RET " ) ; break ;
case 0xca : printf ( " JZ $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xcb : printf ( " NOP " ) ; break ;
case 0xcc : printf ( " CZ $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xcd : printf ( " CALL $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xce : printf ( " ACI,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xcf : printf ( " RST 1 " ) ; break ;
case 0xd0 : printf ( " RNC " ) ; break ;
case 0xd1 : printf ( " POP D " ) ; break ;
case 0xd2 : printf ( " JNC $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xd3 : printf ( " OUT #$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xd4 : printf ( " CNC $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xd5 : printf ( " PUSH D " ) ; break ;
case 0xd6 : printf ( " SUI,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xd7 : printf ( " RST 2 " ) ; break ;
case 0xd8 : printf ( " RC " ) ; break ;
case 0xd9 : printf ( " NOP " ) ; break ;
case 0xda : printf ( " JC $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xdb : printf ( " IN #$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xdc : printf ( " CC $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xdd : printf ( " NOP " ) ; break ;
case 0xde : printf ( " SBI,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xdf : printf ( " RST 3 " ) ; break ;
case 0xe0 : printf ( " RPO " ) ; break ;
case 0xe1 : printf ( " POP H " ) ; break ;
case 0xe2 : printf ( " JPO $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xe3 : printf ( " XTHL " ) ; break ;
case 0xe4 : printf ( " CPO $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xe5 : printf ( " PUSH H " ) ; break ;
case 0xe6 : printf ( " ANI,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xe7 : printf ( " RST 4 " ) ; break ;
case 0xe8 : printf ( " RPE " ) ; break ;
case 0xe9 : printf ( " PCHL " ) ; break ;
case 0xea : printf ( " JPE $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xeb : printf ( " XCHG " ) ; break ;
case 0xec : printf ( " CPE $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xed : printf ( " NOP " ) ; break ;
case 0xee : printf ( " XRI,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xef : printf ( " RST 5 " ) ; break ;
case 0xf0 : printf ( " RP " ) ; break ;
case 0xf1 : printf ( " POP PSW " ) ; break ;
case 0xf2 : printf ( " JP $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xf3 : printf ( " DI " ) ; break ;
case 0xf4 : printf ( " CP $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xf5 : printf ( " PUSH PSW " ) ; break ;
case 0xf6 : printf ( " ORI,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xf7 : printf ( " RST 6 " ) ; break ;
case 0xf8 : printf ( " RM " ) ; break ;
case 0xf9 : printf ( " SPHL " ) ; break ;
case 0xfa : printf ( " JM $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xfb : printf ( " EI " ) ; break ;
case 0xfc : printf ( " CM $%02x%02x " , code [ 2 ] , code [ 1 ] ) ; opbytes = 3 ; break ;
case 0xfd : printf ( " NOP " ) ; break ;
case 0xfe : printf ( " CPI,#$%02x " , code [ 1 ] ) ; opbytes = 2 ; break ;
case 0xff : printf ( " RST 7 " ) ; break ;
}
printf ( " \n " ) ;
return opbytes ;
}
2024-01-20 18:06:47 +00:00
void UnimplementedInstruction ( State8080 * state ) {
2024-01-06 19:33:56 +00:00
printf ( " Error: Unknown instruction " ) ;
2024-01-07 12:32:22 +00:00
return exit ( 1 ) ;
2024-01-06 19:33:56 +00:00
}
int parity ( int x , int size )
{
int i ;
int p = 0 ;
x = ( x & ( ( 1 < < size ) - 1 ) ) ;
for ( i = 0 ; i < size ; i + + )
{
if ( x & 0x1 ) p + + ;
x = x > > 1 ;
}
return ( 0 = = ( p & 0x1 ) ) ;
}
2024-01-13 21:38:02 +00:00
void printState ( State8080 * state ) {
2024-01-15 23:20:20 +00:00
printf ( " \t C=%d,P=%d,S=%d,Z=%d,Enable=%d \n " , state - > cc . cy , state - > cc . p ,
state - > cc . s , state - > cc . z , state - > int_enable ) ;
2024-01-13 21:38:02 +00:00
printf ( " \t A $%02x B $%02x C $%02x D $%02x E $%02x H $%02x L $%02x SP %04x \n " ,
state - > a , state - > b , state - > c , state - > d ,
state - > e , state - > h , state - > l , state - > sp ) ;
}
2024-01-14 10:00:05 +00:00
uint8_t machineIn ( State8080 * state , uint8_t port ) {
uint8_t a ;
switch ( port ) {
2024-01-14 12:26:06 +00:00
case 0 :
2024-01-20 18:06:47 +00:00
a = 0xf ;
2024-01-14 12:26:06 +00:00
break ;
2024-01-20 18:06:47 +00:00
case 1 :
2024-01-14 16:50:35 +00:00
a = in_port ;
2024-01-14 12:26:06 +00:00
break ;
2024-01-20 18:06:47 +00:00
case 2 :
a = 0 ;
break ;
2024-01-14 10:00:05 +00:00
case 3 :
{
uint16_t v = ( state - > shift1 < < 8 ) | ( state - > shift0 ) ;
a = ( ( v > > ( 8 - state - > shift_offset ) ) & 0xff ) ;
}
2024-01-14 16:50:35 +00:00
break ;
2024-01-14 10:00:05 +00:00
}
return a ;
}
2024-01-14 12:26:06 +00:00
void machineOut ( State8080 * state , uint8_t port , uint8_t value ) {
2024-01-14 10:00:05 +00:00
switch ( port ) {
case 2 :
{
state - > shift_offset = value & 0x7 ;
} break ;
case 4 :
{
state - > shift0 = state - > shift1 ;
state - > shift1 = value ;
break ;
}
}
}
2024-01-20 18:06:47 +00:00
// Due to problems in code, many commands were replaced by the ones from the guide
static void LogicFlagsA ( State8080 * state )
{
state - > cc . cy = state - > cc . ac = 0 ;
state - > cc . z = ( state - > a = = 0 ) ;
state - > cc . s = ( 0x80 = = ( state - > a & 0x80 ) ) ;
state - > cc . p = parity ( state - > a , 8 ) ;
}
static void ArithFlagsA ( State8080 * state , uint16_t res )
{
state - > cc . cy = ( res > 0xff ) ;
state - > cc . z = ( ( res & 0xff ) = = 0 ) ;
state - > cc . s = ( 0x80 = = ( res & 0x80 ) ) ;
state - > cc . p = parity ( res & 0xff , 8 ) ;
}
static void WriteMem ( State8080 * state , uint16_t address , uint8_t value )
{
if ( address < 0x2000 )
{
// printf("Writing ROM not allowed %x\n", address);
return ;
}
if ( address > = 0x4000 )
{
// printf("Writing out of Space Invaders RAM not allowed %x\n", address);
return ;
}
state - > memory [ address ] = value ;
}
static uint8_t ReadFromHL ( State8080 * state )
{
uint16_t offset = ( state - > h < < 8 ) | state - > l ;
return state - > memory [ offset ] ;
}
static void WriteToHL ( State8080 * state , uint8_t value )
{
uint16_t offset = ( state - > h < < 8 ) | state - > l ;
WriteMem ( state , offset , value ) ;
}
static void Push ( State8080 * state , uint8_t high , uint8_t low )
{
WriteMem ( state , state - > sp - 1 , high ) ;
WriteMem ( state , state - > sp - 2 , low ) ;
state - > sp = state - > sp - 2 ;
// printf ("%04x %04x\n", state->pc, state->sp);
}
static void Pop ( State8080 * state , uint8_t * high , uint8_t * low )
{
* low = state - > memory [ state - > sp ] ;
* high = state - > memory [ state - > sp + 1 ] ;
state - > sp + = 2 ;
// printf ("%04x %04x pop\n", state->pc, state->sp);
}
static void FlagsZSP ( State8080 * state , uint8_t value )
{
state - > cc . z = ( value = = 0 ) ;
state - > cc . s = ( 0x80 = = ( value & 0x80 ) ) ;
state - > cc . p = parity ( value , 8 ) ;
}
2024-01-14 10:00:05 +00:00
2024-01-06 19:33:56 +00:00
int emulate8080 ( State8080 * state ) {
unsigned char * opcode = & ( state - > memory [ state - > pc ] ) ;
2024-01-20 18:06:47 +00:00
//printf("%04x ", state->pc);
2024-01-08 17:07:28 +00:00
2024-01-20 18:06:47 +00:00
//disassemble8080(opcode);
2024-01-08 17:07:28 +00:00
state - > pc + + ;
2024-01-07 12:32:22 +00:00
2024-01-06 19:33:56 +00:00
switch ( * opcode ) {
2024-01-20 18:06:47 +00:00
case 0x00 : break ; //NOP
case 0x01 : //LXI B,word
state - > c = opcode [ 1 ] ;
state - > b = opcode [ 2 ] ;
state - > pc + = 2 ;
break ;
case 0x02 : //STAX B
{
uint16_t offset = ( state - > b < < 8 ) | state - > c ;
WriteMem ( state , offset , state - > a ) ;
}
break ;
case 0x03 : //INX B
state - > c + + ;
if ( state - > c = = 0 )
state - > b + + ;
break ;
case 0x04 : //INR B
state - > b + = 1 ;
FlagsZSP ( state , state - > b ) ;
break ;
case 0x05 : //DCR B
state - > b - = 1 ;
FlagsZSP ( state , state - > b ) ;
break ;
case 0x06 : //MVI B,byte
state - > b = opcode [ 1 ] ;
state - > pc + + ;
break ;
case 0x07 : //RLC
{
uint8_t x = state - > a ;
state - > a = ( ( x & 0x80 ) > > 7 ) | ( x < < 1 ) ;
state - > cc . cy = ( 0x80 = = ( x & 0x80 ) ) ;
}
break ;
case 0x08 : UnimplementedInstruction ( state ) ; break ;
case 0x09 : //DAD B
{
uint32_t hl = ( state - > h < < 8 ) | state - > l ;
uint32_t bc = ( state - > b < < 8 ) | state - > c ;
uint32_t res = hl + bc ;
state - > h = ( res & 0xff00 ) > > 8 ;
state - > l = res & 0xff ;
state - > cc . cy = ( ( res & 0xffff0000 ) ! = 0 ) ;
}
break ;
case 0x0a : //LDAX B
{
uint16_t offset = ( state - > b < < 8 ) | state - > c ;
state - > a = state - > memory [ offset ] ;
}
break ;
case 0x0b : //DCX B
state - > c - = 1 ;
if ( state - > c = = 0xff )
state - > b - = 1 ;
break ;
case 0x0c : //INR C
state - > c + = 1 ;
FlagsZSP ( state , state - > c ) ;
break ;
case 0x0d : //DCR C
state - > c - = 1 ;
FlagsZSP ( state , state - > c ) ;
break ;
case 0x0e : //MVI C,byte
state - > c = opcode [ 1 ] ;
state - > pc + + ;
break ;
case 0x0f : //RRC
{
uint8_t x = state - > a ;
state - > a = ( ( x & 1 ) < < 7 ) | ( x > > 1 ) ;
state - > cc . cy = ( 1 = = ( x & 1 ) ) ;
}
break ;
case 0x10 : UnimplementedInstruction ( state ) ; break ;
case 0x11 : //LXI D,word
state - > e = opcode [ 1 ] ;
state - > d = opcode [ 2 ] ;
state - > pc + = 2 ;
break ;
case 0x12 : //STAX D
{
uint16_t offset = ( state - > d < < 8 ) | state - > e ;
WriteMem ( state , offset , state - > a ) ;
}
break ;
case 0x13 : //INX D
state - > e + + ;
if ( state - > e = = 0 )
state - > d + + ;
break ;
case 0x14 : //INR D
state - > d + = 1 ;
FlagsZSP ( state , state - > d ) ;
break ;
case 0x15 : //DCR D
state - > d - = 1 ;
FlagsZSP ( state , state - > d ) ;
break ;
case 0x16 : //MVI D,byte
state - > d = opcode [ 1 ] ;
state - > pc + + ;
break ;
case 0x17 : //RAL
{
uint8_t x = state - > a ;
state - > a = state - > cc . cy | ( x < < 1 ) ;
state - > cc . cy = ( 0x80 = = ( x & 0x80 ) ) ;
}
break ;
case 0x18 : UnimplementedInstruction ( state ) ; break ;
case 0x19 : //DAD D
{
uint32_t hl = ( state - > h < < 8 ) | state - > l ;
uint32_t de = ( state - > d < < 8 ) | state - > e ;
uint32_t res = hl + de ;
state - > h = ( res & 0xff00 ) > > 8 ;
state - > l = res & 0xff ;
state - > cc . cy = ( ( res & 0xffff0000 ) ! = 0 ) ;
}
break ;
case 0x1a : //LDAX D
{
uint16_t offset = ( state - > d < < 8 ) | state - > e ;
state - > a = state - > memory [ offset ] ;
}
break ;
case 0x1b : //DCX D
state - > e - = 1 ;
if ( state - > e = = 0xff )
state - > d - = 1 ;
break ;
case 0x1c : //INR E
state - > e + = 1 ;
FlagsZSP ( state , state - > e ) ;
break ;
case 0x1d : //DCR E
state - > e - = 1 ;
FlagsZSP ( state , state - > e ) ;
break ;
case 0x1e : //MVI E,byte
state - > e = opcode [ 1 ] ;
state - > pc + + ;
break ;
case 0x1f : //RAR
{
uint8_t x = state - > a ;
state - > a = ( state - > cc . cy < < 7 ) | ( x > > 1 ) ;
state - > cc . cy = ( 1 = = ( x & 1 ) ) ;
}
break ;
case 0x20 : UnimplementedInstruction ( state ) ; break ;
case 0x21 : //LXI H,word
state - > l = opcode [ 1 ] ;
state - > h = opcode [ 2 ] ;
state - > pc + = 2 ;
break ;
case 0x22 : //SHLD
{
uint16_t offset = opcode [ 1 ] | ( opcode [ 2 ] < < 8 ) ;
WriteMem ( state , offset , state - > l ) ;
WriteMem ( state , offset + 1 , state - > h ) ;
2024-01-06 19:33:56 +00:00
state - > pc + = 2 ;
2024-01-20 18:06:47 +00:00
}
break ;
case 0x23 : //INX H
state - > l + + ;
if ( state - > l = = 0 )
state - > h + + ;
break ;
case 0x24 : //INR H
state - > h + = 1 ;
FlagsZSP ( state , state - > h ) ;
break ;
case 0x25 : //DCR H
state - > h - = 1 ;
FlagsZSP ( state , state - > h ) ;
break ;
case 0x26 : //MVI H,byte
state - > h = opcode [ 1 ] ;
state - > pc + + ;
break ;
case 0x27 :
if ( ( state - > a & 0xf ) > 9 )
state - > a + = 6 ;
if ( ( state - > a & 0xf0 ) > 0x90 )
2024-01-15 23:20:20 +00:00
{
2024-01-20 18:06:47 +00:00
uint16_t res = ( uint16_t ) state - > a + 0x60 ;
state - > a = res & 0xff ;
ArithFlagsA ( state , res ) ;
2024-01-15 23:20:20 +00:00
}
break ;
2024-01-20 18:06:47 +00:00
case 0x28 : UnimplementedInstruction ( state ) ; break ;
case 0x29 : //DAD H
{
uint32_t hl = ( state - > h < < 8 ) | state - > l ;
uint32_t res = hl + hl ;
state - > h = ( res & 0xff00 ) > > 8 ;
state - > l = res & 0xff ;
state - > cc . cy = ( ( res & 0xffff0000 ) ! = 0 ) ;
}
break ;
case 0x2a : //LHLD adr
{
uint16_t offset = opcode [ 1 ] | ( opcode [ 2 ] < < 8 ) ;
state - > l = state - > memory [ offset ] ;
state - > h = state - > memory [ offset + 1 ] ;
2024-01-07 12:32:22 +00:00
state - > pc + = 2 ;
2024-01-20 18:06:47 +00:00
}
break ;
case 0x2b : //DCX H
state - > l - = 1 ;
if ( state - > l = = 0xff )
state - > h - = 1 ;
break ;
case 0x2c : //INR L
state - > l + = 1 ;
FlagsZSP ( state , state - > l ) ;
break ;
case 0x2d : //DCR L
state - > l - = 1 ;
FlagsZSP ( state , state - > l ) ;
break ;
case 0x2e : //MVI L,byte
state - > l = opcode [ 1 ] ;
state - > pc + + ;
break ;
case 0x2f :
state - > a = ~ state - > a ; //CMA
break ;
case 0x30 : UnimplementedInstruction ( state ) ; break ;
case 0x31 : //LXI SP,word
state - > sp = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
state - > pc + = 2 ;
break ;
case 0x32 : //STA (word)
{
uint16_t offset = ( opcode [ 2 ] < < 8 ) | ( opcode [ 1 ] ) ;
WriteMem ( state , offset , state - > a ) ;
state - > pc + = 2 ;
}
break ;
case 0x33 : //INX SP
state - > sp + + ;
break ;
case 0x34 : //INR M
{
uint8_t res = ReadFromHL ( state ) + 1 ;
FlagsZSP ( state , res ) ;
WriteToHL ( state , res ) ;
}
break ;
case 0x35 : //DCR M
{
uint8_t res = ReadFromHL ( state ) - 1 ;
FlagsZSP ( state , res ) ;
WriteToHL ( state , res ) ;
}
break ;
case 0x36 : //MVI M,byte
{
WriteToHL ( state , opcode [ 1 ] ) ;
state - > pc + + ;
}
break ;
case 0x37 : state - > cc . cy = 1 ; break ;
case 0x38 : UnimplementedInstruction ( state ) ; break ;
case 0x39 : //DAD SP
{
uint32_t hl = ( state - > h < < 8 ) | state - > l ;
uint32_t res = hl + state - > sp ;
state - > h = ( res & 0xff00 ) > > 8 ;
state - > l = res & 0xff ;
state - > cc . cy = ( ( res & 0xffff0000 ) > 0 ) ;
}
break ;
case 0x3a : //LDA (word)
{
uint16_t offset = ( opcode [ 2 ] < < 8 ) | ( opcode [ 1 ] ) ;
state - > a = state - > memory [ offset ] ;
state - > pc + = 2 ;
}
break ;
case 0x3b : //DCX SP
state - > sp - = 1 ;
break ;
case 0x3c : //INR A
state - > a + = 1 ;
FlagsZSP ( state , state - > a ) ;
break ;
case 0x3d : //DCR A
state - > a - = 1 ;
FlagsZSP ( state , state - > a ) ;
break ;
case 0x3e : //MVI A,byte
state - > a = opcode [ 1 ] ;
state - > pc + + ;
break ;
case 0x3f : state - > cc . cy = 0 ; break ;
case 0x40 : state - > b = state - > b ; break ;
case 0x41 : state - > b = state - > c ; break ;
case 0x42 : state - > b = state - > d ; break ;
case 0x43 : state - > b = state - > e ; break ;
case 0x44 : state - > b = state - > h ; break ;
case 0x45 : state - > b = state - > l ; break ;
case 0x46 : state - > b = ReadFromHL ( state ) ; break ;
case 0x47 : state - > b = state - > a ; break ;
2024-01-15 23:20:20 +00:00
2024-01-20 18:06:47 +00:00
case 0x48 : state - > c = state - > b ; break ;
case 0x49 : state - > c = state - > c ; break ;
case 0x4a : state - > c = state - > d ; break ;
case 0x4b : state - > c = state - > e ; break ;
case 0x4c : state - > c = state - > h ; break ;
case 0x4d : state - > c = state - > l ; break ;
case 0x4e : state - > c = ReadFromHL ( state ) ; break ;
case 0x4f : state - > c = state - > a ; break ;
case 0x50 : state - > d = state - > b ; break ;
case 0x51 : state - > d = state - > c ; break ;
case 0x52 : state - > d = state - > d ; break ;
case 0x53 : state - > d = state - > e ; break ;
case 0x54 : state - > d = state - > h ; break ;
case 0x55 : state - > d = state - > l ; break ;
case 0x56 : state - > d = ReadFromHL ( state ) ; break ;
case 0x57 : state - > d = state - > a ; break ;
case 0x58 : state - > e = state - > b ; break ;
case 0x59 : state - > e = state - > c ; break ;
case 0x5a : state - > e = state - > d ; break ;
case 0x5b : state - > e = state - > e ; break ;
case 0x5c : state - > e = state - > h ; break ;
case 0x5d : state - > e = state - > l ; break ;
case 0x5e : state - > e = ReadFromHL ( state ) ; break ;
case 0x5f : state - > e = state - > a ; break ;
case 0x60 : state - > h = state - > b ; break ;
case 0x61 : state - > h = state - > c ; break ;
case 0x62 : state - > h = state - > d ; break ;
case 0x63 : state - > h = state - > e ; break ;
case 0x64 : state - > h = state - > h ; break ;
case 0x65 : state - > h = state - > l ; break ;
case 0x66 : state - > h = ReadFromHL ( state ) ; break ;
case 0x67 : state - > h = state - > a ; break ;
case 0x68 : state - > l = state - > b ; break ;
case 0x69 : state - > l = state - > c ; break ;
case 0x6a : state - > l = state - > d ; break ;
case 0x6b : state - > l = state - > e ; break ;
case 0x6c : state - > l = state - > h ; break ;
case 0x6d : state - > l = state - > l ; break ;
case 0x6e : state - > l = ReadFromHL ( state ) ; break ;
case 0x6f : state - > l = state - > a ; break ;
case 0x70 : WriteToHL ( state , state - > b ) ; break ; //MOV M,B
case 0x71 : WriteToHL ( state , state - > c ) ; break ; //MOV M,C
case 0x72 : WriteToHL ( state , state - > d ) ; break ; //MOV M,D
case 0x73 : WriteToHL ( state , state - > e ) ; break ; //MOV M,E
case 0x74 : WriteToHL ( state , state - > h ) ; break ; //MOV M,H
case 0x75 : WriteToHL ( state , state - > l ) ; break ; //MOV M,L
case 0x76 : break ; //HLT
case 0x77 : WriteToHL ( state , state - > a ) ; break ; //MOV M,A
case 0x78 : state - > a = state - > b ; break ;
case 0x79 : state - > a = state - > c ; break ;
case 0x7a : state - > a = state - > d ; break ;
case 0x7b : state - > a = state - > e ; break ;
case 0x7c : state - > a = state - > h ; break ;
case 0x7d : state - > a = state - > l ; break ;
case 0x7e : state - > a = ReadFromHL ( state ) ; break ;
case 0x7f : break ;
case 0x80 : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > b ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADD B
case 0x81 : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > c ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADD C
case 0x82 : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > d ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADD D
case 0x83 : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > e ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADD E
case 0x84 : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > h ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADD H
case 0x85 : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > l ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADD L
case 0x86 : //ADD M
{
uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) ReadFromHL ( state ) ;
ArithFlagsA ( state , res ) ;
state - > a = ( res & 0xff ) ;
} break ;
case 0x87 : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > a ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADC A
case 0x88 : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > b + state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADC B
case 0x89 : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > c + state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADC C
case 0x8a : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > d + state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADC D
case 0x8b : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > e + state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADC E
case 0x8c : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > h + state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADC H
case 0x8d : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > l + state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADC L
case 0x8e : //ADC M
{
uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) ReadFromHL ( state ) + state - > cc . cy ;
ArithFlagsA ( state , res ) ;
state - > a = ( res & 0xff ) ;
} break ;
case 0x8f : { uint16_t res = ( uint16_t ) state - > a + ( uint16_t ) state - > a + state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //ADC A
case 0x90 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > b ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SUB B
case 0x91 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > c ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SUB C
case 0x92 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > d ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SUB D
case 0x93 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > e ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SUB E
case 0x94 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > h ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SUB H
case 0x95 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > l ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SUB L
case 0x96 : //SUB M
{
uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) ReadFromHL ( state ) ;
ArithFlagsA ( state , res ) ;
state - > a = ( res & 0xff ) ;
} break ;
case 0x97 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > a ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SUB A
case 0x98 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > b - state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SBB B
case 0x99 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > c - state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SBB C
case 0x9a : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > d - state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SBB D
case 0x9b : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > e - state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SBB E
case 0x9c : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > h - state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SBB H
case 0x9d : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > l - state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SBB L
case 0x9e : //SBB M
{
uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) ReadFromHL ( state ) - state - > cc . cy ;
ArithFlagsA ( state , res ) ;
state - > a = ( res & 0xff ) ;
} break ;
case 0x9f : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > a - state - > cc . cy ; ArithFlagsA ( state , res ) ; state - > a = ( res & 0xff ) ; } break ; //SBB A
case 0xa0 : state - > a = state - > a & state - > b ; LogicFlagsA ( state ) ; break ;
case 0xa1 : state - > a = state - > a & state - > c ; LogicFlagsA ( state ) ; break ;
case 0xa2 : state - > a = state - > a & state - > d ; LogicFlagsA ( state ) ; break ;
case 0xa3 : state - > a = state - > a & state - > e ; LogicFlagsA ( state ) ; break ;
case 0xa4 : state - > a = state - > a & state - > h ; LogicFlagsA ( state ) ; break ;
case 0xa5 : state - > a = state - > a & state - > l ; LogicFlagsA ( state ) ; break ;
case 0xa6 : state - > a = state - > a & ReadFromHL ( state ) ; LogicFlagsA ( state ) ; break ;
case 0xa7 : state - > a = state - > a & state - > a ; LogicFlagsA ( state ) ; break ;
case 0xa8 : state - > a = state - > a ^ state - > b ; LogicFlagsA ( state ) ; break ;
case 0xa9 : state - > a = state - > a ^ state - > c ; LogicFlagsA ( state ) ; break ;
case 0xaa : state - > a = state - > a ^ state - > d ; LogicFlagsA ( state ) ; break ;
case 0xab : state - > a = state - > a ^ state - > e ; LogicFlagsA ( state ) ; break ;
case 0xac : state - > a = state - > a ^ state - > h ; LogicFlagsA ( state ) ; break ;
case 0xad : state - > a = state - > a ^ state - > l ; LogicFlagsA ( state ) ; break ;
case 0xae : state - > a = state - > a ^ ReadFromHL ( state ) ; LogicFlagsA ( state ) ; break ;
case 0xaf : state - > a = state - > a ^ state - > a ; LogicFlagsA ( state ) ; break ;
case 0xb0 : state - > a = state - > a | state - > b ; LogicFlagsA ( state ) ; break ;
case 0xb1 : state - > a = state - > a | state - > c ; LogicFlagsA ( state ) ; break ;
case 0xb2 : state - > a = state - > a | state - > d ; LogicFlagsA ( state ) ; break ;
case 0xb3 : state - > a = state - > a | state - > e ; LogicFlagsA ( state ) ; break ;
case 0xb4 : state - > a = state - > a | state - > h ; LogicFlagsA ( state ) ; break ;
case 0xb5 : state - > a = state - > a | state - > l ; LogicFlagsA ( state ) ; break ;
case 0xb6 : state - > a = state - > a | ReadFromHL ( state ) ; LogicFlagsA ( state ) ; break ;
case 0xb7 : state - > a = state - > a | state - > a ; LogicFlagsA ( state ) ; break ;
case 0xb8 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > b ; ArithFlagsA ( state , res ) ; } break ; //CMP B
case 0xb9 : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > c ; ArithFlagsA ( state , res ) ; } break ; //CMP C
case 0xba : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > d ; ArithFlagsA ( state , res ) ; } break ; //CMP D
case 0xbb : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > e ; ArithFlagsA ( state , res ) ; } break ; //CMP E
case 0xbc : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > h ; ArithFlagsA ( state , res ) ; } break ; //CMP H
case 0xbd : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > l ; ArithFlagsA ( state , res ) ; } break ; //CMP L
case 0xbe : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) ReadFromHL ( state ) ; ArithFlagsA ( state , res ) ; } break ; //CMP L
case 0xbf : { uint16_t res = ( uint16_t ) state - > a - ( uint16_t ) state - > a ; ArithFlagsA ( state , res ) ; } break ; //CMP A
case 0xc0 : //RNZ
if ( state - > cc . z = = 0 )
{
state - > pc = state - > memory [ state - > sp ] | ( state - > memory [ state - > sp + 1 ] < < 8 ) ;
state - > sp + = 2 ;
}
break ;
case 0xc1 : //POP B
Pop ( state , & state - > b , & state - > c ) ;
break ;
case 0xc2 : //JNZ address
if ( 0 = = state - > cc . z )
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
else
state - > pc + = 2 ;
break ;
case 0xc3 : //JMP address
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
break ;
case 0xc4 : //CNZ adr
if ( state - > cc . z = = 0 )
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
}
else
state - > pc + = 2 ;
break ;
case 0xc5 : //PUSH B
Push ( state , state - > b , state - > c ) ;
break ;
case 0xc6 : //ADI byte
{
uint16_t x = ( uint16_t ) state - > a + ( uint16_t ) opcode [ 1 ] ;
FlagsZSP ( state , x & 0xff ) ;
state - > cc . cy = ( x > 0xff ) ;
state - > a = x & 0xff ;
state - > pc + + ;
}
break ;
case 0xc7 : //RST 0
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = 0x0000 ;
}
break ;
case 0xc8 : //RZ
if ( state - > cc . z )
{
state - > pc = state - > memory [ state - > sp ] | ( state - > memory [ state - > sp + 1 ] < < 8 ) ;
state - > sp + = 2 ;
}
break ;
case 0xc9 : //RET
state - > pc = state - > memory [ state - > sp ] | ( state - > memory [ state - > sp + 1 ] < < 8 ) ;
state - > sp + = 2 ;
break ;
case 0xca : //JZ adr
if ( state - > cc . z )
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
else
state - > pc + = 2 ;
break ;
case 0xcb : UnimplementedInstruction ( state ) ; break ;
case 0xcc : //CZ adr
if ( state - > cc . z = = 1 )
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
2024-01-19 19:20:17 +00:00
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
2024-01-20 18:06:47 +00:00
}
else
state - > pc + = 2 ;
break ;
case 0xcd : //CALL address
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
}
break ;
case 0xce : //ACI byte
{
uint16_t x = state - > a + opcode [ 1 ] + state - > cc . cy ;
FlagsZSP ( state , x & 0xff ) ;
state - > cc . cy = ( x > 0xff ) ;
state - > a = x & 0xff ;
state - > pc + + ;
}
break ;
case 0xcf : //RST 1
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = 0x0008 ;
}
break ;
case 0xd0 : //RNC
if ( state - > cc . cy = = 0 )
{
state - > pc = state - > memory [ state - > sp ] | ( state - > memory [ state - > sp + 1 ] < < 8 ) ;
state - > sp + = 2 ;
}
break ;
case 0xd1 : //POP D
Pop ( state , & state - > d , & state - > e ) ;
break ;
case 0xd2 : //JNC
if ( state - > cc . cy = = 0 )
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
else
state - > pc + = 2 ;
break ;
case 0xd3 : //OUT d8
machineOut ( state , opcode [ 1 ] , state - > a ) ;
state - > pc + + ;
break ;
case 0xd4 : //CNC adr
if ( state - > cc . cy = = 0 )
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
}
else
state - > pc + = 2 ;
break ;
case 0xd5 : //PUSH D
Push ( state , state - > d , state - > e ) ;
break ;
case 0xd6 : //SUI byte
{
uint8_t x = state - > a - opcode [ 1 ] ;
FlagsZSP ( state , x & 0xff ) ;
state - > cc . cy = ( state - > a < opcode [ 1 ] ) ;
state - > a = x ;
state - > pc + + ;
}
break ;
case 0xd7 : //RST 2
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = 0x10 ;
}
break ;
case 0xd8 : //RC
if ( state - > cc . cy ! = 0 )
{
state - > pc = state - > memory [ state - > sp ] | ( state - > memory [ state - > sp + 1 ] < < 8 ) ;
state - > sp + = 2 ;
}
break ;
case 0xd9 : UnimplementedInstruction ( state ) ; break ;
case 0xda : //JC
if ( state - > cc . cy ! = 0 )
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
else
state - > pc + = 2 ;
break ;
case 0xdb : //IN d8
state - > a = machineIn ( state , opcode [ 1 ] ) ; //Check if this works
state - > pc + + ;
break ;
case 0xdc : //CC adr
if ( state - > cc . cy ! = 0 )
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
}
else
state - > pc + = 2 ;
break ;
case 0xdd : UnimplementedInstruction ( state ) ; break ;
case 0xde : //SBI byte
{
uint16_t x = state - > a - opcode [ 1 ] - state - > cc . cy ;
FlagsZSP ( state , x & 0xff ) ;
state - > cc . cy = ( x > 0xff ) ;
state - > a = x & 0xff ;
state - > pc + + ;
}
break ;
case 0xdf : //RST 3
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = 0x18 ;
}
break ;
case 0xe0 : //RPO
if ( state - > cc . p = = 0 )
2024-01-20 11:31:11 +00:00
{
state - > pc = state - > memory [ state - > sp ] | ( state - > memory [ state - > sp + 1 ] < < 8 ) ;
state - > sp + = 2 ;
}
break ;
2024-01-20 18:06:47 +00:00
case 0xe1 : //POP H
Pop ( state , & state - > h , & state - > l ) ;
break ;
case 0xe2 : //JPO
if ( state - > cc . p = = 0 )
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
else
state - > pc + = 2 ;
break ;
case 0xe3 : //XTHL
{
uint8_t h = state - > h ;
uint8_t l = state - > l ;
2024-01-07 12:32:22 +00:00
state - > l = state - > memory [ state - > sp ] ;
2024-01-20 18:06:47 +00:00
state - > h = state - > memory [ state - > sp + 1 ] ;
WriteMem ( state , state - > sp , l ) ;
WriteMem ( state , state - > sp + 1 , h ) ;
}
2024-01-19 19:20:17 +00:00
break ;
2024-01-20 18:06:47 +00:00
case 0xe4 : //CPO adr
if ( state - > cc . p = = 0 )
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
2024-01-19 19:20:17 +00:00
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
2024-01-20 18:06:47 +00:00
}
2024-01-19 19:20:17 +00:00
else
state - > pc + = 2 ;
break ;
2024-01-20 18:06:47 +00:00
case 0xe5 : //PUSH H
Push ( state , state - > h , state - > l ) ;
break ;
case 0xe6 : //ANI byte
{
state - > a = state - > a & opcode [ 1 ] ;
LogicFlagsA ( state ) ;
state - > pc + + ;
}
break ;
case 0xe7 : //RST 4
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = 0x20 ;
}
break ;
case 0xe8 : //RPE
if ( state - > cc . p ! = 0 )
2024-01-20 11:31:11 +00:00
{
state - > pc = state - > memory [ state - > sp ] | ( state - > memory [ state - > sp + 1 ] < < 8 ) ;
state - > sp + = 2 ;
}
break ;
2024-01-20 18:06:47 +00:00
case 0xe9 : //PCHL
state - > pc = ( state - > h < < 8 ) | state - > l ;
2024-01-20 11:31:11 +00:00
break ;
2024-01-20 18:06:47 +00:00
case 0xea : //JPE
if ( state - > cc . p ! = 0 )
2024-01-20 11:31:11 +00:00
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
else
state - > pc + = 2 ;
2024-01-20 18:06:47 +00:00
break ;
case 0xeb : //XCHG
{
uint8_t save1 = state - > d ;
uint8_t save2 = state - > e ;
state - > d = state - > h ;
state - > e = state - > l ;
state - > h = save1 ;
state - > l = save2 ;
}
2024-01-20 11:31:11 +00:00
break ;
2024-01-20 18:06:47 +00:00
case 0xec : //CPE adr
if ( state - > cc . p ! = 0 )
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
}
else
state - > pc + = 2 ;
break ;
case 0xed : UnimplementedInstruction ( state ) ; break ;
case 0xee : //XRI data
{
uint8_t x = state - > a ^ opcode [ 1 ] ;
FlagsZSP ( state , x ) ;
state - > cc . cy = 0 ; //data book says clear cy
state - > a = x ;
state - > pc + + ;
}
break ;
case 0xef : //RST 5
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = 0x28 ;
}
break ;
case 0xf0 : //RP
if ( state - > cc . s = = 0 )
{
state - > pc = state - > memory [ state - > sp ] | ( state - > memory [ state - > sp + 1 ] < < 8 ) ;
state - > sp + = 2 ;
}
break ;
case 0xf1 : //POP PSW
Pop ( state , & state - > a , ( unsigned char * ) & state - > cc ) ;
break ;
case 0xf2 :
if ( state - > cc . s = = 0 )
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
else
state - > pc + = 2 ;
break ;
case 0xf3 : state - > int_enable = 0 ; break ;
case 0xf4 : //CP
if ( state - > cc . s = = 0 )
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
}
else
state - > pc + = 2 ;
break ;
case 0xf5 : //PUSH PSW
Push ( state , state - > a , * ( unsigned char * ) & state - > cc ) ;
break ;
case 0xf6 : //ORI byte
{
//AC set if lower nibble of h was zero prior to dec
uint8_t x = state - > a | opcode [ 1 ] ;
FlagsZSP ( state , x ) ;
state - > cc . cy = 0 ;
state - > a = x ;
state - > pc + + ;
}
break ;
case 0xf7 : //RST 6
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = 0x30 ;
}
break ;
case 0xf8 : //RM
if ( state - > cc . s ! = 0 )
{
state - > pc = state - > memory [ state - > sp ] | ( state - > memory [ state - > sp + 1 ] < < 8 ) ;
state - > sp + = 2 ;
}
break ;
case 0xf9 : //SPHL
state - > sp = state - > l | ( state - > h < < 8 ) ;
break ;
case 0xfa : //JM
if ( state - > cc . s ! = 0 )
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
else
state - > pc + = 2 ;
break ;
case 0xfb : state - > int_enable = 1 ; break ;
case 0xfc : //CM
if ( state - > cc . s ! = 0 )
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = ( opcode [ 2 ] < < 8 ) | opcode [ 1 ] ;
}
else
state - > pc + = 2 ;
break ;
case 0xfd : UnimplementedInstruction ( state ) ; break ;
case 0xfe : //CPI byte
{
uint8_t x = state - > a - opcode [ 1 ] ;
FlagsZSP ( state , x ) ;
state - > cc . cy = ( state - > a < opcode [ 1 ] ) ;
state - > pc + + ;
}
break ;
case 0xff : //RST 7
{
uint16_t ret = state - > pc + 2 ;
WriteMem ( state , state - > sp - 1 , ( ret > > 8 ) & 0xff ) ;
WriteMem ( state , state - > sp - 2 , ( ret & 0xff ) ) ;
state - > sp = state - > sp - 2 ;
state - > pc = 0x38 ;
}
break ;
default : UnimplementedInstruction ( state ) ; break ;
2024-01-06 19:33:56 +00:00
}
2024-01-20 18:06:47 +00:00
//printState(state);
2024-01-14 16:50:35 +00:00
return cycles8080 [ * opcode ] ;
2024-01-07 12:32:22 +00:00
}
2024-01-14 12:26:06 +00:00
void generateInterrupt ( State8080 * state , int interrupt_num )
2024-01-14 10:00:05 +00:00
{
2024-01-14 12:26:06 +00:00
//perform "PUSH PC"
state - > memory [ state - > sp - 1 ] = ( ( state - > pc & 0xFF00 ) > > 8 ) ;
state - > memory [ state - > sp - 2 ] = ( state - > pc & 0xff ) ;
state - > sp - = 2 ;
2024-01-14 10:00:05 +00:00
//Set the PC to the low memory vector.
2024-01-14 12:26:06 +00:00
state - > pc = 8 * interrupt_num ;
state - > int_enable = 0 ;
2024-01-14 10:00:05 +00:00
}
2024-01-08 17:07:28 +00:00
void read_Space_Invaders_ROM ( State8080 * state , const char * filename , int offset ) {
//Works exclusively with the memory system of Space Invaders
FILE * file = fopen ( filename , " rb " ) ;
if ( file = = NULL ) {
printf ( " Issue opening the file. \n " ) ;
exit ( 1 ) ;
2024-01-07 12:32:22 +00:00
}
2024-01-08 17:07:28 +00:00
//Get the file size and read it into a memory buffer
fseek ( file , 0L , SEEK_END ) ;
int fsize = ftell ( file ) ;
fseek ( file , 0L , SEEK_SET ) ;
uint8_t * buffer = & state - > memory [ offset ] ;
fread ( buffer , fsize , 1 , file ) ;
fclose ( file ) ;
2024-01-13 21:38:02 +00:00
}
2024-01-08 17:07:28 +00:00
2024-01-15 13:06:04 +00:00
typedef struct cpu_data {
char done ;
int total_cycles_count ;
GtkWidget * drawing_area ;
State8080 * state ;
2024-01-14 21:35:01 +00:00
2024-01-15 13:06:04 +00:00
} cpu_data ;
2024-01-14 21:35:01 +00:00
2024-01-19 21:45:49 +00:00
void * cpu ( void * arg ) {
cpu_data * cpu = ( cpu_data * ) arg ;
char done = cpu - > done ;
State8080 * state = cpu - > state ;
int counter ;
2024-01-14 21:35:01 +00:00
2024-01-20 18:06:47 +00:00
sleep ( 2 ) ;
2024-01-19 21:45:49 +00:00
while ( ! done ) {
counter = emulate8080 ( cpu - > state ) ;
cpu - > total_cycles_count + = counter ;
printf ( " Total cycles: %d \n " , cpu - > total_cycles_count ) ;
2024-01-20 18:06:47 +00:00
//usleep(1); // EMULATION OF THE PROCESSOR ŠPEED
2024-01-19 21:45:49 +00:00
if ( ( cpu - > total_cycles_count > 16000 ) & & ( state - > int_enable ) ) //1/60 second has elapsed
{
//redraw screen() will be handeled by the gtk_main() function
if ( which_interrupt = = 2 ) {
generateInterrupt ( state , 2 ) ; //interrupt 2
cpu - > total_cycles_count = 0 ;
which_interrupt = 1 ;
} else {
generateInterrupt ( state , 1 ) ; //interrupt 1
cpu - > total_cycles_count = 0 ;
which_interrupt = 2 ;
}
}
}
}
2024-01-19 19:20:17 +00:00
2024-01-20 18:06:47 +00:00
//===== GTK GRAPHICS =====
2024-01-19 19:20:17 +00:00
static void draw_callback ( GtkWidget * widget , cairo_t * cr , gpointer user_data ) {
2024-01-20 11:31:11 +00:00
// Clear the drawing area if you want
//cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
//cairo_paint(cr);
2024-01-19 19:20:17 +00:00
for ( int i = 0 ; i < 224 ; i + + ) {
for ( int j = 0 ; j < 32 ; j + + ) {
uint8_t byte = bitmap [ i * 32 + j ] ;
for ( int p = 0 ; p < 8 ; p + + ) {
int pixel = ( byte > > p ) & 1 ; // flip the bit order within each byte
int x = i ; // swap x and y
int y = 255 - ( j * 8 + p ) ; // flip the y-coordinate
if ( x > = 0 & & x < 256 & & y > = 0 & & y < 256 ) { // Check bounds
2024-01-20 18:06:47 +00:00
if ( pixel ) {
cairo_set_source_rgb ( cr , 1.0 , 1.0 , 1.0 ) ; // Set color to white
} else {
cairo_set_source_rgb ( cr , 0.0 , 0.0 , 0.0 ) ; // Set color to black
}
cairo_rectangle ( cr , x * upscaleFactor , y * upscaleFactor , upscaleFactor , upscaleFactor ) ;
cairo_fill ( cr ) ;
2024-01-19 19:20:17 +00:00
}
2024-01-15 20:15:53 +00:00
}
}
}
2024-01-15 13:06:04 +00:00
}
2024-01-14 21:35:01 +00:00
2024-01-19 21:45:49 +00:00
void on_about_clicked ( GtkToolButton * toolbutton , gpointer user_data ) {
GtkWidget * dialog = gtk_about_dialog_new ( ) ;
2024-01-20 18:06:47 +00:00
GtkWidget * image = gtk_image_new_from_file ( " space.png " ) ;
GtkWidget * box = gtk_box_new ( GTK_ORIENTATION_VERTICAL , 5 ) ;
gtk_box_pack_start ( GTK_BOX ( box ) , image , TRUE , TRUE , 0 ) ;
2024-01-20 11:31:11 +00:00
gtk_about_dialog_set_program_name ( GTK_ABOUT_DIALOG ( dialog ) , " Lux8080-Emulator " ) ;
gtk_about_dialog_set_comments ( GTK_ABOUT_DIALOG ( dialog ) , " This is a simple Intel 8080-Emulator for Space Invaders using C and GTK. Following the guide of @realemulator101 " ) ;
2024-01-20 18:06:47 +00:00
gtk_about_dialog_set_logo_icon_name ( GTK_ABOUT_DIALOG ( dialog ) , " 8080.ico " ) ;
GtkWidget * content_area = gtk_dialog_get_content_area ( GTK_DIALOG ( dialog ) ) ;
gtk_box_pack_start ( GTK_BOX ( content_area ) , box , TRUE , TRUE , 0 ) ;
gtk_widget_show_all ( box ) ;
2024-01-19 21:45:49 +00:00
gtk_dialog_run ( GTK_DIALOG ( dialog ) ) ;
gtk_widget_destroy ( dialog ) ;
2024-01-14 21:35:01 +00:00
}
2024-01-20 18:06:47 +00:00
2024-01-19 19:20:17 +00:00
gboolean update_ui ( gpointer data ) {
// Seems like GTK is not thread safe
// we fix it with update_ui using gtk_main_iteration_do(FALSE)
GtkWidget * drawing_area = ( GtkWidget * ) data ;
gtk_widget_queue_draw ( drawing_area ) ;
while ( gtk_events_pending ( ) )
gtk_main_iteration_do ( FALSE ) ;
return TRUE ;
}
2024-01-19 21:45:49 +00:00
void on_size_changed ( GtkComboBox * combo_box , gpointer user_data ) {
gchar * text = gtk_combo_box_text_get_active_text ( GTK_COMBO_BOX_TEXT ( combo_box ) ) ;
if ( g_strcmp0 ( text , " 1x " ) = = 0 ) {
upscaleFactor = 1 ;
} else if ( g_strcmp0 ( text , " 2x " ) = = 0 ) {
upscaleFactor = 2 ;
} else if ( g_strcmp0 ( text , " 3x " ) = = 0 ) {
upscaleFactor = 3 ;
}
g_free ( text ) ;
}
2024-01-20 18:06:47 +00:00
gboolean close_splash_screen ( gpointer data ) {
GtkWidget * splash_screen = ( GtkWidget * ) data ;
gtk_widget_hide ( splash_screen ) ;
return FALSE ;
}
gboolean open_screen ( gpointer data ) {
GtkWidget * window = ( GtkWidget * ) data ;
gtk_widget_show_all ( window ) ;
return FALSE ;
}
2024-01-19 21:45:49 +00:00
2024-01-14 19:45:36 +00:00
int main ( int argc , char * argv [ ] ) {
2024-01-19 19:20:17 +00:00
// Emulator init
2024-01-07 12:32:22 +00:00
2024-01-14 12:26:06 +00:00
State8080 * state = ( State8080 * ) calloc ( 1 , sizeof ( State8080 ) ) ; //memset obsolte with calloc
2024-01-08 17:07:28 +00:00
state - > cc . z = 1 ;
state - > cc . s = 1 ;
state - > cc . p = 1 ;
state - > cc . cy = 0 ;
2024-01-15 23:20:20 +00:00
state - > cc . ac = 1 ;
state - > int_enable = 1 ;
2024-01-07 12:32:22 +00:00
state - > pc = 0 ;
2024-01-19 19:20:17 +00:00
state - > memory = calloc ( 0x10000 , 1 ) ;
2024-01-08 17:07:28 +00:00
read_Space_Invaders_ROM ( state , " ROM/invaders.h " , 0 ) ;
read_Space_Invaders_ROM ( state , " ROM/invaders.g " , 0x800 ) ;
read_Space_Invaders_ROM ( state , " ROM/invaders.f " , 0x1000 ) ;
read_Space_Invaders_ROM ( state , " ROM/invaders.e " , 0x1800 ) ;
2024-01-14 21:35:01 +00:00
2024-01-19 19:20:17 +00:00
// GTK init
2024-01-15 13:06:04 +00:00
gtk_init ( & argc , & argv ) ;
GtkWidget * window = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
2024-01-20 11:31:11 +00:00
gtk_window_set_default_size ( GTK_WINDOW ( window ) , 448 , 550 ) ;
gtk_window_set_title ( GTK_WINDOW ( window ) , " Lux8080-Emulator " ) ;
2024-01-15 13:06:04 +00:00
g_signal_connect ( window , " key-press-event " , G_CALLBACK ( on_key_press ) , NULL ) ;
g_signal_connect ( window , " key-release-event " , G_CALLBACK ( on_key_release ) , NULL ) ;
g_signal_connect ( window , " destroy " , G_CALLBACK ( gtk_main_quit ) , NULL ) ;
2024-01-14 21:35:01 +00:00
2024-01-20 18:06:47 +00:00
// Splashscreen
GtkWidget * splash_screen = gtk_window_new ( GTK_WINDOW_POPUP ) ;
gtk_window_set_position ( GTK_WINDOW ( splash_screen ) , GTK_WIN_POS_CENTER ) ;
GtkWidget * image = gtk_image_new_from_file ( " space.png " ) ;
gtk_container_add ( GTK_CONTAINER ( splash_screen ) , image ) ;
gtk_widget_show_all ( splash_screen ) ;
g_timeout_add ( 2000 , close_splash_screen , splash_screen ) ;
g_timeout_add ( 2002 , open_screen , window ) ;
2024-01-19 21:45:49 +00:00
// Toolbar init
GtkWidget * toolbar = gtk_toolbar_new ( ) ;
GtkCssProvider * provider = gtk_css_provider_new ( ) ;
gtk_css_provider_load_from_data ( provider , " * { -GtkWidget-toolbar-style: both-horiz; } " , - 1 , NULL ) ;
gtk_style_context_add_provider ( gtk_widget_get_style_context ( toolbar ) , GTK_STYLE_PROVIDER ( provider ) , GTK_STYLE_PROVIDER_PRIORITY_USER ) ;
2024-01-20 18:06:47 +00:00
2024-01-19 21:45:49 +00:00
// Size option in the toolbar
GtkToolItem * size = gtk_tool_item_new ( ) ;
GtkWidget * combo_box = gtk_combo_box_text_new ( ) ;
gtk_combo_box_text_append_text ( GTK_COMBO_BOX_TEXT ( combo_box ) , " 1x " ) ;
gtk_combo_box_text_append_text ( GTK_COMBO_BOX_TEXT ( combo_box ) , " 2x " ) ;
gtk_combo_box_text_append_text ( GTK_COMBO_BOX_TEXT ( combo_box ) , " 3x " ) ;
gtk_container_add ( GTK_CONTAINER ( size ) , combo_box ) ;
gtk_toolbar_insert ( GTK_TOOLBAR ( toolbar ) , size , - 1 ) ;
g_signal_connect ( combo_box , " changed " , G_CALLBACK ( on_size_changed ) , NULL ) ;
// About option in the toolbar
GtkToolItem * about = gtk_tool_button_new ( NULL , " About " ) ;
gtk_toolbar_insert ( GTK_TOOLBAR ( toolbar ) , about , - 1 ) ;
g_signal_connect ( about , " clicked " , G_CALLBACK ( on_about_clicked ) , NULL ) ;
2024-01-20 18:06:47 +00:00
gtk_widget_set_can_focus ( GTK_WIDGET ( combo_box ) , FALSE ) ;
gtk_widget_set_can_focus ( GTK_WIDGET ( about ) , FALSE ) ;
2024-01-19 19:20:17 +00:00
// Drawing area init
2024-01-14 21:39:57 +00:00
bitmap = & ( state - > memory [ 0x2400 ] ) ;
2024-01-14 21:35:01 +00:00
GtkWidget * drawing_area = gtk_drawing_area_new ( ) ;
2024-01-15 19:44:19 +00:00
gtk_widget_set_app_paintable ( drawing_area , TRUE ) ;
2024-01-14 21:39:57 +00:00
g_signal_connect ( drawing_area , " draw " , G_CALLBACK ( draw_callback ) , NULL ) ;
2024-01-19 21:45:49 +00:00
// VBox to hold toolbar and drawing area
GtkWidget * vbox = gtk_box_new ( GTK_ORIENTATION_VERTICAL , 0 ) ;
gtk_box_pack_start ( GTK_BOX ( vbox ) , toolbar , FALSE , FALSE , 0 ) ;
gtk_box_pack_start ( GTK_BOX ( vbox ) , drawing_area , TRUE , TRUE , 0 ) ;
gtk_container_add ( GTK_CONTAINER ( window ) , vbox ) ;
2024-01-20 18:06:47 +00:00
//gtk_widget_show_all(window);
2024-01-14 21:35:01 +00:00
2024-01-19 19:20:17 +00:00
// CPU-init
2024-01-15 13:06:04 +00:00
cpu_data * cpu_eco = malloc ( sizeof ( cpu_data ) ) ;
cpu_eco - > state = state ;
cpu_eco - > drawing_area = drawing_area ;
cpu_eco - > done = 0 ;
cpu_eco - > total_cycles_count = 0 ;
2024-01-14 21:35:01 +00:00
2024-01-19 19:20:17 +00:00
// Pthread
2024-01-15 19:44:19 +00:00
pthread_t pid ;
pthread_create ( & pid , NULL , cpu , ( void * ) cpu_eco ) ;
2024-01-19 19:20:17 +00:00
// Main GTK Loop
2024-01-20 18:06:47 +00:00
g_timeout_add ( 80 , update_ui , drawing_area ) ;
2024-01-14 21:35:01 +00:00
gtk_main ( ) ;
2024-01-20 18:06:47 +00:00
cpu_eco - > done = 1 ;
2024-01-15 19:44:19 +00:00
pthread_join ( pid , NULL ) ;
2024-01-08 17:07:28 +00:00
free ( state - > memory ) ;
free ( state ) ;
2024-01-15 13:06:04 +00:00
free ( cpu_eco ) ;
2024-01-07 12:32:22 +00:00
return 0 ;
2024-01-06 19:33:56 +00:00
}