// Commodore 64 Registers and Constants

// Processor port data direction register
const byte* PROCPORT_DDR = $00;
// Mask for PROCESSOR_PORT_DDR which allows only memory configuration to be written
const byte PROCPORT_DDR_MEMORY_MASK = %00000111;

// Processor Port Register controlling RAM/ROM configuration and the datasette
const byte* PROCPORT = $01;
// RAM in all three areas $A000, $D000, $E000
const byte PROCPORT_RAM_ALL         = %00000000;
// RAM in $A000, $E000 I/O in $D000
const byte PROCPORT_RAM_IO          = %00000101;
// RAM in $A000, $E000 CHAR ROM in $D000
const byte PROCPORT_RAM_CHARROM     = %00000001;
// RAM in $A000, I/O in $D000, KERNEL in $E000
const byte PROCPORT_KERNEL_IO       = %00000110;
// BASIC in $A000, I/O in $D000, KERNEL in $E000
const byte PROCPORT_BASIC_KERNEL_IO = %00000111;

// The address of the CHARGEN character set
const byte* CHARGEN = $d000;

// Positions of the border (in sprite positions)
const byte BORDER_XPOS_LEFT=24;
const word BORDER_XPOS_RIGHT=344;
const byte BORDER_YPOS_TOP=50;
const byte BORDER_YPOS_BOTTOM=250;

// The offset of the sprite pointers from the screen start address
const word SPRITE_PTRS = $3f8;

const byte* SPRITES_XPOS = $d000;
const byte* SPRITES_YPOS = $d001;
const byte* SPRITES_XMSB = $d010;
const byte* RASTER = $d012;
const byte* SPRITES_ENABLE = $d015;
const byte* SPRITES_EXPAND_Y = $d017;
const byte* SPRITES_PRIORITY = $d01b;
const byte* SPRITES_MC = $d01c;
const byte* SPRITES_EXPAND_X = $d01d;
const byte* BORDERCOL = $d020;
const byte* BGCOL = $d021;
const byte* BGCOL1 = $d021;
const byte* BGCOL2 = $d022;
const byte* BGCOL3 = $d023;
const byte* BGCOL4 = $d024;
const byte* SPRITES_MC1 = $d025;
const byte* SPRITES_MC2 = $d026;
const byte* SPRITES_COLS = $d027;

const byte* VIC_CONTROL = $d011;
const byte* D011 = $d011;
const byte VIC_RST8 = %10000000;
const byte VIC_ECM =  %01000000;
const byte VIC_BMM =  %00100000;
const byte VIC_DEN =  %00010000;
const byte VIC_RSEL = %00001000;

const byte* VIC_CONTROL2 = $d016;
const byte* D016 = $d016;
const byte VIC_MCM =  %00010000;
const byte VIC_CSEL = %00001000;

const byte* D018 = $d018;
const byte* VIC_MEMORY = $d018;

const byte* LIGHTPEN_X = $d013;
const byte* LIGHTPEN_Y = $d014;

// VIC II IRQ Status Register
const byte* IRQ_STATUS = $d019;
// VIC II IRQ Enable Register
const byte* IRQ_ENABLE = $d01a;
// Bits for the IRQ Status/Enable Registers
const byte IRQ_RASTER = %00000001;
const byte IRQ_COLLISION_BG = %00000010;
const byte IRQ_COLLISION_SPRITE = %00000100;
const byte IRQ_LIGHTPEN = %00001000;

// Color Ram
const byte* COLS = $d800;

