inline void register_write(uint8_t reg, uint8_t value) /* Write to register Writes a value to an APU register by feeding the 6502 with instructions for loading the value into A, and then storing the value in $40<reg>. */ { // Put STA_zp on bus before deactivating CPU latch bus_write(STA_zp); // Open latch output bus_select(CPU_ADDRESS); // The code in the register set function has to be cycle exact, so it has to // be run with interrupts disabled: ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { register_set(reg, value); } // Finally, latch the last bus value by deselecting the CPU bus_deselect(); // Reflect change in mirror reg_mirror[reg] = value; }
void io_reset_pc() { bus_write(STA_zp); bus_select(CPU_ADDRESS); ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { reset_pc(); } bus_deselect(); }
void input_refresh(void) /* Reads one column of switch data each time it is called and auto-increments the current row */ { static uint8_t current_row = 0; static uint8_t stage = 0; static uint8_t last_data = 0; // Update row latch value bus_select(ROW_ADDRESS); bus_write(row_mirror | (0x20 << current_row)); nop(); // Latch row value and switch to the switch column input buffer bus_select(SWITCHCOL_ADDRESS); bus_dir_input(); uint8_t switch_data = bus_read(); bus_dir_output(); bus_deselect(); if (stage == 1) { // Expand the switch bits into individual bytes in the input array uint8_t* row = &input[current_row]; // Debouncing: *row = (switch_data & *row) | (switch_data & last_data) | (last_data & *row); if (++current_row == 3) current_row = 0; } stage ^= 1; last_data = switch_data; }
void io_setup() /* Initializes the interface to communicate with 6502 */ { // Configure the /RES pin on PORT C as output and set /RES high, also set // bits 0, 1 as output DDRC |= RES; PORTC |= RES | RW; bus_select(CPU_ADDRESS); bus_write(STA_abs); bus_deselect(); // Set /RES low PORTC &= ~RES; // Hold it low for some time, for 6502 to perform reset _delay_us(10); // Set /RES high again PORTC |= RES; // Wait a while until the 6502 has completed its reset cycle _delay_us(100); // Run detect function and set the right functions for communicating with // the 2A03/clone chip used. Try three times to ensure that a correct // value is read. uint8_t tries = 3; while (tries-- > 0) { io_clockdiv = detect(); if (io_clockdiv == 12 || io_clockdiv == 15 || io_clockdiv == 16) break; } switch (io_clockdiv) { case 12: register_set= ®ister_set12; reset_pc = &reset_pc12; disable_interrupts = &disable_interrupts12; break; case 15: register_set = ®ister_set15; reset_pc = &reset_pc15; disable_interrupts = &disable_interrupts15; break; case 16: register_set = ®ister_set16; reset_pc = &reset_pc16; disable_interrupts = &disable_interrupts16; break; } // Disable interrupts on the 6502 disable_interrupts(); // Reset PC to ensure that it doesn't read any of the APU registers io_reset_pc(); }