Compare commits
2 Commits
766cc5bb43
...
ba617a5779
Author | SHA1 | Date |
---|---|---|
Oliver Schmidt | ba617a5779 | |
Oliver Schmidt | 60622b9097 |
|
@ -1,3 +1,3 @@
|
||||||
a.out
|
pidrive/*.o
|
||||||
|
pidrive/*#062000
|
||||||
src/gpclk
|
pipico/build/
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
set(PROJECT_NAME Apple-II-Pi)
|
set(PROJECT_NAME Apple-II-Pi)
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.12)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
include(pico_sdk_import.cmake)
|
include(pico_sdk_import.cmake)
|
||||||
|
project(${PROJECT_NAME} C CXX ASM)
|
||||||
pico_sdk_init()
|
pico_sdk_init()
|
||||||
|
|
||||||
project(${PROJECT_NAME} C CXX ASM)
|
|
||||||
add_executable(${PROJECT_NAME})
|
add_executable(${PROJECT_NAME})
|
||||||
pico_add_extra_outputs(${PROJECT_NAME})
|
pico_add_extra_outputs(${PROJECT_NAME})
|
||||||
|
|
||||||
pico_enable_stdio_uart(${PROJECT_NAME} 0)
|
pico_enable_stdio_uart(${PROJECT_NAME} 0)
|
||||||
pico_enable_stdio_usb(${PROJECT_NAME} 1)
|
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
|
target_sources(${PROJECT_NAME} PRIVATE
|
||||||
main.c
|
main.c
|
||||||
|
@ -23,5 +30,5 @@ target_sources(${PROJECT_NAME} PRIVATE
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||||
pico_stdlib
|
pico_stdlib
|
||||||
pico_multicore
|
pico_multicore
|
||||||
hardware_pio
|
a2pico
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,7 +24,7 @@ SOFTWARE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "bus.pio.h"
|
#include <a2pico.h>
|
||||||
|
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
|
@ -32,71 +32,53 @@ extern const __attribute__((aligned(4))) uint8_t firmware[];
|
||||||
|
|
||||||
static bool active;
|
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 command;
|
||||||
static uint32_t control;
|
static uint32_t control;
|
||||||
|
|
||||||
void __time_critical_func(board)(void) {
|
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++) {
|
a2pico_init(pio0);
|
||||||
pio_gpio_init(pio0, gpio);
|
|
||||||
gpio_set_pulls(gpio, false, false); // floating
|
|
||||||
}
|
|
||||||
|
|
||||||
gpio_init(gpio_enbl);
|
a2pico_resetcallback(&callback);
|
||||||
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;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
uint32_t enbl = pio_sm_get_blocking(pio0, sm_enbl);
|
uint32_t pico = a2pico_getaddr(pio0);
|
||||||
uint32_t addr = enbl & 0x0FFF;
|
uint32_t addr = pico & 0x0FFF;
|
||||||
uint32_t io = enbl & 0x0F00; // IOSTRB or IOSEL
|
uint32_t io = pico & 0x0F00; // IOSTRB or IOSEL
|
||||||
uint32_t strb = enbl & 0x0800; // IOSTRB
|
uint32_t strb = pico & 0x0800; // IOSTRB
|
||||||
uint32_t read = enbl & 0x1000; // R/W
|
uint32_t read = pico & 0x1000; // R/W
|
||||||
|
|
||||||
if (read) {
|
if (read) {
|
||||||
if (!io) { // DEVSEL
|
if (!io) { // DEVSEL
|
||||||
switch (addr & 0xF) {
|
switch (addr & 0xF) {
|
||||||
case 0x8:
|
case 0x8:
|
||||||
pio_sm_put(pio0, sm_read, sio_hw->fifo_rd);
|
a2pico_putdata(pio0, sio_hw->fifo_rd);
|
||||||
break;
|
break;
|
||||||
case 0x9:
|
case 0x9:
|
||||||
// SIO_FIFO_ST_VLD_BITS _u(0x00000001)
|
// SIO_FIFO_ST_VLD_BITS _u(0x00000001)
|
||||||
// SIO_FIFO_ST_RDY_BITS _u(0x00000002)
|
// 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;
|
break;
|
||||||
case 0xA:
|
case 0xA:
|
||||||
pio_sm_put(pio0, sm_read, command);
|
a2pico_putdata(pio0, command);
|
||||||
break;
|
break;
|
||||||
case 0xB:
|
case 0xB:
|
||||||
pio_sm_put(pio0, sm_read, control);
|
a2pico_putdata(pio0, control);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!strb || (active && (addr != 0x0FFF))) {
|
if (!strb || (active && (addr != 0x0FFF))) {
|
||||||
pio_sm_put(pio0, sm_read, firmware[addr]);
|
a2pico_putdata(pio0, firmware[addr]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint32_t data = pio_sm_get_blocking(pio0, sm_write);
|
uint32_t data = a2pico_getdata(pio0);
|
||||||
if (!io) { // DEVSEL
|
if (!io) { // DEVSEL
|
||||||
switch (addr & 0xF) {
|
switch (addr & 0xF) {
|
||||||
case 0x8:
|
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/stdlib.h>
|
||||||
#include <pico/multicore.h>
|
#include <pico/multicore.h>
|
||||||
|
|
||||||
#include "bus.pio.h"
|
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
|
@ -49,17 +48,14 @@ void uart_printf(uart_inst_t *uart, const char *format, ...) {
|
||||||
void main(void) {
|
void main(void) {
|
||||||
multicore_launch_core1(board);
|
multicore_launch_core1(board);
|
||||||
|
|
||||||
gpio_init(gpio_irq);
|
|
||||||
gpio_pull_up(gpio_irq);
|
|
||||||
|
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
stdio_set_translate_crlf(&stdio_usb, false);
|
stdio_set_translate_crlf(&stdio_usb, false);
|
||||||
|
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
uart_init(uart0, 115200);
|
uart_init(uart0, 115200);
|
||||||
uart_set_translate_crlf(uart0, true);
|
uart_set_translate_crlf(uart0, true);
|
||||||
gpio_set_function(0, GPIO_FUNC_UART);
|
gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
|
||||||
gpio_set_function(1, GPIO_FUNC_UART);
|
gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
Loading…
Reference in New Issue