Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,28 @@ _thanks to @swetland for [this idea](https://github.com/markadev/AppleII-VGA/dis
![Live action shot](docs/installed_in_iie.jpg)


## 80 Columns support for AppleII+

This code implements a videx card virtually mapped to slot 3. The Apple2Vga can be used in slot 7 and let slot 3 empty.

I found out that the videx card is not compatible to grappler+ (printer interface) 'cos they share the same banking rom solution using I/O STB address. I had to remove my printer interface to have the videx running :D.

I decided to virtally map slot 3 directly from the memory in order to leave the devsel signal to change the character rom fonts. So the card can be used in slot 7 but it always maps videx card to slot 3.

**AppleII+ running 80 Columms Videos**


[![AppleII Videx Videoterm 80 Columns card Demo running at AppleIIVga by Markadev](http://img.youtube.com/vi/jKAShbG-p9Y/0.jpg)](https://www.youtube.com/watch?v=jKAShbG-p9Y "Apple][+ Videx Videoterm 80 Columns card Demo running at AppleIIVga by Markadev")

[![AppleII Accessing BBS using Videx Videoterm 80 Columns card running at AppleIIVga by Markadev](http://img.youtube.com/vi/D4BjUacbDPo/0.jpg)](https://www.youtube.com/watch?v=D4BjUacbDPo "Apple][+ Accessing BBS using Videx Videoterm 80 Columns card running at AppleIIVga by Markade")

**AppleII+ running 80 Columms Examples**

![AppleII 80 Columms Mode 1](docs/apple2_80columms1.jpg)
![AppleII 80 Columms Mode 2](docs/apple2_80columms2.jpg)
![AppleII 80 Columms Mode 3](docs/apple2_80columms3.jpg)


## Comparisons

Here are a few comparisons of the VGA card output vs composite video through
Expand Down
Binary file added docs/apple2_80columms1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/apple2_80columms2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/apple2_80columms3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion pico/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pico_sdk_init()

add_compile_options(-Wall -Wextra -Wnull-dereference -Wno-unused-parameter -Wno-unused-function)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPICO_USE_MALLOC_MUTEX=1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_SYSCLOCK=252 -DPICO_FLASH_SPI_CLKDIV=8 -DOVERCLOCKED=1")

add_executable(applevga)
pico_set_binary_type(applevga copy_to_ram)
Expand All @@ -28,7 +30,8 @@ file(GLOB TEXTFONT_SRC_FILES textfont/*.c)
target_sources(applevga PUBLIC
main.c
abus.c
buffers.c
card_videx.c
buffers.c
colors.c
config.c
device_regs.c
Expand All @@ -37,6 +40,7 @@ target_sources(applevga PUBLIC
render_lores.c
render_testpat.c
render_text.c
render_videx_text.c
${TEXTFONT_SRC_FILES}
vga.c
)
Expand Down
12 changes: 12 additions & 0 deletions pico/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# What's new in this version

* support for reading registers/data/firmware from the card (pio)
* videx card on slot 3
* overclocked to 252 mhz (like v2analog board) to sync i/o timing
* videx text fonts - by default rom1 is normal font and rom 2 is inverse font

# To do:

* allow user to change/select fonts in rom1 and rom2
* organize/standardize my code :)

# Set Up Raspberry Pi Pico SDK and build the firmware

## Windows Subsystem for Linux (WSL)
Expand Down
180 changes: 149 additions & 31 deletions pico/abus.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,33 @@
#error CONFIG_PIN_APPLEBUS_PHI0 and PHI0_GPIO must be set to the same pin
#endif


enum {
ABUS_MAIN_SM = 0,
};

typedef void (*shadow_handler)(bool is_write, uint_fast16_t address, uint_fast8_t data);


static int reset_detect_state = 0;
static shadow_handler softsw_handlers[128];


static void abus_device_read_setup(PIO pio, uint sm) {
uint program_offset = pio_add_program(pio, &abus_device_read_program);
pio_sm_claim(pio, sm);

pio_sm_config c = abus_device_read_program_get_default_config(program_offset);

// set the "device selected" pin as the jump pin
sm_config_set_jmp_pin(&c, CONFIG_PIN_APPLEBUS_DEVSEL);

// map the OUT pin group to the data signals
sm_config_set_out_pins(&c, CONFIG_PIN_APPLEBUS_DATA_BASE, 8);

// map the SET pin group to the Data transceiver control signals
sm_config_set_set_pins(&c, CONFIG_PIN_APPLEBUS_CONTROL_BASE, 2);

pio_sm_init(pio, sm, program_offset, &c);

// All the GPIOs are shared and setup by the main program
}

static void abus_main_setup(PIO pio, uint sm) {
uint program_offset = pio_add_program(pio, &abus_program);
pio_sm_claim(pio, sm);
Expand All @@ -37,40 +52,32 @@ static void abus_main_setup(PIO pio, uint sm) {
sm_config_set_in_pins(&c, CONFIG_PIN_APPLEBUS_DATA_BASE);

// map the SET pin group to the bus transceiver enable signals
sm_config_set_set_pins(&c, CONFIG_PIN_APPLEBUS_CONTROL_BASE, 3);
sm_config_set_set_pins(&c, CONFIG_PIN_APPLEBUS_CONTROL_BASE+1, 3);

// configure left shift into ISR & autopush every 26 bits
sm_config_set_in_shift(&c, false, true, 26);

pio_sm_init(pio, sm, program_offset, &c);

// configure the GPIOs
// Ensure all transceivers will start disabled
pio_sm_set_pins_with_mask(
pio, sm, (uint32_t)0x7 << CONFIG_PIN_APPLEBUS_CONTROL_BASE, (uint32_t)0x7 << CONFIG_PIN_APPLEBUS_CONTROL_BASE);
pio_sm_set_pindirs_with_mask(pio, sm, (0x7 << CONFIG_PIN_APPLEBUS_CONTROL_BASE),
(1 << CONFIG_PIN_APPLEBUS_PHI0) | (0x7 << CONFIG_PIN_APPLEBUS_CONTROL_BASE) | (0x3ff << CONFIG_PIN_APPLEBUS_DATA_BASE));

// In the rev A schematic this pin was originally used to control the data bus pins transceiver direction
// so that bus reads could be responded to with data. This code has since been removed so the GPIO could be
// repurposed.
//
// A pull-down is set on this pin to remain compatible with these rev A based designs. This will ensure that
// by default the data transceiver direction in "inward".
gpio_set_pulls(CONFIG_PIN_APPLEBUS_SYNC, false, true);
// Ensure all transceivers will start disabled, with Data transceiver direction set to 'in'
pio_sm_set_pins_with_mask(pio, sm,
(uint32_t)0xe << CONFIG_PIN_APPLEBUS_CONTROL_BASE,
(uint32_t)0xf << CONFIG_PIN_APPLEBUS_CONTROL_BASE);
pio_sm_set_pindirs_with_mask(pio, sm,
(0xf << CONFIG_PIN_APPLEBUS_CONTROL_BASE),
(1 << CONFIG_PIN_APPLEBUS_PHI0) | (0xf << CONFIG_PIN_APPLEBUS_CONTROL_BASE) | (0x3ff << CONFIG_PIN_APPLEBUS_DATA_BASE));

// Disable input synchronization on input pins that are sampled at known stable times
// to shave off two clock cycles of input latency
pio->input_sync_bypass |= (0x3ff << CONFIG_PIN_APPLEBUS_DATA_BASE);

pio_gpio_init(pio, CONFIG_PIN_APPLEBUS_PHI0);
gpio_set_pulls(CONFIG_PIN_APPLEBUS_PHI0, false, false);

for(int pin = CONFIG_PIN_APPLEBUS_CONTROL_BASE; pin < CONFIG_PIN_APPLEBUS_CONTROL_BASE + 3; pin++) {
for(int pin=CONFIG_PIN_APPLEBUS_CONTROL_BASE; pin < CONFIG_PIN_APPLEBUS_CONTROL_BASE+4; pin++) {
pio_gpio_init(pio, pin);
}

for(int pin = CONFIG_PIN_APPLEBUS_DATA_BASE; pin < CONFIG_PIN_APPLEBUS_DATA_BASE + 10; pin++) {
for(int pin=CONFIG_PIN_APPLEBUS_DATA_BASE; pin < CONFIG_PIN_APPLEBUS_DATA_BASE+10; pin++) {
pio_gpio_init(pio, pin);
gpio_set_pulls(pin, false, false);
}
Expand Down Expand Up @@ -159,6 +166,19 @@ static void shadow_softsw_57(bool is_write, uint_fast16_t address, uint_fast8_t
soft_switches |= SOFTSW_HIRES_MODE;
}


#ifdef APPLE_MODEL_IIPLUS
// To turn on/off 80 columns mode:
// Write at 0xC058 or 0xC059
static void shadow_softsw_58(bool is_write, uint_fast16_t address, uint_fast8_t data) {
card_videx_80col = false;
}

static void shadow_softsw_59(bool is_write, uint_fast16_t address, uint_fast8_t data) {
card_videx_80col = true;
}
#endif

static void shadow_softsw_5e(bool is_write, uint_fast16_t address, uint_fast8_t data) {
soft_dhires = true;
}
Expand All @@ -178,6 +198,11 @@ static void shadow_softsw_5f(bool is_write, uint_fast16_t address, uint_fast8_t


void abus_init() {

#ifdef APPLE_MODEL_IIPLUS
card_videx_card_videx_init();
#endif

// Init states
soft_switches = SOFTSW_TEXT_MODE;

Expand All @@ -191,6 +216,8 @@ void abus_init() {
softsw_handlers[0x55] = shadow_softsw_55;
softsw_handlers[0x56] = shadow_softsw_56;
softsw_handlers[0x57] = shadow_softsw_57;
softsw_handlers[0x58] = shadow_softsw_58;
softsw_handlers[0x59] = shadow_softsw_59;
#ifdef APPLE_MODEL_IIE
softsw_handlers[0x00] = shadow_softsw_00;
softsw_handlers[0x01] = shadow_softsw_01;
Expand All @@ -204,9 +231,11 @@ void abus_init() {
softsw_handlers[0x5f] = shadow_softsw_5f;
#endif

abus_device_read_setup(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM);
abus_main_setup(CONFIG_ABUS_PIO, ABUS_MAIN_SM);

pio_enable_sm_mask_in_sync(CONFIG_ABUS_PIO, (1 << ABUS_MAIN_SM));
//pio_enable_sm_mask_in_sync(CONFIG_ABUS_PIO, (1 << ABUS_MAIN_SM));
pio_enable_sm_mask_in_sync(CONFIG_ABUS_PIO, (1 << ABUS_MAIN_SM) | (1 << ABUS_DEVICE_READ_SM));
}


Expand Down Expand Up @@ -318,24 +347,113 @@ static void shadow_memory(bool is_write, uint_fast16_t address, uint32_t value)
}
}


void abus_loop() {
uint32_t value;
uint_fast16_t address;

uint instr_irq = pio_encode_irq_set(false, 6) | pio_encode_sideset(1, 1);

while(1) {
uint32_t value = pio_sm_get_blocking(CONFIG_ABUS_PIO, ABUS_MAIN_SM);
value = pio_sm_get_blocking(CONFIG_ABUS_PIO, ABUS_MAIN_SM);
address = (value >> 10) & 0xffff;

const bool is_devsel = ((value & (1u << (CONFIG_PIN_APPLEBUS_DEVSEL - CONFIG_PIN_APPLEBUS_DATA_BASE))) == 0);
const bool is_write = ((value & (1u << (CONFIG_PIN_APPLEBUS_RW - CONFIG_PIN_APPLEBUS_DATA_BASE))) == 0);


#ifdef APPLE_MODEL_IIPLUS
// Handle shadowing of the videx in the range 0xc000 - 0xc07f
// To Control the card:
//
// IOSTB (0xC800-0xCFFF)
if(card_videx_mem_on && address >= 0xC800 && address <= 0xCDFF){
if(is_write) {
// Write
card_videx_putSLOTC8XX(address, value);
}
else{
// Read
pio_sm_exec(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, instr_irq);
CONFIG_ABUS_PIO->txf[ABUS_DEVICE_READ_SM] = card_videx_getSLOTC8XX(address);
}

//gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN);
continue;
}

// IOSEL // 0xC300-C3FFF - slot 3
else if(address >= 0xC300 && address <= 0xC3FF) {


if(is_write) { //WRITE
card_videx_mem_on = true;
}
else{ //READ
pio_sm_exec(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, instr_irq);
CONFIG_ABUS_PIO->txf[ABUS_DEVICE_READ_SM] = card_videx_getRomIoSel(address);
card_videx_mem_on = true;
}
//gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN);

continue;
}

// DEVSEL // 0xC0B0-C0BF - slot 3
else if(address >=0xC0B0 && address <=0xC0BF){

if(is_write) {
// Write
card_videx_putC0SLOTX(address, (value & 0xff));
}
else{
// Read

//define current memory bank
videx_bankSLOT = (address & 0x000c) >> 2;

if (address & 0x0001){
// get current register value
pio_sm_exec(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, pio_encode_irq_set(false, 6) | pio_encode_sideset(1, 1));
CONFIG_ABUS_PIO->txf[ABUS_DEVICE_READ_SM] = videx_regSLOT[videx_regvalSLOT];
}
else{
// define current register
//pio_sm_exec(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, pio_encode_irq_set(false, 6) | pio_encode_sideset(1, 1));
//CONFIG_ABUS_PIO->txf[ABUS_DEVICE_READ_SM] = videx_regvalSLOT;
}

//pio_sm_exec(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, pio_encode_irq_set(false, 6) | pio_encode_sideset(1, 1));
//CONFIG_ABUS_PIO->txf[ABUS_DEVICE_READ_SM] = card_videx_getC0SLOTX(address);
//pio_sm_exec(CONFIG_ABUS_PIO, ABUS_MAIN_SM, pio_encode_irq_set(false, 6) | pio_encode_sideset(1, 1));
}
//gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN);

continue;
}
else if ( address >= 0xCE00 && address <= 0xCFFF) {
card_videx_mem_on = false;
continue;
}

#endif

const bool is_devsel = ((value & (1u << (CONFIG_PIN_APPLEBUS_DEVSEL - CONFIG_PIN_APPLEBUS_DATA_BASE))) == 0);


if(is_devsel) {
// device slot access
if(is_write) {
if(is_write) { //WRITE
uint_fast8_t device_reg = (value >> 10) & 0xf;
device_write(device_reg, value & 0xff);

}
gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN);

//gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN);
} else {
// some other bus cycle - handle memory & soft-switch shadowing
uint_fast16_t address = (value >> 10) & 0xffff;
//uint_fast16_t address = (value >> 10) & 0xffff;
shadow_memory(is_write, address, value);
}
}


}
}
13 changes: 13 additions & 0 deletions pico/abus.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,16 @@

void abus_init();
void abus_loop();

#define CARD_SELECT ((value & (1u << (CONFIG_PIN_APPLEBUS_DEVSEL - CONFIG_PIN_APPLEBUS_DATA_BASE))) == 0)
#define CARD_DEVSEL ((address & 0xff80) == 0xc080)
#define CARD_IOSEL (((address & 0xff00) >= 0xc100) && ((address & 0xff00) < 0xc700))
#define CARD_IOSTROBE ((address & 0xf800) == 0xc800)

#define ACCESS_READ ((value & (1u << (CONFIG_PIN_APPLEBUS_RW - CONFIG_PIN_APPLEBUS_DATA_BASE))) != 0)
#define ACCESS_WRITE ((value & (1u << (CONFIG_PIN_APPLEBUS_RW - CONFIG_PIN_APPLEBUS_DATA_BASE))) == 0)

enum {
ABUS_MAIN_SM = 0,
ABUS_DEVICE_READ_SM = 1,
};
Loading