Using the Front Panel Switches in Magic‐1 - retrotruestory/M1DEV GitHub Wiki

Using the Front Panel Switches in Magic-1

Hardware Interface

The front panel switches in Magic-1 are memory-mapped at address 0xFFA0, allowing direct access from software:

// Define the switches address
#define SWITCHES_BASE 0xFFA0

// Read the current switch positions
uint8_t read_front_panel() {
    return *(volatile uint8_t*)SWITCHES_BASE;
}

Each bit in the read value represents the state of one switch (0 = off, 1 = on).

Software Interface

The Magic-1 bootloader includes a built-in function to read the switches:

// Read the front panel switches
uint8_t switch_value = read_switches();

Common Usage Patterns

1. Boot Control

// Wait for switch input before continuing boot
if (pause_before_boot) {
    uart_puts("Set switches and press any key to continue...\r\n");
    while (read_switches() == 0); // Wait until any switch is set
}

// Select boot image based on switches
int boot_image = read_switches() & 0x07; // Lower 3 bits for image selection (0-7)

2. Debugging Options

// Check switch configuration for debug options
if (read_switches() & 0x01) {
    // Switch 0 enables verbose output
    debug_level = DEBUG_VERBOSE;
} 

if (read_switches() & 0x02) {
    // Switch 1 enables memory diagnostics
    run_memory_test();
}

if (read_switches() & 0x04) {
    // Switch 2 enables execution tracing
    enable_execution_trace();
}

3. Runtime Configuration

// Select operating mode based on switches
uint8_t mode = read_switches() & 0x0F; // Lower 4 bits for mode selection
switch (mode) {
    case 1: start_terminal_mode(); break;
    case 2: start_monitor_mode(); break;
    case 4: start_diagnostic_mode(); break;
    case 8: start_network_mode(); break;
    default: start_normal_mode(); break;
}

4. Program Execution Control

// Use switches to control execution or debugging
void debug_loop() {
    while (1) {
        uint8_t switches = read_switches();
        
        if (switches & 0x01) step_instruction();      // Execute single instruction
        if (switches & 0x02) dump_registers();        // Display registers
        if (switches & 0x04) dump_memory(mem_addr);   // Display memory
        if (switches & 0x08) continue_execution();    // Continue normal execution
        if (switches & 0x10) break;                   // Exit debug loop
    }
}

Important Information for Programmers

  1. Read Frequency: Switches can be read at any time without impacting system performance (fast access to mapped memory)

  2. Switch Debouncing: Mechanical switches may exhibit contact bounce, so debouncing techniques are recommended:

    // Simple debounce implementation
    uint8_t debounce_switches() {
        uint8_t val1 = read_switches();
        // Small delay
        for (volatile int i = 0; i < 1000; i++);
        uint8_t val2 = read_switches();
        return (val1 & val2); // Return only switches that are stable
    }
    
  3. Switch Masking: Often used to isolate specific bits:

    // Check only specific switches
    uint8_t check_specific_switches() {
        uint8_t switches = read_switches();
        uint8_t mask = 0x03; // Only interested in bits 0 and 1
        return (switches & mask);
    }
    
  4. State Change Detection:

    // Detect changes in switch states
    uint8_t last_state = 0;
    
    void check_switch_changes() {
        uint8_t current = read_switches();
        uint8_t changed = current ^ last_state;
        
        if (changed) {
            // Switches have changed
            uart_puts("Switches changed: ");
            uart_puthex(changed);
            uart_puts("\r\n");
        }
        
        last_state = current;
    }
    
  5. Use in Interrupt Handlers: Switches can be safely read in interrupt handlers since access is fast and requires no additional synchronization.

The front panel switches provide a simple yet powerful mechanism for interacting with the Magic-1 system without requiring keyboard input, which is particularly useful during early boot phases or hardware debugging.