Compare commits

...

6 Commits

Author SHA1 Message Date
David Kuder 0185620ff5 Update config.c 2023-04-28 23:59:39 -04:00
David Kuder e94cfac000 Video 7 support 2023-04-28 23:23:03 -04:00
David Kuder d5e001f2c1 Macro consolidation 2023-04-28 23:21:14 -04:00
David Kuder ea4af57302 Update buffers.h 2023-04-28 23:18:51 -04:00
David Kuder 8531bb7881 Analog GS jumpers and M2B0 2023-04-28 23:18:42 -04:00
David Kuder 006ff637a6 IIgs timing tweaks 2023-04-28 23:18:00 -04:00
16 changed files with 538 additions and 155 deletions

View File

@ -21,27 +21,29 @@
; x - select Data, active low
.wrap_target
next_bus_cycle:
set PINS, 0b011 ; enable AddrHi tranceiver
wait 1 GPIO, PHI0_GPIO ; wait for PHI0 to rise. Data propagation through the transceiver should
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 [12] ; enable AddrLo tranceiver and delay for transceiver propagation delay
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+82ns (P0 + 10ns + 2 clocks (input synchronizers) + 16 instructions)
; the current time is P0+98ns (P0 + 10ns + 2 clocks (input synchronizers) + 20 instructions)
set PINS, 0b110 [21] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+170ns)
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+82ns (P0 + 10ns + 2 clocks (input synchronizers) + 16 instructions)
; the current time is P0+98ns (P0 + 10ns + 2 clocks (input synchronizers) + 16 instructions)
set PINS, 0b110 [4] ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+102ns+buffer delay)
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
@ -66,7 +68,7 @@ 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+114ns (P0 + 10ns + 2 clocks (input synchronizers) + 24 instructions) and
; the current time is P0+130ns and
; this read cycle is addressed to this device.
;
; Phase 0 is typically 489 ns long.
@ -76,16 +78,16 @@ wait_loop:
irq set DATA_BUSY_IRQ
set PINS, 0b01 [10] ; enable Data tranceiver with output direction [160ns]
mov OSR, ~NULL [31] ; [288ns]
out PINDIRS, 8 [31] ; set data pins as outputs [416ns]
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 [420ns]
out PINS, 8 ; [424ns]
pull noblock ; pull value from the FIFO as late as possible [P0+422ns]
out PINS, 8 ; [P0+426ns]
; the current time is P0+424ns (P0 + 10ns + 2 clocks (input synchronizers) + 101 instructions)
; the current time is P0+426ns
wait 0 GPIO, PHI0_GPIO [2] ; wait for PHI0 to fall then hold for 15ns (2 clocks (input synchronizers) + 7 instructions)
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

View File

