Skip to content
Merged
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
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ These features are currently supported:
(thanks to @dkgrizzly and @Paco1979)
* Soft-monochrome mode to force display as if on a monochrome monitor
* Some Video-7 RGB card extended graphical modes are implemented
* Compatibility with Videx VideoTerm modes on Apple II+ (thanks to @abaffa)

I had these goals in mind during design:
* Generate video out to a more modern display - I don't have any old CRTs for
Expand Down Expand Up @@ -94,8 +95,22 @@ a cheap composite -> HDMI adapter
**DHires**
![DHires Mode](docs/composite_vs_vga_dhires.jpg)

**80 Columms**
![80 Columms Mode](docs/composite_vs_vga_80columms.jpg)
**80 Columns**
![80 Columns Mode](docs/composite_vs_vga_80columms.jpg)


## 80 Column support for the Apple II+

The firmware implements Videx VideoTerm compatibility when there's a VideoTerm card installed
in slot 3. It's not enabled by default but if you have a Videx VideoTerm card in slot 3
then you can enable 80 column VGA support using the Configuration Disk image. The VGA card
can still be installed in any slot.

**Apple II+ running 80 Columns Examples**

![AppleII 80 Columms Mode 1](docs/apple2plus_videx_80columns1.jpg)
![AppleII 80 Columms Mode 2](docs/apple2plus_videx_80columns2.jpg)
![AppleII 80 Columms Mode 3](docs/apple2plus_videx_80columns3.jpg)


