.define public PHI0_GPIO 14 .define READ_DATA_TRIGGER_IRQ 4 .define DATA_BUSY_IRQ 5 ; Apple II bus interface ; Ref: Understanding the Apple II, pages 4-7, 7-8 .program abus ; Prerequisites: ; * Bus clock used is PHI0, wired to GPIO 26 ; * JMP pin is mapped to the R/W signal ; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0] ; * SET pins are mapped to the transceiver enable signals ; * input shift left & autopush @ 26 bits ; * run at about 250MHz (4ns/instruction) ; ; SET bits for tranceiver control: ; 0bxxx ; x - select AddrHi, active low ; x - select AddrLo, active low ; x - select Data, active low .wrap_target next_bus_cycle: set PINS, 0b111 ; enable CPLD OE wait 1 GPIO, PHI0_GPIO [4] ; wait for PHI0 to rise. Data propagation through the transceiver should ; be complete by the time this happens. in PINS, 6 ; read CPLD[5:0] set PINS, 0b011 [5] ; enable AddrHi tranceiver in PINS, 8 ; read AddrHi[7:0] set PINS, 0b101 [5] ; enable AddrLo tranceiver and delay for transceiver propagation delay in PINS, 8 ; read AddrLo[7:0] jmp PIN, read_cycle ; jump based on the state of the R/W pin write_cycle: ; the current time is P0+98ns (P0 + 10ns + 2 clocks (input synchronizers) + 20 instructions) set PINS, 0b110 [17] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+170ns) in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall jmp next_bus_cycle read_cycle: ; the current time is P0+98ns (P0 + 10ns + 2 clocks (input synchronizers) + 16 instructions) set PINS, 0b110 [5] ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+118ns) in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control .wrap .program abus_device_read ; Prerequisites: ; * Bus clock used is PHI0, wired to GPIO 26 ; * JMP pin is the ~DEVSEL signal ; * OUT pins are the 8 data signals ; * SET pins are the Data transceiver control signals ; ; SET bits for tranceiver control: ; 0bxx ; x - select Data transceiver (active low) ; x - Data transceiver direction (0=input, 1=output) .wrap_target wait_loop: wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM) jmp PIN, wait_loop ; skip if this device is not being addressed ; the current time is P0+130ns and ; this read cycle is addressed to this device. ; ; Phase 0 is typically 489 ns long. ; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0 ; * Data should be held for no more than 20ns after phase 0 ends ; * Data bus should be tri-stated within 30ns after phase 0 ends irq set DATA_BUSY_IRQ set PINS, 0b01 [7] ; enable Data tranceiver with output direction [P0+162ns] mov OSR, ~NULL [31] ; [P0+290ns] out PINDIRS, 8 [31] ; set data pins as outputs [P0+418ns] pull noblock ; pull value from the FIFO as late as possible [P0+422ns] out PINS, 8 ; [P0+426ns] ; the current time is P0+426ns wait 0 GPIO, PHI0_GPIO [2] ; wait for PHI0 to fall then hold for 12ns (2 clocks (input synchronizers) + 7 instructions) set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus mov OSR, NULL out PINDIRS, 8 ; reset data pins as inputs pull noblock ; extra late pull to clear out any standing values from the FIFO [P1+56ns] irq clear DATA_BUSY_IRQ .wrap