// CIA#1 Port A: keyboard matrix columns and joystick #2
const byte* CIA1_PORT_A = $dc00;
// CIA#1 Port B: keyboard matrix rows and joystick #1.
const byte* CIA1_PORT_B = $dc01;
// CIA #1 Port A data direction register.
const byte* CIA1_PORT_A_DDR = $dc02;
// CIA #1 Port B data direction register.
const byte* CIA1_PORT_B_DDR = $dc03;
// CIA #1 Timer A Value
const word* CIA1_TIMER_A = $dc04;
// CIA #1 Timer B Value
const word* CIA1_TIMER_B = $dc06;
// CIA #1 Time-of-day real-time-clock tenth seconds (BCD)
const byte* CIA1_TOD_10THS = $dc08;
// CIA #1 Time-of-day real-time-clock seconds (BCD)
const byte* CIA1_TOD_SEC = $dc09;
// CIA #1 Time-of-day real-time-clock minutes (BCD)
const byte* CIA1_TOD_MIN = $dc0a;
// CIA #1 Time-of-day real-time-clock hours (BCD)
const byte* CIA1_TOD_HOURS = $dc0b;
// CIA #1 Serial Shift Register
const byte* CIA1_SERIAL_SHIFT_OUT = $dc0c;
// CIA#1 Interrupt Status & Control Register
const byte* CIA1_INTERRUPT = $dc0d;
// CIA#1 Timer A Control Register
const byte* CIA1_TIMER_A_CONTROL = $dc0e;
// CIA#1 Timer B Control Register
const byte* CIA1_TIMER_B_CONTROL = $dc0f;

// CIA#2 Port A: Serial bus, RS-232, VIC memory bank
const byte* CIA2_PORT_A = $dd00;
// CIA#2 Port B: RS-232
const byte* CIA2_PORT_B = $dd01;
// CIA #2 Port A data direction register.
const byte* CIA2_PORT_A_DDR = $dd02;
// CIA #2 Port B data direction register.
const byte* CIA2_PORT_B_DDR = $dd03;
// CIA #2 Timer A+B Value (32-bit)
const dword* CIA2_TIMER_AB = $dd04;
// CIA #2 Timer A Value (16-bit)
const word* CIA2_TIMER_A = $dd04;
// CIA #2 Timer B Value (16-bit)
const word* CIA2_TIMER_B = $dd06;
// CIA #2 Time-of-day real-time-clock tenth seconds (BCD)
const byte* CIA2_TOD_10THS = $dd08;
// CIA #2 Time-of-day real-time-clock seconds (BCD)
const byte* CIA2_TOD_SEC = $dd09;
// CIA #2 Time-of-day real-time-clock minutes (BCD)
const byte* CIA2_TOD_MIN = $dd0a;
// CIA #2 Time-of-day real-time-clock hours (BCD)
const byte* CIA2_TOD_HOURS = $dd0b;
// CIA #2 Serial Shift Register
const byte* CIA2_SERIAL_SHIFT_OUT = $dd0c;
// CIA #2 Interrupt Status & Control Register
const byte* CIA2_INTERRUPT = $dd0d;
// CIA #2 Timer A Control Register
const byte* CIA2_TIMER_A_CONTROL = $dd0e;
// CIA #2 Timer B Control Register
const byte* CIA2_TIMER_B_CONTROL = $dd0f;

// Value that disables all CIA interrupts when stored to the CIA Interrupt registers
const byte CIA_INTERRUPT_CLEAR = $7f;

