Exemple #1
0
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;
}
Exemple #2
0
void io_reset_pc()
{
  bus_write(STA_zp);

  bus_select(CPU_ADDRESS);

  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    reset_pc();
  }
  
  bus_deselect();
}
Exemple #3
0
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;
}
Exemple #4
0
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= &register_set12;
      reset_pc = &reset_pc12;
      disable_interrupts = &disable_interrupts12;
      break;
      
    case 15:
      register_set = &register_set15;
      reset_pc = &reset_pc15;
      disable_interrupts = &disable_interrupts15;
      break;
      
    case 16:
      register_set = &register_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();
}