## Future work
Expand Down
27 changes: 18 additions & 9 deletions config-disk/STARTUP.bas
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
130 PRINT "1 SCANLINES ON 2 SCANLINES OFF"
140 PRINT "3 MONOCHROME ON 4 MONOCHROME OFF"
150 PRINT "5 MONOCHROME CFG 6 CHARSET CFG"
170 PRINT "7 COLOR PATTERNS": PRINT ""
180 PRINT "11 ABOUT": PRINT "12 LOAD DEFAULT CONFIG"
180 PRINT "13 QUIT W/OUT SAVING": PRINT"14 SAVE AND QUIT": PRINT ""
160 PRINT "7 ][+ VIDEX ON 8 ][+ VIDEX OFF"
170 PRINT "9 COLOR PATTERNS": PRINT ""
175 PRINT "11 ABOUT"
180 PRINT "12 LOAD DEFAULT CONFIG": PRINT "13 LOAD SAVED CONFIG"
185 PRINT "14 SAVE AND QUIT": PRINT "15 QUIT W/OUT SAVING"
190 VTAB 22: GOSUB 1400: INPUT "PLEASE ENTER YOUR SELECTION: ";CH
200 IF CH < 1 THEN GOSUB 1550
210 IF CH = 1 THEN GOSUB 500
Expand All @@ -23,14 +25,15 @@
240 IF CH = 4 THEN GOSUB 650
250 IF CH = 5 THEN GOSUB 2000
260 IF CH = 6 THEN GOSUB 3000
270 IF CH = 7 THEN GOSUB 700
280 IF CH = 8 THEN GOSUB 1550
290 IF CH = 9 THEN GOSUB 1550
270 IF CH = 7 THEN GOSUB 900
280 IF CH = 8 THEN GOSUB 950
290 IF CH = 9 THEN GOSUB 700
300 IF CH = 10 THEN GOSUB 1550
310 IF CH = 11 THEN GOSUB 1650
320 IF CH = 12 THEN GOSUB 800
330 IF CH = 13 THEN GOTO 4050
340 IF CH = 14 THEN GOTO 4000
325 IF CH = 13 THEN GOSUB 850
330 IF CH = 14 THEN GOTO 4000
340 IF CH = 15 THEN GOTO 4050
350 IF CH > 14 THEN GOSUB 1550
360 GOTO 100
500 REM '''SCANLINES ON
Expand All @@ -46,7 +49,13 @@
720 FOR I = 0 TO 31: COLOR= I / 2: VLIN 0,39 AT I: NEXT I: FOR I = 0 TO 14 STEP 2: PRINT TAB( I * 2 + 1);I;: NEXT I: PRINT : FOR I = 1 TO 15 STEP 2: PRINT TAB( I * 2 + 1);I;: NEXT I
730 PRINT "": GET A$: TEXT : RETURN
800 REM '''LOAD DEFAULT CONFIGURATION
810 POKE BASEADDR + 4,1: RETURN
810 POKE BASEADDR + 4,0: RETURN
850 REM '''LOAD SAVED CONFIGURATION
860 POKE BASEADDR + 4,1: RETURN
900 REM '''][+ VIDEX ON
910 POKE BASEADDR + 0,4: RETURN
950 REM '''][+ VIDEX OFF
910 POKE BASEADDR + 0,8: RETURN
1400 REM STRING ROUTINES
1410 PRINT "---------------------------------------": RETURN
1450 HOME : PRINT "APPLE II VGA": GOSUB 1400: PRINT "COPYRIGHT (C) 2021-2023 MARK AIKENS": PRINT "COPYRIGHT (C) 2022-2023 DAVID KUDER": RETURN
Expand Down
7 changes: 6 additions & 1 deletion docs/Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ After you load on the firmware for your respective Apple II system (II+ or IIe)
the VGA card is generally plug-and-play. Plug it in, power on your Apple II
and that's it.

There are some optional features and other controls that can be changed using the
menu-based Configuration disk or by directly using `POKE` commands.


## Soft Monochrome Mode

Expand Down Expand Up @@ -56,7 +59,9 @@ This register controls enablement of some features of the card

| bit(s) | Description
| ------ | -----------
| 7:2 | reserved
| 7:4 | reserved
| 3 | Setting to 1 will disable Videx VideoTerm support (II+ only)
| 2 | Setting to 1 will enable Videx VideoTerm support (II+ only)
| 1 | Setting to 1 will disable simulated scanline rendering
| 0 | Setting to 1 will enable simulated scanline rendering

Expand Down
Binary file added docs/apple2plus_videx_80columns1.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/apple2plus_videx_80columns2.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/apple2plus_videx_80columns3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions pico/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ target_sources(applevga PUBLIC
render_text.c
${TEXTFONT_SRC_FILES}
vga.c
videx_vterm.c
)
target_include_directories(applevga PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(applevga PUBLIC
Expand Down
53 changes: 49 additions & 4 deletions pico/abus.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include "buffers.h"
#include "colors.h"
#include "device_regs.h"
#ifdef APPLE_MODEL_IIPLUS
#include "videx_vterm.h"
#endif


#if CONFIG_PIN_APPLEBUS_PHI0 != PHI0_GPIO
Expand All @@ -21,7 +24,7 @@ typedef void (*shadow_handler)(bool is_write, uint_fast16_t address, uint_fast8_


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


static void abus_main_setup(PIO pio, uint sm) {
Expand Down Expand Up @@ -159,6 +162,18 @@ static void shadow_softsw_57(bool is_write, uint_fast16_t address, uint_fast8_t
soft_switches |= SOFTSW_HIRES_MODE;
}

static void shadow_softsw_58(bool is_write, uint_fast16_t address, uint_fast8_t data) {
#ifdef APPLE_MODEL_IIPLUS
videx_vterm_80col_enabled = false;
#endif
}

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

static void shadow_softsw_5e(bool is_write, uint_fast16_t address, uint_fast8_t data) {
soft_dhires = true;
}
Expand All @@ -181,6 +196,10 @@ void abus_init() {
// Init states
soft_switches = SOFTSW_TEXT_MODE;

#ifdef APPLE_MODEL_IIPLUS
videx_vterm_init();
#endif

// Setup soft-switch handlers for the Apple model
softsw_handlers[0x21] = shadow_softsw_21;
softsw_handlers[0x50] = shadow_softsw_50;
Expand All @@ -191,6 +210,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 @@ -203,6 +224,12 @@ void abus_init() {
softsw_handlers[0x5e] = shadow_softsw_5e;
softsw_handlers[0x5f] = shadow_softsw_5f;
#endif
#ifdef APPLE_MODEL_IIPLUS
// slot 3 device registers
for(uint i = 0xb0; i < 0xc0; i++) {
softsw_handlers[i] = videx_vterm_shadow_register;
}
#endif

abus_main_setup(CONFIG_ABUS_PIO, ABUS_MAIN_SM);

Expand Down Expand Up @@ -273,13 +300,28 @@ static void shadow_memory(bool is_write, uint_fast16_t address, uint32_t value)
case 0xc000 >> 10:
reset_detect_state = 0;

// Handle shadowing of the soft switches in the range 0xc000 - 0xc07f
if(address < 0xc080) {
shadow_handler h = softsw_handlers[address & 0x7f];
// Handle shadowing of the soft switches and I/O in the range $C000 - $C0FF
if(address < 0xc100) {
shadow_handler h = softsw_handlers[address & 0xff];
if(h) {
h(is_write, address, value & 0xff);
}
}
#ifdef APPLE_MODEL_IIPLUS
else if((address >= 0xc300) && (address < 0xc400)) {
// slot 3 access
videx_vterm_mem_selected = true;
}
#endif
break;

case 0xc800 >> 10:
case 0xcc00 >> 10:
// expansion slot memory space $C800-$CFFF
reset_detect_state = 0;
#ifdef APPLE_MODEL_IIPLUS
videx_vterm_shadow_c8xx(is_write, address, value);
#endif
break;

case 0x0000 >> 10:
Expand All @@ -305,6 +347,9 @@ static void shadow_memory(bool is_write, uint_fast16_t address, uint32_t value)
soft_80store = false;
soft_altcharset = false;
soft_ramwrt = false;
#ifdef APPLE_MODEL_IIPLUS
videx_vterm_80col_enabled = false;
#endif

reset_detect_state = 0;
} else {
Expand Down
25 changes: 25 additions & 0 deletions pico/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include "buffers.h"
#include "colors.h"
#include "textfont/textfont.h"
#ifdef APPLE_MODEL_IIPLUS
#include "videx_vterm.h"
#endif


// A block of flash is reserved for storing configuration persistently across power cycles
Expand All @@ -32,11 +35,18 @@ struct config {

// magic word determines if the stored configuration is valid
uint32_t magic_word;

// Add new fields after here. When reading the config use the IS_STORED_IN_CONFIG macro
// to determine if the field you're looking for is actually present in the stored config.

uint8_t videx_vterm_enabled;
};

// This is a compile-time check to ensure the size of the config struct fits within one flash erase sector
typedef char config_struct_size_check[(sizeof(struct config) <= FLASH_SECTOR_SIZE) - 1];

#define IS_STORED_IN_CONFIG(cfg, field) ((offsetof(struct config, field) + sizeof((cfg)->field)) <= (cfg)->size)


extern uint8_t __persistent_data_start[];
static struct config *cfg = (struct config *)__persistent_data_start;
Expand All @@ -54,6 +64,14 @@ void config_load() {
mono_bg_color = cfg->mono_bg_color;
mono_fg_color = cfg->mono_fg_color;
memcpy(character_rom, cfg->character_rom, CHARACTER_ROM_SIZE);

#ifdef APPLE_MODEL_IIPLUS
if(IS_STORED_IN_CONFIG(cfg, videx_vterm_enabled) && cfg->videx_vterm_enabled) {
videx_vterm_enable();
} else {
videx_vterm_disable();
}
#endif
}


Expand All @@ -63,6 +81,9 @@ void config_load_defaults() {
mono_bg_color = mono_bg_colors[1];
mono_fg_color = mono_fg_colors[1];
memcpy(character_rom, default_character_rom, CHARACTER_ROM_SIZE);
#ifdef APPLE_MODEL_IIPLUS
videx_vterm_disable();
#endif
}


Expand All @@ -71,6 +92,7 @@ void config_save() {
const int new_config_size = (sizeof(struct config) + FLASH_PAGE_SIZE - 1) & -FLASH_PAGE_SIZE;
struct config *new_config = malloc(new_config_size);
memset(new_config, 0xff, new_config_size);
memset(new_config, 0, sizeof(struct config));

new_config->size = sizeof(struct config);
new_config->scanline_emulation = soft_scanline_emulation;
Expand All @@ -79,6 +101,9 @@ void config_save() {
new_config->mono_fg_color = mono_fg_color;
memcpy(new_config->character_rom, character_rom, CHARACTER_ROM_SIZE);
new_config->magic_word = MAGIC_WORD_VALUE;
#ifdef APPLE_MODEL_IIPLUS
new_config->videx_vterm_enabled = videx_vterm_enabled;
#endif

const uint32_t flash_offset = (uint32_t)cfg - XIP_BASE;
flash_range_erase(flash_offset, FLASH_SECTOR_SIZE);
Expand Down
11 changes: 10 additions & 1 deletion pico/device_regs.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include "colors.h"
#include "config.h"
#include "textfont/textfont.h"
#ifdef APPLE_MODEL_IIPLUS
#include "videx_vterm.h"
#endif


static unsigned int char_write_offset;
Expand All @@ -18,6 +21,12 @@ void device_write(uint_fast8_t reg, uint_fast8_t data) {
soft_scanline_emulation = true;
if(data & 0x02)
soft_scanline_emulation = false;
#ifdef APPLE_MODEL_IIPLUS
if(data & 0x04)
videx_vterm_enable();
if(data & 0x08)
videx_vterm_disable();
#endif
break;

// soft-monochrome color setting
Expand Down Expand Up @@ -55,7 +64,7 @@ void device_write(uint_fast8_t reg, uint_fast8_t data) {
// command value.
//
// Note: some of these commands could take a long time (relative to 6502 bus cycles) so
// some bus activity may be missed. Other projects like the Analog-V2 delegate this execution
// some bus activity may be missed. Other projects like the V2-Analog delegate this execution
// to the other (VGA) core to avoid this. Maybe do this if the missed bus cycles become a noticable
// issue; I only expect it would happen when some config is being saved, which is not done often.
void execute_device_command(uint_fast8_t cmd) {
Expand Down
21 changes: 18 additions & 3 deletions pico/render.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include "render.h"
#include "buffers.h"
#ifdef APPLE_MODEL_IIPLUS
#include "videx_vterm.h"
#endif


void render_init() {
Expand All @@ -8,11 +11,16 @@ void render_init() {


void render_loop() {
while(1) {
#ifdef RENDER_TEST_PATTERN
while(1) {
render_vga_testpattern();
}
#else
while(1) {
update_text_flasher();
#ifdef APPLE_MODEL_IIPLUS
videx_vterm_update_flasher();
#endif

switch(soft_switches & SOFTSW_MODE_MASK) {
case 0:
Expand All @@ -28,9 +36,16 @@ void render_loop() {
render_hires(true);
break;
default:
render_text();
#ifdef APPLE_MODEL_IIPLUS
if(videx_vterm_enabled && videx_vterm_80col_enabled) {
render_videx_text();
} else
#endif
{
render_text();
}
break;
}
#endif
}
#endif
}
Loading