Compare commits
2 Commits
766cc5bb43
...
ba617a5779
Author | SHA1 | Date |
---|---|---|
Oliver Schmidt | ba617a5779 | |
Oliver Schmidt | 60622b9097 |
|
@ -1,3 +1,3 @@
|
|||
a.out
|
||||
|
||||
src/gpclk
|
||||
pidrive/*.o
|
||||
pidrive/*#062000
|
||||
pipico/build/
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
set(PROJECT_NAME Apple-II-Pi)
|
||||
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
project(${PROJECT_NAME} C CXX ASM)
|
||||
pico_sdk_init()
|
||||
|
||||
project(${PROJECT_NAME} C CXX ASM)
|
||||
add_executable(${PROJECT_NAME})
|
||||
pico_add_extra_outputs(${PROJECT_NAME})
|
||||
|
||||
pico_enable_stdio_uart(${PROJECT_NAME} 0)
|
||||
pico_enable_stdio_usb(${PROJECT_NAME} 1)
|
||||
|
||||
pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/bus.pio)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(a2pico
|
||||
GIT_REPOSITORY https://github.com/oliverschmidt/a2pico.git
|
||||
GIT_TAG main
|
||||
)
|
||||
FetchContent_MakeAvailable(a2pico)
|
||||
|
||||
add_dependencies(${PROJECT_NAME} rom)
|
||||
add_custom_target(rom make -C ../../pidrive)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
main.c
|
||||
|
@ -23,5 +30,5 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
pico_stdlib
|
||||
pico_multicore
|
||||
hardware_pio
|
||||
a2pico
|
||||
)
|
||||
|
|
|
@ -24,7 +24,7 @@ SOFTWARE.
|
|||
|
||||
*/
|
||||
|
||||
#include "bus.pio.h"
|
||||
#include <a2pico.h>
|
||||
|
||||
#include "board.h"
|
||||
|
||||
|
@ -32,71 +32,53 @@ extern const __attribute__((aligned(4))) uint8_t firmware[];
|
|||
|
||||
static bool active;
|
||||
|
||||
static void __time_critical_func(callback)(uint gpio, uint32_t events) {
|
||||
if (events & GPIO_IRQ_EDGE_FALL) {
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t command;
|
||||
static uint32_t control;
|
||||
|
||||
void __time_critical_func(board)(void) {
|
||||
for (uint gpio = gpio_addr; gpio < gpio_addr + size_addr; gpio++) {
|
||||
gpio_init(gpio);
|
||||
gpio_set_pulls(gpio, false, false); // floating
|
||||
}
|
||||
|
||||
for (uint gpio = gpio_data; gpio < gpio_data + size_data; gpio++) {
|
||||
pio_gpio_init(pio0, gpio);
|
||||
gpio_set_pulls(gpio, false, false); // floating
|
||||
}
|
||||
a2pico_init(pio0);
|
||||
|
||||
gpio_init(gpio_enbl);
|
||||
gpio_set_pulls(gpio_enbl, false, false); // floating
|
||||
|
||||
uint offset;
|
||||
|
||||
offset = pio_add_program(pio0, &enbl_program);
|
||||
enbl_program_init(offset);
|
||||
|
||||
offset = pio_add_program(pio0, &write_program);
|
||||
write_program_init(offset);
|
||||
|
||||
offset = pio_add_program(pio0, &read_program);
|
||||
read_program_init(offset);
|
||||
|
||||
active = false;
|
||||
|
||||
command = 0;
|
||||
control = 0;
|
||||
a2pico_resetcallback(&callback);
|
||||
|
||||
while (true) {
|
||||
uint32_t enbl = pio_sm_get_blocking(pio0, sm_enbl);
|
||||
uint32_t addr = enbl & 0x0FFF;
|
||||
uint32_t io = enbl & 0x0F00; // IOSTRB or IOSEL
|
||||
uint32_t strb = enbl & 0x0800; // IOSTRB
|
||||
uint32_t read = enbl & 0x1000; // R/W
|
||||
uint32_t pico = a2pico_getaddr(pio0);
|
||||
uint32_t addr = pico & 0x0FFF;
|
||||
uint32_t io = pico & 0x0F00; // IOSTRB or IOSEL
|
||||
uint32_t strb = pico & 0x0800; // IOSTRB
|
||||
uint32_t read = pico & 0x1000; // R/W
|
||||
|
||||
if (read) {
|
||||
if (!io) { // DEVSEL
|
||||
switch (addr & 0xF) {
|
||||
case 0x8:
|
||||
pio_sm_put(pio0, sm_read, sio_hw->fifo_rd);
|
||||
a2pico_putdata(pio0, sio_hw->fifo_rd);
|
||||
break;
|
||||
case 0x9:
|
||||
// SIO_FIFO_ST_VLD_BITS _u(0x00000001)
|
||||
// SIO_FIFO_ST_RDY_BITS _u(0x00000002)
|
||||
pio_sm_put(pio0, sm_read, (sio_hw->fifo_st & 3) << 3);
|
||||
a2pico_putdata(pio0, (sio_hw->fifo_st & 3) << 3);
|
||||
break;
|
||||
case 0xA:
|
||||
pio_sm_put(pio0, sm_read, command);
|
||||
a2pico_putdata(pio0, command);
|
||||
break;
|
||||
case 0xB:
|
||||
pio_sm_put(pio0, sm_read, control);
|
||||
a2pico_putdata(pio0, control);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!strb || (active && (addr != 0x0FFF))) {
|
||||
pio_sm_put(pio0, sm_read, firmware[addr]);
|
||||
a2pico_putdata(pio0, firmware[addr]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t data = pio_sm_get_blocking(pio0, sm_write);
|
||||
uint32_t data = a2pico_getdata(pio0);
|
||||
if (!io) { // DEVSEL
|
||||
switch (addr & 0xF) {
|
||||
case 0x8:
|
||||
|
|
205
pipico/bus.pio
205
pipico/bus.pio
|
@ -1,205 +0,0 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Oliver Schmidt (https://a2retro.de/)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
.define public gpio_addr 2 // 12 pins
|
||||
.define public gpio_rw 14
|
||||
.define public gpio_data 15 // 8 pins
|
||||
.define public gpio_enbl 23 // DEVSEL | IOSEL | IOSTRB
|
||||
.define public gpio_irq 24
|
||||
.define public gpio_res 25
|
||||
|
||||
.define public size_addr 13 // incl. R/W
|
||||
.define public size_data 8
|
||||
|
||||
.define public sm_enbl 0
|
||||
.define public sm_read 1 // from Apple II perspective
|
||||
.define public sm_write 2 // from Apple II perspective
|
||||
|
||||
.define irq_write 4
|
||||
|
||||
/*
|
||||
|
||||
Implementation of the Apple II peripheral bus protocol:
|
||||
|
||||
- /DEVSEL, /IOSEL and /IOSTRB are supposed to combined to ENBL via an AND gate.
|
||||
|
||||
- On the falling edge of ENBL, the lines A0-A11 and R/W are sampled and pushed
|
||||
into the 'enable' state machine RX FIFO.
|
||||
|
||||
- In case of an Apple II write cycle, the lines D0-D7 are sampled ~300ns later
|
||||
and pushed into the 'write' state machine RX FIFO.
|
||||
|
||||
- If a byte is pushed into the 'read' state machine TX FIFO, it is driven out
|
||||
to the lines D0-D7 until the rising edge of ENBL.
|
||||
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
.program enbl
|
||||
|
||||
.wrap_target
|
||||
|
||||
idle:
|
||||
wait 1 gpio gpio_enbl // wait for ENBL to rise
|
||||
wait 0 gpio gpio_enbl // wait for ENBL to fall
|
||||
|
||||
in pins, size_addr // shift A0-A11 + R/W into ISR
|
||||
|
||||
jmp pin idle // jump to 'idle' if R/W is high
|
||||
|
||||
irq irq_write // set 'write' IRQ
|
||||
|
||||
.wrap
|
||||
|
||||
% c-sdk {
|
||||
static inline void enbl_program_init(uint offset) {
|
||||
pio_sm_config c = enbl_program_get_default_config(offset);
|
||||
|
||||
// in_base: gpio_addr
|
||||
sm_config_set_in_pins(&c, gpio_addr);
|
||||
|
||||
// shift_right: false
|
||||
// autopush: true
|
||||
// push_threshold: size_addr
|
||||
sm_config_set_in_shift(&c, false, true, size_addr);
|
||||
|
||||
// pin: gpio_rw
|
||||
sm_config_set_jmp_pin(&c, gpio_rw);
|
||||
|
||||
// state_machine: sm_enbl
|
||||
// initial_pc: offset
|
||||
pio_sm_init(pio0, sm_enbl, offset, &c);
|
||||
|
||||
// state_machine: sm_enbl
|
||||
pio_sm_set_enabled(pio0, sm_enbl, true);
|
||||
}
|
||||
%}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
.program write
|
||||
|
||||
.wrap_target
|
||||
|
||||
wait 1 irq irq_write [31] // wait for 'write' IRQ to be set and clear it
|
||||
// [31 cycles to allow 6502 to set up D0-D7]
|
||||
|
||||
in pins, size_data // shift D0-D7 into ISR
|
||||
|
||||
.wrap
|
||||
|
||||
% c-sdk {
|
||||
static inline void write_program_init(uint offset) {
|
||||
pio_sm_config c = write_program_get_default_config(offset);
|
||||
|
||||
// in_base: gpio_data
|
||||
sm_config_set_in_pins(&c, gpio_data);
|
||||
|
||||
// shift_right: false
|
||||
// autopush: true
|
||||
// push_threshold: size_data
|
||||
sm_config_set_in_shift(&c, false, true, size_data);
|
||||
|
||||
// state_machine: sm_write
|
||||
// initial_pc: offset
|
||||
pio_sm_init(pio0, sm_write, offset, &c);
|
||||
|
||||
// state_machine: sm_write
|
||||
pio_sm_set_enabled(pio0, sm_write, true);
|
||||
}
|
||||
%}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
.program read
|
||||
|
||||
/*
|
||||
|
||||
Both set and set-side are limited to 5 pins each. So both set and side-set are
|
||||
configured to set (the direction of) 4 pins. This approach allows to set the
|
||||
direction of D0-D7 in one operation.
|
||||
|
||||
Note: The naive approach would have been
|
||||
mov osr, ~x // move 0xFFFFFFFF to OSR
|
||||
out pindirs, size_data // enable output of D0-D7
|
||||
[...]
|
||||
mov osr, x // move 0x00000000 to OSR
|
||||
out pindirs, size_data // disable output of D0-D7
|
||||
but this would have required two operations and destroyed OSR.
|
||||
|
||||
*/
|
||||
|
||||
.side_set (size_data / 2) opt pindirs
|
||||
|
||||
.wrap_target
|
||||
|
||||
pull block // pull data into OSR, block on empty FIFO
|
||||
|
||||
out pins, size_data // shift OSR out to D0-D7
|
||||
|
||||
set pindirs, 15 side 15 // enable output of D0-D7
|
||||
|
||||
wait 1 gpio gpio_enbl // wait for ENBL to rise
|
||||
|
||||
set pindirs, 0 side 0 // disable output of D0-D7
|
||||
|
||||
.wrap
|
||||
|
||||
% c-sdk {
|
||||
static inline void read_program_init(uint offset) {
|
||||
pio_sm_config c = read_program_get_default_config(offset);
|
||||
|
||||
// out_base: gpio_data
|
||||
// out_count: size_data
|
||||
sm_config_set_out_pins(&c, gpio_data, size_data);
|
||||
|
||||
// shift_right: true
|
||||
// autopull: false
|
||||
// pull_threshold: size_data
|
||||
sm_config_set_out_shift(&c, true, false, size_data);
|
||||
|
||||
// set_base: gpio_data
|
||||
// set_count: size_data / 2
|
||||
sm_config_set_set_pins(&c, gpio_data, size_data / 2);
|
||||
|
||||
// sideset_base: gpio_data + size_data / 2
|
||||
sm_config_set_sideset_pins(&c, gpio_data + size_data / 2);
|
||||
|
||||
// state_machine: sm_read
|
||||
// initial_pc: offset
|
||||
pio_sm_init(pio0, sm_read, offset, &c);
|
||||
|
||||
// state_machine: sm_read
|
||||
pio_sm_set_enabled(pio0, sm_read, true);
|
||||
}
|
||||
%}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
|
@ -29,7 +29,6 @@ SOFTWARE.
|
|||
#include <pico/stdlib.h>
|
||||
#include <pico/multicore.h>
|
||||
|
||||
#include "bus.pio.h"
|
||||
#include "board.h"
|
||||
|
||||
#ifdef TRACE
|
||||
|
@ -49,17 +48,14 @@ void uart_printf(uart_inst_t *uart, const char *format, ...) {
|
|||
void main(void) {
|
||||
multicore_launch_core1(board);
|
||||
|
||||
gpio_init(gpio_irq);
|
||||
gpio_pull_up(gpio_irq);
|
||||
|
||||
stdio_init_all();
|
||||
stdio_set_translate_crlf(&stdio_usb, false);
|
||||
|
||||
#ifdef TRACE
|
||||
uart_init(uart0, 115200);
|
||||
uart_set_translate_crlf(uart0, true);
|
||||
gpio_set_function(0, GPIO_FUNC_UART);
|
||||
gpio_set_function(1, GPIO_FUNC_UART);
|
||||
gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
|
||||
gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);
|
||||
#endif
|
||||
|
||||
while (true) {
|
||||
|
|
Loading…
Reference in New Issue