@ -57,8 +57,13 @@ static void abus_main_setup(PIO pio, uint sm) {
// map the SET pin group to the bus transceiver enable signals
sm_config_set_set_pins(&c, CONFIG_PIN_APPLEBUS_CONTROL_BASE+1, 3);
#ifdef ANALOG_GS
// configure left shift into ISR & autopush every 32 bits
sm_config_set_in_shift(&c, false, true, 32);
#else
// configure left shift into ISR & autopush every 26 bits
sm_config_set_in_shift(&c, false, true, 26);
#endif
pio_sm_init(pio, sm, program_offset, &c);

View File

@ -7,6 +7,9 @@ void abus_init();
#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,

View File

@ -68,45 +68,51 @@ extern volatile uint32_t soft_switches;
extern volatile uint32_t internal_flags;
#define SOFTSW_TEXT_MODE 0x00000001
#define SOFTSW_MIX_MODE 0x00000002
#define SOFTSW_HIRES_MODE 0x00000004
#define SOFTSW_MODE_MASK 0x00000007
#define SOFTSW_PAGE_2 0x00000008
#define SOFTSW_TEXT_MODE 0x00000001ul
#define SOFTSW_MIX_MODE 0x00000002ul
#define SOFTSW_HIRES_MODE 0x00000004ul
#define SOFTSW_MODE_MASK 0x00000007ul
#define SOFTSW_PAGE_2 0x00000008ul
// Apple IIe/c/gs softswitches
#define SOFTSW_80STORE 0x00000100
#define SOFTSW_AUX_READ 0x00000200
#define SOFTSW_AUX_WRITE 0x00000400
#define SOFTSW_AUXZP 0x00000800
#define SOFTSW_SLOT3ROM 0x00001000
#define SOFTSW_80COL 0x00002000
#define SOFTSW_ALTCHAR 0x00004000
#define SOFTSW_DGR 0x00008000
#define SOFTSW_80STORE 0x00000100ul
#define SOFTSW_AUX_READ 0x00000200ul
#define SOFTSW_AUX_WRITE 0x00000400ul
#define SOFTSW_AUXZP 0x00000800ul
#define SOFTSW_SLOT3ROM 0x00001000ul
#define SOFTSW_80COL 0x00002000ul
#define SOFTSW_ALTCHAR 0x00004000ul
#define SOFTSW_DGR 0x00008000ul
#define SOFTSW_NEWVID_MASK 0xE0
#define SOFTSW_NEWVID_MASK 0xE0ul
#define SOFTSW_NEWVID_SHIFT 11
#define SOFTSW_MONOCHROME 0x00010000
#define SOFTSW_LINEARIZE 0x00020000
#define SOFTSW_SHR 0x00040000
#define SOFTSW_MONOCHROME 0x00010000ul
#define SOFTSW_LINEARIZE 0x00020000ul
#define SOFTSW_SHR 0x00040000ul
#define SOFTSW_IOUDIS 0x00080000
#define SOFTSW_IOUDIS 0x00080000ul
#define SOFTSW_SHADOW_MASK 0x7F
#define SOFTSW_SHADOW_MASK 0x7Ful
#define SOFTSW_SHADOW_SHIFT 20
#define SOFTSW_SHADOW_TEXT 0x00100000
#define SOFTSW_SHADOW_HGR1 0x00200000
#define SOFTSW_SHADOW_HGR2 0x00400000
#define SOFTSW_SHADOW_SHR 0x00800000
#define SOFTSW_SHADOW_AUXHGR 0x01000000
#define SOFTSW_SHADOW_ALTDISP 0x02000000
#define SOFTSW_SHADOW_IO 0x04000000
#define SOFTSW_SHADOW_TEXT 0x00100000ul
#define SOFTSW_SHADOW_HGR1 0x00200000ul
#define SOFTSW_SHADOW_HGR2 0x00400000ul
#define SOFTSW_SHADOW_SHR 0x00800000ul
#define SOFTSW_SHADOW_AUXHGR 0x01000000ul
#define SOFTSW_SHADOW_ALTDISP 0x02000000ul
#define SOFTSW_SHADOW_IO 0x04000000ul
// V2 Analog specific softswitches
#define IFLAGS_OLDCOLOR 0x08000000
#define SOFTSW_TERMINAL 0x10000000
#define IFLAGS_TEST 0x20000000
#define IFLAGS_IIE_REGS 0x40000000
#define IFLAGS_IIGS_REGS 0x80000000
#define IFLAGS_VIDEO7 0x04000000ul
#define IFLAGS_OLDCOLOR 0x08000000ul
#define IFLAGS_TERMINAL 0x10000000ul
#define IFLAGS_TEST 0x20000000ul
#define IFLAGS_IIE_REGS 0x40000000ul
#define IFLAGS_IIGS_REGS 0x80000000ul
#define IFLAGS_V7_MODE0 0x00000000ul
#define IFLAGS_V7_MODE1 0x00000001ul
#define IFLAGS_V7_MODE2 0x00000002ul
#define IFLAGS_V7_MODE3 0x00000003ul

View File

@ -55,3 +55,6 @@
#define CFGTOKEN_TBCOLOR 0x00005456 // "VT\xXX\x00" Custom default TBCOLOR
#define CFGTOKEN_BORDER 0x00004256 // "VB\xXX\x00" Custom default BORDER
#define CFGTOKEN_VIDEO7 0x00003756 // "V7\xXX\x00" Video 7 Enable / Disable
#define CFGTOKEN_RGBCOLOR 0x00005043 // "CP\xXX\x04" RGB Palette Entry Override

View File

@ -68,21 +68,29 @@ bool DELAYED_COPY_CODE(parse_config)(uint32_t address) {
switch(config[i] & 0x0000FFFF) {
case CFGTOKEN_HOST_AUTO:
cfg_machine = MACHINE_AUTO;
internal_flags |= (IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case CFGTOKEN_HOST_II:
cfg_machine = MACHINE_II;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case CFGTOKEN_HOST_IIE:
cfg_machine = MACHINE_IIE;
internal_flags |= IFLAGS_IIE_REGS;
internal_flags &= ~IFLAGS_IIGS_REGS;
break;
case CFGTOKEN_HOST_IIGS:
cfg_machine = MACHINE_IIGS;
internal_flags &= ~IFLAGS_IIE_REGS;
internal_flags |= IFLAGS_IIGS_REGS;
break;
case CFGTOKEN_HOST_PRAVETZ:
cfg_machine = MACHINE_PRAVETZ;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case CFGTOKEN_HOST_BASIS:
cfg_machine = MACHINE_BASIS;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
#ifdef FUNCTION_VGA
case CFGTOKEN_FONT_00:
@ -98,6 +106,17 @@ bool DELAYED_COPY_CODE(parse_config)(uint32_t address) {
case CFGTOKEN_BORDER:
terminal_border = (config[i] >> 16) & 0xF;
break;
case CFGTOKEN_RGBCOLOR:
lores_palette[(config[i] >> 16) & 0xF] = config[i+1];
dhgr_palette[((config[i] >> 17) & 0x7) | ((config[i] >> 13) & 0x8)] = config[i+1];
break;
case CFGTOKEN_VIDEO7:
if((config[i] >> 16) & 1) {
internal_flags |= IFLAGS_VIDEO7;
} else {
internal_flags &= ~IFLAGS_VIDEO7;
}
break;
#elif defined(FUNCTION_Z80)
case CFGTOKEN_MUX_LOOP:
serialmux[(config[i] >> 16) & 1] = SERIAL_LOOP;
@ -172,7 +191,17 @@ void DELAYED_COPY_CODE(default_config)() {
strcpy((char*)wifi_ssid, "V2RetroNet");
strcpy((char*)wifi_psk, "Analog");
#endif
#ifdef ANALOG_GS
cfg_machine = MACHINE_IIGS;
current_machine = MACHINE_IIGS;
internal_flags &= ~IFLAGS_IIE_REGS;
internal_flags |= IFLAGS_IIGS_REGS;
#else
cfg_machine = MACHINE_AUTO;
current_machine = MACHINE_AUTO;
internal_flags |= (IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
#endif
internal_flags |= IFLAGS_VIDEO7;
}
int DELAYED_COPY_CODE(make_config)(uint32_t rev) {
@ -277,6 +306,13 @@ int DELAYED_COPY_CODE(make_config)(uint32_t rev) {
config_temp[i++] = CFGTOKEN_MONO_00 | ((mono_palette & 0xF) << 20);
config_temp[i++] = CFGTOKEN_TBCOLOR | ((terminal_tbcolor & 0xFF) << 16);
config_temp[i++] = CFGTOKEN_BORDER | ((terminal_border & 0xF) << 16);
config_temp[i++] = CFGTOKEN_VIDEO7 | ((internal_flags & IFLAGS_VIDEO7) ? (1ul<<16) : 0);
for(uint32_t j = 0; j < 16; j++) {
config_temp[i++] = CFGTOKEN_RGBCOLOR | (j << 16);
config_temp[i++] = lores_palette[j];
}
#endif
config_temp[i++] = NEWCONFIG_EOF_MARKER;
@ -320,12 +356,14 @@ uint8_t DELAYED_COPY_CODE(get_config_rev)(uint32_t address) {
// Every time we write the config we overwrite the older slot,
// ensuring we don't leave the user without a configuration.
// We increment the revision number each time, wrapping back to 0x00 from 0xFF.
#if 0
bool DELAYED_COPY_CODE(is_primary_config_newer)() {
uint8_t a=get_config_rev(FLASH_CONFIG_PRIMARY);
uint8_t b=get_config_rev(FLASH_CONFIG_SECONDARY);
return ((int8_t)(a-b)) >= 0;
}
#endif
bool DELAYED_COPY_CODE(read_config)() {
if(is_config_valid(FLASH_CONFIG_ONETIME)) {
@ -334,6 +372,13 @@ bool DELAYED_COPY_CODE(read_config)() {
if(parse_config(FLASH_CONFIG_ONETIME))
return true;
}
if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
if(parse_config(FLASH_CONFIG_PRIMARY))
return true;
}
#if 0
if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
if(!is_config_valid(FLASH_CONFIG_SECONDARY) || (is_primary_config_newer())) {
if(parse_config(FLASH_CONFIG_PRIMARY))
@ -344,6 +389,7 @@ bool DELAYED_COPY_CODE(read_config)() {
if(parse_config(FLASH_CONFIG_SECONDARY))
return true;
}
#endif
default_config();
return false;
@ -359,6 +405,10 @@ bool DELAYED_COPY_CODE(write_config)(bool onetime) {
vga_dpms_sleep();
#endif
write_secondary = false;
rev = get_config_rev(FLASH_CONFIG_PRIMARY);
#if 0
if(is_config_valid(FLASH_CONFIG_PRIMARY) && is_config_valid(FLASH_CONFIG_SECONDARY)) {
write_secondary = is_primary_config_newer();
rev = write_secondary ? get_config_rev(FLASH_CONFIG_PRIMARY) : get_config_rev(FLASH_CONFIG_SECONDARY);
@ -369,9 +419,9 @@ bool DELAYED_COPY_CODE(write_config)(bool onetime) {
write_secondary = false;
rev = get_config_rev(FLASH_CONFIG_SECONDARY);
}
#endif
if(make_config(rev + 1) <= CONFIG_SIZE) {
if(onetime) {
flash_range_erase((FLASH_CONFIG_ONETIME-XIP_BASE), CONFIG_SIZE);
flash_range_program((FLASH_CONFIG_ONETIME-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE);
@ -401,6 +451,7 @@ uint8_t DELAYED_COPY_CODE(get_config_block)() {
last_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
next_config_block = last_config_block;
#if 0
if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
if(!is_config_valid(FLASH_CONFIG_SECONDARY) || (is_primary_config_newer())) {
last_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
@ -413,6 +464,7 @@ uint8_t DELAYED_COPY_CODE(get_config_block)() {
last_config_block = (FLASH_CONFIG_SECONDARY-XIP_BASE) / 4096;
next_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
}
#endif
config_rpybuf[5] = (next_config_block >> 8) & 0xFF;
config_rpybuf[4] = (next_config_block >> 0) & 0xFF;
@ -574,6 +626,31 @@ void DELAYED_COPY_CODE(config_handler)() {
config_rpybuf[0] = REPLY_BUSY;
switch(config_cmdbuf[0]) {
case 'P':
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
#ifdef FUNCTION_VGA
case 'r':
memcpy((void *)cfbuf, lores_palette, 16*2);
cfptr = 0;
retval = REPLY_OK;
break;
case 'T':
for(uint j = 0; j < 16; j++) {
#ifdef ANALOG_GS
lores_palette[j] = ((uint16_t *)cfbuf)[j] & 0xFFF;
#else
lores_palette[j] = ((uint16_t *)cfbuf)[j] & 0x1FF;
#endif
}
cfptr = 0;
retval = REPLY_OK;
break;
#endif
}
break;
case 'C':
switch(config_cmdbuf[1]) {
default:

View File

@ -19,9 +19,6 @@
#include <pico/cyw43_arch.h>
#endif
#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)
static void __noinline __time_critical_func(core1_loop)() {
uint32_t value;
uint32_t address;
@ -49,25 +46,25 @@ static void __noinline __time_critical_func(core1_loop)() {
// Config memory in card slot-rom address space
if(ACCESS_WRITE) {
if((address & 0xFF) == 0xEC) {
apple_memory[address] = value;
cfptr = (cfptr & 0x0F00) | value;
apple_memory[address] = (value & 0xff);
cfptr = (cfptr & 0x0F00) | (value & 0xff);
apple_memory[address+2] = cfbuf[cfptr]; // $CnEE
apple_memory[address+3] = cfbuf[cfptr]; // $CnEF
}
if((address & 0xFF) == 0xED) {
apple_memory[address] = value & 0x0F;
apple_memory[address] = (value & 0x0F);
cfptr = ((cfptr & 0xFF) | (((uint16_t)value) << 8)) & 0xFFF;
apple_memory[address+1] = cfbuf[cfptr]; // $CnEE
apple_memory[address+2] = cfbuf[cfptr]; // $CnEF
}
if((address & 0xFF) == 0xEF) {
cfbuf[cfptr] = value;
cfbuf[cfptr] = (value & 0xff);
cfptr = (cfptr + 1) & 0x0FFF;
apple_memory[address-1] = cfbuf[cfptr]; // $CnEE
apple_memory[address] = cfbuf[cfptr]; // $CnEF
}
if((address & 0xFF) >= 0xF0) {
apple_memory[address] = value;
apple_memory[address] = (value & 0xff);
}
} else if((address & 0xFF) == 0xEE) {
cfptr = (cfptr + 1) & 0x0FFF;
@ -79,7 +76,12 @@ static void __noinline __time_critical_func(core1_loop)() {
}
#ifdef FUNCTION_VGA
} else if(current_machine == MACHINE_AUTO) {
if((apple_memory[0x404] == 0xE5) && (apple_memory[0x0403] == 0xD8)) { // ROMXe
if(value & 0x08000000) {
// Hardware jumpered for IIGS mode.
current_machine = MACHINE_IIGS;
internal_flags &= ~IFLAGS_IIE_REGS;
internal_flags |= IFLAGS_IIGS_REGS;
} else if((apple_memory[0x404] == 0xE5) && (apple_memory[0x0403] == 0xD8)) { // ROMXe
current_machine = MACHINE_IIE;
internal_flags |= IFLAGS_IIE_REGS;
internal_flags &= ~IFLAGS_IIGS_REGS;
@ -111,25 +113,27 @@ static void __noinline __time_critical_func(core1_loop)() {
#endif
} else switch(reset_state) {
case 0:
if((value & 0x3FFFF00) == ((0xFFFC << 10) | 0x300))
if((value & 0x7FFFF00) == ((0xFFFC << 10) | 0x300))
reset_state++;
break;
case 1:
if((value & 0x3FFFF00) == ((0xFFFD << 10) | 0x300))
if((value & 0x7FFFF00) == ((0xFFFD << 10) | 0x300))
reset_state++;
else
reset_state=0;
break;
case 2:
if((value & 0x3FFFF00) == ((0xFA62 << 10) | 0x300))
if((value & 0x7FFFF00) == ((0xFA62 << 10) | 0x300))
reset_state++;
else
reset_state=0;
break;
case 3:
#ifdef FUNCTION_VGA
soft_switches = SOFTSW_TEXT_MODE;
soft_switches |= SOFTSW_TEXT_MODE;
soft_switches &= ~SOFTSW_80COL;
soft_switches &= ~SOFTSW_DGR;
internal_flags &= ~(IFLAGS_TERMINAL | IFLAGS_TEST | IFLAGS_V7_MODE3);
#endif
default:
reset_state = 0;

View File

@ -8,16 +8,18 @@
volatile uint8_t *terminal_page = terminal_memory;
void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
// Shadow parts of the Apple's memory by observing the bus write cycles
if((address < 0xC000) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
// Apple IIgs: CARD_SELECT is pulled low by our CPLD when M2B0 is active and addr < $C000
#ifdef ANALOG_GS
if(CARD_SELECT) {
// Apple IIgs: Bit 27 is GS jumper closed, Bit 26 is M2B0
if(value & 0x4000000) {
if(ACCESS_WRITE) {
private_memory[address] = value & 0xff;
return;
}
return;
}
#endif
// Shadow parts of the Apple's memory by observing the bus write cycles
if(ACCESS_WRITE) {
// Mirror Video Memory from MAIN & AUX banks
if(soft_switches & SOFTSW_80STORE) {
if(soft_switches & SOFTSW_PAGE_2) {
@ -46,57 +48,57 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
if((address & 0xff80) == 0xc000) {
switch(address & 0x7f) {
case 0x00:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches &= ~SOFTSW_80STORE;
}
break;
case 0x01:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches |= SOFTSW_80STORE;
}
break;
case 0x04:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches &= ~SOFTSW_AUX_WRITE;
}
break;
case 0x05:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches |= SOFTSW_AUX_WRITE;
}
break;
case 0x08:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches &= ~SOFTSW_AUXZP;
}
break;
case 0x09:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches |= SOFTSW_AUXZP;
}
break;
case 0x0c:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches &= ~SOFTSW_80COL;
}
break;
case 0x0d:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches |= SOFTSW_80COL;
}
break;
case 0x0e:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches &= ~SOFTSW_ALTCHAR;
}
break;
case 0x0f:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
soft_switches |= SOFTSW_ALTCHAR;
}
break;
case 0x21:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ACCESS_WRITE) {
if(value & 0x80) {
soft_switches |= SOFTSW_MONOCHROME;
} else {
@ -105,22 +107,22 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
}
break;
case 0x22:
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIGS_REGS) && ACCESS_WRITE) {
apple_tbcolor = value & 0xff;
}
break;
case 0x29:
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIGS_REGS) && ACCESS_WRITE) {
soft_switches = (soft_switches & ~(SOFTSW_NEWVID_MASK << SOFTSW_NEWVID_SHIFT)) | ((value & SOFTSW_NEWVID_MASK) << SOFTSW_NEWVID_SHIFT);
}
break;
case 0x34:
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIGS_REGS) && ACCESS_WRITE) {
apple_border = value & 0x0f;
}
break;
case 0x35:
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIGS_REGS) && ACCESS_WRITE) {
soft_switches = (soft_switches & ~(SOFTSW_SHADOW_MASK << SOFTSW_SHADOW_SHIFT)) | ((value & SOFTSW_SHADOW_MASK) << SOFTSW_SHADOW_SHIFT);
}
break;
@ -154,17 +156,22 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
}
break;
case 0x5f:
// Video 7 shift register
if(!soft_switches & SOFTSW_DGR) {
internal_flags = (internal_flags & 0xfffffffc) | ((internal_flags & 0x1) << 1) | ((soft_switches & SOFTSW_80COL) ? 1 : 0);
}
if(internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) {
soft_switches &= ~SOFTSW_DGR;
}
break;
case 0x7e:
if((internal_flags & IFLAGS_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIE_REGS) && ACCESS_WRITE) {
soft_switches |= SOFTSW_IOUDIS;
}
break;
case 0x7f:
if((internal_flags & IFLAGS_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIE_REGS) && ACCESS_WRITE) {
soft_switches &= ~SOFTSW_IOUDIS;
}
break;
@ -173,24 +180,24 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
}
// Control sequences used by ROMX and ROMXe
if(value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) {
if(((address >> 8) == 0xCA) || ((address >> 8) == 0xFA)) {
switch(address & 0xFF) {
case 0xCA:
romx_unlocked = (romx_unlocked == 1) ? 2 : 1;
break;
case 0xFE:
romx_unlocked = (romx_unlocked == 2) ? 3 : 0;
if(romx_unlocked == 3)
romx_type = address >> 8;
break;
default:
if(romx_unlocked != 3)
romx_unlocked = 0;
break;
}
} else if(romx_unlocked == 3) {
if(romx_type == 0xFA) {
switch(current_machine) {
case MACHINE_IIE:
// Trigger on read sequence FACA FACA FAFE
if(ACCESS_READ) {
if((address >> 8) == 0xFA) {
switch(address & 0xFF) {
case 0xCA:
romx_unlocked = (romx_unlocked == 1) ? 2 : 1;
break;
case 0xFE:
romx_unlocked = (romx_unlocked == 2) ? 3 : 0;
break;
default:
if(romx_unlocked != 3)
romx_unlocked = 0;
break;
}
} else if(romx_unlocked == 3) {
if((address & 0xFFF0) == 0xF810) {
romx_textbank = address & 0xF;
}
@ -198,7 +205,26 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
romx_changed = 1;
romx_unlocked = 0;
}
} else if(romx_type == 0xCA) {
}
}
break;
case MACHINE_II:
// Trigger on read sequence CACA CACA CAFE
if(ACCESS_READ) {
if((address >> 8) == 0xCA) {
switch(address & 0xFF) {
case 0xCA:
romx_unlocked = (romx_unlocked == 1) ? 2 : 1;
break;
case 0xFE:
romx_unlocked = (romx_unlocked == 2) ? 3 : 0;
break;
default:
if(romx_unlocked != 3)
romx_unlocked = 0;
break;
}
} else if(romx_unlocked == 3) {
if((address & 0xFFF0) == 0xCFD0) {
romx_textbank = address & 0xF;
}
@ -208,20 +234,26 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
}
}
}
break;
}
// Card Registers
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) {
if(ACCESS_WRITE) {
if(CARD_SELECT && CARD_DEVSEL) {
cardslot = (address >> 4) & 0x7;
switch(address & 0x0F) {
case 0x01:
mono_palette = (value >> 4) & 0xF;
if(value & 0x8) {
if(value & 8) {
internal_flags |= IFLAGS_OLDCOLOR;
} else {
internal_flags &= ~IFLAGS_OLDCOLOR;
}
if(value & 4) {
internal_flags |= IFLAGS_VIDEO7;
} else {
internal_flags &= ~IFLAGS_VIDEO7;
}
apple_memory[address] = value;
break;
case 0x02:
@ -233,10 +265,10 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
apple_memory[address] = terminal_border;
break;
case 0x08:
soft_switches &= ~SOFTSW_TERMINAL;
internal_flags &= ~IFLAGS_TERMINAL;
break;
case 0x09:
soft_switches |= SOFTSW_TERMINAL;
internal_flags |= IFLAGS_TERMINAL;
break;
case 0x0A:
terminal_fifo[terminal_fifo_wrptr++] = (value & 0xFF);

View File

@ -213,7 +213,7 @@ void DELAYED_COPY_CODE(render_loop)() {
vga_prepare_frame();
render_shr();
#endif
} else if(soft_switches & SOFTSW_TERMINAL) {
} else if(internal_flags & IFLAGS_TERMINAL) {
vga_prepare_frame();
render_terminal();
} else {

View File

@ -6,6 +6,8 @@
#define RENDER_TEST_PATTERN
extern uint16_t lores_palette[16];
extern uint16_t dhgr_palette[16];
extern uint16_t text_fore, text_back, text_border;
extern uint8_t status_line[81];
extern bool mono_rendering;
@ -25,8 +27,11 @@ extern void render_test_sleep();
extern void update_text_flasher();
extern void render_text();
extern void render_mixed_text();
extern void render_text40_line(bool p2, unsigned int line);
extern void render_text80_line(bool p2, unsigned int line);
extern void render_color_text40_line(unsigned int line);
extern void render_color_text80_line(unsigned int line);
extern void render_status_line();
extern void render_terminal();

View File

@ -9,6 +9,7 @@
uint8_t terminal_jsoffset = 0;
uint8_t terminal_ssoffset = 0;
bool terminal_inverse = 0;
bool terminal_esc = 0;
bool terminal_esc_crz = 0;
int terminal_esc_pos = 0;
@ -26,15 +27,19 @@ static inline uint_fast8_t char_terminal_bits(uint_fast8_t ch, uint_fast8_t glyp
return (bits & 0x7f);
}
static void DELAYED_COPY_CODE(terminal_scroll)() {
// Clear the next text buffer line (using dma if possible)
memset((void*)(terminal_memory+(((terminal_height+terminal_jsoffset) * 128) & 0xFFF)), ' ', 128);
// Smooth scroll then increment jsoffset
terminal_ssoffset = 1;
}
static void DELAYED_COPY_CODE(terminal_linefeed)() {
if(terminal_row < (terminal_height-1)) {
terminal_row++;
} else {
// Clear the next text buffer line (using dma if possible)
memset((void*)(terminal_memory+(((terminal_row+1+terminal_jsoffset) * 128) & 0xFFF)), ' ', 128);
// Smooth scroll then increment jsoffset
terminal_ssoffset = 1;
terminal_scroll();
}
}
@ -89,7 +94,7 @@ void DELAYED_COPY_CODE(terminal_process_input)() {
terminal_clear_screen();
break;
case '1':
soft_switches &= ~SOFTSW_TERMINAL;
internal_flags &= ~IFLAGS_TERMINAL;
break;
case '2':
terminal_charset = 0;
@ -104,17 +109,30 @@ void DELAYED_COPY_CODE(terminal_process_input)() {
}
terminal_esc_crz = false;
} else if(terminal_esc) {
terminal_esc = false;
switch(ch) {
case 'K':
case '>':
terminal_esc = true;
case 'A':
terminal_advance_cursor();
break;
case 'J':
case '<':
terminal_esc = true;
case 'B':
if(terminal_col > 0)
terminal_col--;
break;
case 'M':
case 'v':
terminal_esc = true;
case 'C':
terminal_linefeed();
break;
case 'I':
case '^':
terminal_esc = true;
case 'D': // Reverse Linefeed
if(terminal_row > 0)
terminal_row--;
@ -128,14 +146,25 @@ void DELAYED_COPY_CODE(terminal_process_input)() {
case '@': // Clear screen
terminal_clear_screen();
break;
case '4':
internal_flags &= ~IFLAGS_TERMINAL;
break;
case '8':
internal_flags |= IFLAGS_TERMINAL;
break;
default:
terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch;
terminal_advance_cursor();
break;
}
terminal_esc = false;
} else
switch(ch) {
case 0x07:
break;
case 0x08:
if(terminal_col > 0)
terminal_col--;
break;
case 0x0A: // Line Feed
terminal_linefeed();
break;
@ -148,10 +177,25 @@ void DELAYED_COPY_CODE(terminal_process_input)() {
case 0x0D: // Ctrl-M: Carriage Return
terminal_col = 0;
break;
case 0x0E: // Normal Text
terminal_inverse = false;
break;
case 0x0F: // Inverse Text
terminal_inverse = true;
break;
case 0x11:
internal_flags &= ~IFLAGS_TERMINAL;
break;
case 0x12:
internal_flags |= IFLAGS_TERMINAL;
break;
case 0x13: // Ctrl-S: Xon/Xoff (unimplemented)
break;
case 0x15: // Ctrl-U: Copy (unimplemented)
break;
case 0x17: // Ctrl-W: Scroll one line without moving cursor
terminal_scroll();
break;
case 0x19: // Ctrl-Y: Home Cursor
terminal_row = 0;
terminal_col = 0;
@ -176,7 +220,7 @@ void DELAYED_COPY_CODE(terminal_process_input)() {
terminal_row--;
break;
default:
terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch;
terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch ^ (terminal_inverse ? 0x80 : 0x00);
terminal_advance_cursor();
break;
}

View File

@ -30,13 +30,7 @@ void DELAYED_COPY_CODE(render_mixed_dgr)() {
render_dgr_line(PAGE2SEL, line);
}
for(uint line=20; line < 24; line++) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
} else {
render_text40_line(PAGE2SEL, line);
}
}
render_mixed_text();
}

View File

@ -25,27 +25,25 @@ static inline uint dhgr_line_to_mem_offset(uint line) {
void DELAYED_COPY_CODE(render_dhgr)() {
if((internal_flags & IFLAGS_VIDEO7) && (internal_flags & IFLAGS_V7_MODE3 == IFLAGS_V7_MODE3)) {
mono_rendering = true;
}
for(uint line=0; line < 192; line++) {
render_dhgr_line(PAGE2SEL, line);
}
}
void DELAYED_COPY_CODE(render_mixed_dhgr)() {
if((internal_flags & IFLAGS_VIDEO7) && (internal_flags & IFLAGS_V7_MODE3 == IFLAGS_V7_MODE3)) {
mono_rendering = true;
}
for(uint line=0; line < 160; line++) {
render_dhgr_line(PAGE2SEL, line);
}
for(uint line=20; line < 24; line++) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
} else {
render_text40_line(PAGE2SEL, line);
}
}
render_mixed_text();
}
static void DELAYED_COPY_CODE(render_dhgr_line)(bool p2, uint line) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
@ -54,10 +52,17 @@ static void DELAYED_COPY_CODE(render_dhgr_line)(bool p2, uint line) {
const uint8_t *line_mema = (const uint8_t *)((p2 ? hgr_p2 : hgr_p1) + dhgr_line_to_mem_offset(line));
const uint8_t *line_memb = (const uint8_t *)((p2 ? hgr_p4 : hgr_p3) + dhgr_line_to_mem_offset(line));
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word
if((internal_flags & IFLAGS_VIDEO7) && ((internal_flags & IFLAGS_V7_MODE3) == IFLAGS_V7_MODE1)) {
// Pad 30 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_7) << 16); // 12 pixels per word
sl->data[sl_pos++] = (text_border) | ((text_border) << 16); // 2 pixels per word
} else {
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word
}
// DHGR is weird. Nuff said.
uint32_t dots = 0;
@ -86,6 +91,27 @@ static void DELAYED_COPY_CODE(render_dhgr_line)(bool p2, uint line) {
dotc -= 2;
}
}
} else if((internal_flags & IFLAGS_VIDEO7) && ((internal_flags & IFLAGS_V7_MODE3) == IFLAGS_V7_MODE1)) {
while(i < 40) {
// Load in as many subpixels as possible
while((dotc <= 18) && (i < 40)) {
dots |= (line_memb[i] & 0xff) << dotc;
dotc += 8;
dots |= (line_mema[i] & 0xff) << dotc;
dotc += 8;
i++;
}
// Consume pixels
while(dotc >= 8) {
pixeldata = (dhgr_palette[dots & 0xf] | THEN_EXTEND_3);
dots >>= 4;
pixeldata |= (dhgr_palette[dots & 0xf] | THEN_EXTEND_3) << 16;
dots >>= 4;
sl->data[sl_pos++] = pixeldata;
dotc -= 8;
}
}
} else if(internal_flags & IFLAGS_OLDCOLOR) {
while(i < 40) {
// Load in as many subpixels as possible
@ -149,10 +175,17 @@ static void DELAYED_COPY_CODE(render_dhgr_line)(bool p2, uint line) {
sl->data[sl_pos++] = pixeldata;
}
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word
if((internal_flags & IFLAGS_VIDEO7) && ((internal_flags & IFLAGS_V7_MODE3) == IFLAGS_V7_MODE1)) {
// Pad 30 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_7) << 16); // 12 pixels per word
sl->data[sl_pos++] = (text_border) | ((text_border) << 16); // 2 pixels per word
} else {
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word
}
sl->length = sl_pos;
sl->repeat_count = 1;

View File

@ -29,13 +29,7 @@ void DELAYED_COPY_CODE(render_mixed_hires)() {
render_hires_line(PAGE2SEL, line);
}
for(uint line=20; line < 24; line++) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
} else {
render_text40_line(PAGE2SEL, line);
}
}
render_mixed_text();
}
static void DELAYED_COPY_CODE(render_hires_line)(bool p2, uint line) {

View File

@ -48,13 +48,7 @@ void DELAYED_COPY_CODE(render_mixed_lores)() {
render_lores_line(PAGE2SEL, line);
}
for(uint line=20; line < 24; line++) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
} else {
render_text40_line(PAGE2SEL, line);
}
}
render_mixed_text();
}

View File

@ -4,6 +4,8 @@
#include "vga/render.h"
#include "vga/vgaout.h"
extern uint16_t lores_palette[16];
//#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2))
#define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2)
@ -48,11 +50,53 @@ static inline uint_fast8_t char_text_bits(uint_fast8_t ch, uint_fast8_t glyph_li
}
void DELAYED_COPY_CODE(render_text)() {
for(uint line=0; line < 24; line++) {
uint line;
if((internal_flags & IFLAGS_VIDEO7) && !(soft_switches & SOFTSW_DGR)) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
for(line=0; line < 24; line++) {
render_color_text80_line(line);
}
} else {
render_text40_line(PAGE2SEL, line);
for(line=0; line < 24; line++) {
render_color_text40_line(line);
}
}
} else {
if(soft_switches & SOFTSW_80COL) {
for(line=0; line < 24; line++) {
render_text80_line(PAGE2SEL, line);
}
} else {
for(line=0; line < 24; line++) {
render_text40_line(PAGE2SEL, line);
}
}
}
}
void DELAYED_COPY_CODE(render_mixed_text)() {
uint line;
if((internal_flags & IFLAGS_VIDEO7) && !(soft_switches & SOFTSW_DGR)) {
if(soft_switches & SOFTSW_80COL) {
for(line=20; line < 24; line++) {
render_color_text80_line(line);
}
} else {
for(line=20; line < 24; line++) {
render_color_text40_line(line);
}
}
} else {
if(soft_switches & SOFTSW_80COL) {
for(line=20; line < 24; line++) {
render_text80_line(PAGE2SEL, line);
}
} else {
for(line=20; line < 24; line++) {
render_text40_line(PAGE2SEL, line);
}
}
}
}
@ -150,3 +194,146 @@ void DELAYED_COPY_CODE(render_text80_line)(bool p2, unsigned int line) {
}
}
void DELAYED_COPY_CODE(render_color_text40_line)(unsigned int line) {
const uint8_t *line_buf = (const uint8_t *)(text_p1 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
const uint8_t *color_buf = (const uint8_t *)(text_p3 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
for(uint glyph_line=0; glyph_line < 8; glyph_line++) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
for(uint col=0; col < 40; ) {
// Grab 14 pixels from the next two characters
uint32_t bits_a = char_text_bits(line_buf[col], glyph_line);
uint16_t color1 = lores_palette[(color_buf[col] >> 4) & 0xf];
uint16_t color2 = lores_palette[color_buf[col] & 0xf];
col++;
uint32_t bits_b = char_text_bits(line_buf[col], glyph_line);
uint16_t color3 = lores_palette[(color_buf[col] >> 4) & 0xf];
uint16_t color4 = lores_palette[color_buf[col] & 0xf];
col++;
uint32_t bits = (bits_a << 7) | bits_b;
uint32_t pixeldata;
// Translate each pair of bits into a pair of pixels
for(int i=0; i < 3; i++) {
pixeldata = (bits & 0x2000) ? (color2|THEN_EXTEND_1) : (color1|THEN_EXTEND_1);
pixeldata |= (bits & 0x1000) ?
(uint32_t)(color2|THEN_EXTEND_1) << 16 :
(uint32_t)(color1|THEN_EXTEND_1) << 16;
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
}
pixeldata = (bits & 0x2000) ? (color2|THEN_EXTEND_1) : (color1|THEN_EXTEND_1);
pixeldata |= (bits & 0x1000) ?
(uint32_t)(color4|THEN_EXTEND_1) << 16 :
(uint32_t)(color3|THEN_EXTEND_1) << 16;
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
for(int i=4; i < 7; i++) {
pixeldata = (bits & 0x2000) ? (color4|THEN_EXTEND_1) : (color3|THEN_EXTEND_1);
pixeldata |= (bits & 0x1000) ?
(uint32_t)(color4|THEN_EXTEND_1) << 16 :
(uint32_t)(color3|THEN_EXTEND_1) << 16;
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
}
}
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
sl->length = sl_pos;
sl->repeat_count = 1;
vga_submit_scanline(sl);
}
}
void DELAYED_COPY_CODE(render_color_text80_line)(unsigned int line) {
const uint8_t *line_buf_a = (const uint8_t *)(text_p1 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
const uint8_t *line_buf_b = (const uint8_t *)(text_p3 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
const uint8_t *color_buf_a = (const uint8_t *)(text_p2 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
const uint8_t *color_buf_b = (const uint8_t *)(text_p4 + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
for(uint glyph_line=0; glyph_line < 8; glyph_line++) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
for(uint col=0; col < 40; ) {
// Grab 14 pixels from the next two characters
uint32_t bits_a = char_text_bits(line_buf_a[col], glyph_line);
uint32_t bits_b = char_text_bits(line_buf_b[col], glyph_line);
uint16_t color1 = lores_palette[color_buf_a[col] >> 4];
uint16_t color2 = lores_palette[color_buf_a[col] & 0xF];
uint16_t color3 = lores_palette[color_buf_b[col] >> 4];
uint16_t color4 = lores_palette[color_buf_b[col] & 0xF];
col++;
uint32_t bits = (bits_b << 7) | bits_a;
uint32_t pixeldata;
// Translate each pair of bits into a pair of pixels
for(int i=0; i < 3; i++) {
pixeldata = (bits & 0x2000) ? (color2) : (color1);
pixeldata |= (bits & 0x1000) ?
(uint32_t)(color2) << 16 :
(uint32_t)(color1) << 16;
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
}
pixeldata = (bits & 0x2000) ? (color2) : (color1);
pixeldata |= (bits & 0x1000) ?
(uint32_t)(color4) << 16 :
(uint32_t)(color3) << 16;
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
for(int i=4; i < 7; i++) {
pixeldata = (bits & 0x2000) ? (color4) : (color3);
pixeldata |= (bits & 0x1000) ?
(uint32_t)(color4) << 16 :
(uint32_t)(color3) << 16;
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
}
}
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
sl->length = sl_pos;
sl->repeat_count = 1;
vga_submit_scanline(sl);
}
}