// Timer Control - Start/stop timer (0:stop, 1: start)
const byte CIA_TIMER_CONTROL_STOP = 0b00000000;
// Timer Control - Start/stop timer (0:stop, 1: start)
const byte CIA_TIMER_CONTROL_START = 0b00000001;
// Timer Control - Time CONTINUOUS/ONE-SHOT (0:CONTINUOUS, 1: ONE-SHOT)
const byte CIA_TIMER_CONTROL_CONTINUOUS = 0b00000000;
// Timer Control - Time CONTINUOUS/ONE-SHOT (0:CONTINUOUS, 1: ONE-SHOT)
const byte CIA_TIMER_CONTROL_ONESHOT = 0b00001000;
// Timer A Control - Timer counts (0:system cycles, 1: CNT pulses)
const byte CIA_TIMER_CONTROL_A_COUNT_CYCLES = 0b00000000;
// Timer A Control - Timer counts (0:system cycles, 1: CNT pulses)
const byte CIA_TIMER_CONTROL_A_COUNT_CNT = 0b00100000;
// Timer A Control - Serial Port Mode (0: Serial Port Input, 1: Serial Port Output)
const byte CIA_TIMER_CONTROL_A_SERIAL_IN = 0b00000000;
// Timer A Control - Serial Port Mode (0: Serial Port Input, 1: Serial Port Output)
const byte CIA_TIMER_CONTROL_A_SERIAL_OUT = 0b01000000;
// Timer A Control - time-of-day clock Mode (0: 60Hz, 1: 50Hz)
const byte CIA_TIMER_CONTROL_A_TOD_60HZ = 0b00000000;
// Timer A Control - time-of-day clock Mode (0: 60Hz, 1: 50Hz)
const byte CIA_TIMER_CONTROL_A_TOD_50HZ = 0b10000000;
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
const byte CIA_TIMER_CONTROL_B_COUNT_CYCLES = 0b00000000;
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
const byte CIA_TIMER_CONTROL_B_COUNT_CNT = 0b00100000;
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
const byte CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A = 0b01000000;
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
const byte CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A_CNT = 0b01100000;
// Timer B Control - time-of-day write mode (0: TOD clock, 1: TOD alarm)
const byte CIA_TIMER_CONTROL_B_TOD_CLOCK_SET = 0b00000000;
// Timer B Control - time-of-day write mode (0: TOD clock, 1: TOD alarm)
const byte CIA_TIMER_CONTROL_B_TOD_ALARM_SET = 0b10000000;

// The vector used when the KERNAL serves IRQ interrupts
const void()** KERNEL_IRQ = $0314;
// The vector used when the KERNAL serves NMI interrupts
const void()** KERNEL_NMI = $0318;

// The vector used when the HARDWARE serves IRQ interrupts
const void()** HARDWARE_IRQ = $fffe;

// The SID volume
const byte* SID_VOLUME = $d418;


// The colors of the C64
const byte BLACK = $0;
const byte WHITE = $1;
const byte RED = $2;
const byte CYAN = $3;
const byte PURPLE = $4;
const byte GREEN = $5;
const byte BLUE = $6;
const byte YELLOW = $7;
const byte ORANGE = $8;
const byte BROWN = $9;
const byte PINK = $a;
const byte DARK_GREY= $b;
const byte GREY = $c;
const byte LIGHT_GREEN = $d;
const byte LIGHT_BLUE = $e;
const byte LIGHT_GREY = $f;

// Get the value to store into D018 to display a specific screen and charset/bitmap
// Optimized for ASM from (byte)((((word)screen&$3fff)/$40)|(((word)charset&$3fff)/$400));
inline byte toD018(byte* screen, byte* gfx) {
    return (>((((word)screen&$3fff)*4)))|(((>((word)gfx))/4)&$f);
}

// Get the value to store into DD00 (CIA 2 port A) to choose a specific VIC bank
// Optimized for ASM from %00000011 ^ (byte)((word)gfx/$4000)
inline byte toDd00(byte* gfx) {
    return %00000011 ^ (>((word)gfx))/$40;
}

// Get the sprite pointer for a sprite.
// The sprite pointer is the index of the sprite within the graphics bank and equal to the sprite (byte)(sprite_addr/64)
// The sprite pointers are stored SCREEN+$3f8+sprite_id to set the pointer of each sprite
inline byte toSpritePtr(byte* sprite) {
	return (byte)(((word)sprite)/$40);
}

// Select a specific VIC graphics bank by setting the CIA 2 port A ($dd00) as needed
inline void vicSelectGfxBank(byte* gfx) {
    *CIA2_PORT_A_DDR = %00000011;
    *CIA2_PORT_A = toDd00(gfx);
}
