Thursday, March 26, 2009

In this project i have written more macros than ever before. The main reason is the similarities between opcodes, that the way the read operands are similar. By using macros the opcode implementations can be kept down to 2-3 lines of code instead of 6-7, which makes it much easier to maintain. It is also generally faster implementing it as macros as real functions.

Below you can see macros helping with data retrieval. The code is a bit more linebreaked here, just to fit the stupid fixed blog width.

// Macros for addressing modes
#define READ_BYTE_IMM() read_byte( PC++ )

// Read addresses
#define READ_ADDR_ZP() (READ_BYTE_IMM())
#define READ_ADDR_ZP_X() ((READ_BYTE_IMM() + X) & 0xff)
#define READ_ADDR_ZP_Y() ((READ_BYTE_IMM() + Y) & 0xff)

#define READ_ADDR_ABS() (READ_BYTE_IMM() \
| READ_BYTE_IMM()<<8)
#define READ_ADDR_ABS_X() (READ_ADDR_ABS() + X)
#define READ_ADDR_ABS_Y() (READ_ADDR_ABS() + Y)

#define READ_ADDR_IND_X() (read_word_zp(\
READ_BYTE_IMM() + X))
#define READ_ADDR_IND_Y() (read_word_zp(\
READ_BYTE_IMM()) + Y)

#define READ_JUMP_ADDR() (b1 = READ_BYTE_IMM(), b1 & \
0x80 ? (PC - ((b1 ^ 0xff)+1)) : (PC + b1))

// Read data
#define READ_BYTE_ZP() read_byte_zp(READ_ADDR_ZP())
#define READ_BYTE_ZP_X() read_byte_zp(READ_ADDR_ZP_X())
#define READ_BYTE_ZP_Y() read_byte_zp(READ_ADDR_ZP_Y())

#define READ_BYTE_ABS() read_byte(READ_ADDR_ABS())
#define READ_BYTE_ABS_X() read_byte(READ_ADDR_ABS_X())
#define READ_BYTE_ABS_Y() read_byte(READ_ADDR_ABS_Y())

#define READ_BYTE_IND_X() read_byte(READ_ADDR_IND_X())
#define READ_BYTE_IND_Y() read_byte(READ_ADDR_IND_Y())

#define PUSH_BYTE_STACK(b) (memory->mem[ (SP--) \
| STACK_BOTTOM ] = (b))
#define POP_BYTE_STACK(b) memory->mem[ (++SP) \
| STACK_BOTTOM ]

// Macros for flag handling
#define SET_FLAG_NZ(B) (N = Z = B)

#define IS_ZERO (!Z)
#define IS_NEGATIVE (!!(N & 0x80))


This allows opcode implementations like:

 // And accumulator with memory
case AND_IMM:
SET_FLAG_NZ(A &= READ_BYTE_IMM());
break;
case AND_ZP:
SET_FLAG_NZ(A &= READ_BYTE_ZP());
break;
case AND_ZP_X:
SET_FLAG_NZ(A &= READ_BYTE_ZP_X());
break;
case AND_ABS:
SET_FLAG_NZ(A &= READ_BYTE_ABS());
break;
case AND_ABS_X:
SET_FLAG_NZ(A &= READ_BYTE_ABS_X());
break;
case AND_ABS_Y:
SET_FLAG_NZ(A &= READ_BYTE_ABS_Y());
break;
case AND_IND_X:
SET_FLAG_NZ(A &= READ_BYTE_IND_X());
break;
case AND_IND_Y :
SET_FLAG_NZ(A &= READ_BYTE_IND_Y());
break;


and

 case JMP_ABS:
PC = READ_ADDR_ABS();
break;
case JMP_IND:
PC = read_word(READ_ADDR_ABS());
break;

case JSR:
PUSH_BYTE_STACK( PC+1 >> 8 );
PUSH_BYTE_STACK( PC+1 );
PC = READ_ADDR_ABS();
break;



Nice!

No comments:

Post a Comment