mirror of
https://github.com/V2RetroComputing/analog.git
synced 2024-11-28 19:49:45 +00:00
Firmware Release 23-01-16-119
New autodetect routines for Apple II+, IIe (Platinum), IIgs (ROM03). Timing tweaks to improve compatibility on IIgs and IIe. Corrected text rendering on all supported machines. Initial Super HiRes support (not recommended to use at this time) Monochrome DHGR and HGR support activated with IIgs MONOCOLOR or NEWVID registers. 80 Column mode on IIe and IIgs.
This commit is contained in:
parent
c62efee7ee
commit
d9be2ed9cd
@ -29,6 +29,8 @@ target_sources(v2-analog-${PICO_BOARD} PUBLIC
|
||||
common/main.c
|
||||
diag/businterface.c
|
||||
diag/diag.c
|
||||
fs/businterface.c
|
||||
fs/fs.c
|
||||
vga/vgamain.c
|
||||
vga/businterface.c
|
||||
vga/vgabuf.c
|
||||
@ -36,9 +38,10 @@ target_sources(v2-analog-${PICO_BOARD} PUBLIC
|
||||
vga/render_hires.c
|
||||
vga/render_lores.c
|
||||
vga/render_text.c
|
||||
vga/render_terminal.c
|
||||
vga/render_videx.c
|
||||
vga/render_dhgr.c
|
||||
vga/render_dgr.c
|
||||
vga/render_shr.c
|
||||
vga/render_test.c
|
||||
vga/terminal_rom.c
|
||||
vga/character_rom.c
|
||||
@ -61,11 +64,16 @@ target_link_libraries(v2-analog-${PICO_BOARD} PUBLIC
|
||||
pico_multicore
|
||||
pico_stdlib
|
||||
littlefs-lib
|
||||
pico_cyw43_arch_lwip_poll
|
||||
hardware_dma
|
||||
hardware_pio
|
||||
)
|
||||
|
||||
if(${PICO_BOARD} MATCHES "pico_w")
|
||||
target_link_libraries(v2-analog-${PICO_BOARD} PUBLIC
|
||||
pico_cyw43_arch_lwip_poll
|
||||
)
|
||||
endif(${PICO_BOARD} MATCHES "pico_w")
|
||||
|
||||
pico_enable_stdio_usb(v2-analog-${PICO_BOARD} 0)
|
||||
pico_enable_stdio_uart(v2-analog-${PICO_BOARD} 0)
|
||||
|
||||
|
@ -33,9 +33,9 @@ next_bus_cycle:
|
||||
write_cycle:
|
||||
; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions)
|
||||
|
||||
set PINS, 0b110 [15] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+200ns)
|
||||
set PINS, 0b110 [14] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+200ns)
|
||||
in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush
|
||||
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
|
||||
wait 0 GPIO, PHI0_GPIO [6] ; wait for PHI0 to fall
|
||||
jmp next_bus_cycle
|
||||
|
||||
read_cycle:
|
||||
@ -45,7 +45,7 @@ read_cycle:
|
||||
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
|
||||
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
|
||||
wait 0 GPIO, PHI0_GPIO [6] ; wait for PHI0 to fall
|
||||
wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control
|
||||
.wrap
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern volatile uint8_t config_memory[32];
|
||||
@ -48,3 +50,47 @@ extern volatile uint8_t *slot7rom;
|
||||
|
||||
/* Videx VideoTerm */
|
||||
extern volatile uint8_t *videx_page;
|
||||
|
||||
extern volatile uint32_t soft_switches;
|
||||
|
||||
#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
|
||||
|
||||
// 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_NEWVID_MASK 0xE0
|
||||
#define SOFTSW_NEWVID_SHIFT 11
|
||||
|
||||
#define SOFTSW_MONOCHROME 0x00010000
|
||||
#define SOFTSW_LINEARIZE 0x00020000
|
||||
#define SOFTSW_SHR 0x00040000
|
||||
|
||||
#define SOFTSW_IOUDIS 0x00080000
|
||||
|
||||
#define SOFTSW_SHADOW_MASK 0x7F
|
||||
#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
|
||||
|
||||
// V2 Analog specific softswitches
|
||||
#define SOFTSW_VIDEX 0x10000000
|
||||
#define SOFTSW_TEST 0x20000000
|
||||
#define SOFTSW_IIE_REGS 0x40000000
|
||||
#define SOFTSW_IIGS_REGS 0x80000000
|
||||
|
@ -8,13 +8,18 @@ v2mode_t v2mode;
|
||||
usbmux_t usbmux;
|
||||
serialmux_t serialmux;
|
||||
wifimode_t wifimode;
|
||||
compat_t machine;
|
||||
uint8_t wifi_ssid[32];
|
||||
uint8_t wifi_psk[32];
|
||||
|
||||
extern bool userfont;
|
||||
|
||||
void parse_config(uint8_t *buffer) {
|
||||
if(!memcmp("MODE=", buffer, 5)) {
|
||||
if(!strcmp("DIAG", buffer+5)) {
|
||||
v2mode = MODE_DIAG;
|
||||
} else if(!strcmp("FS", buffer+5)) {
|
||||
v2mode = MODE_FS;
|
||||
} else if(!strcmp("VGA", buffer+5)) {
|
||||
v2mode = MODE_VGACARD;
|
||||
} else if(!strcmp("Z80", buffer+5)) {
|
||||
@ -26,6 +31,18 @@ void parse_config(uint8_t *buffer) {
|
||||
} else if(!strcmp("SNESMAX", buffer+5)) {
|
||||
v2mode = MODE_SNESMAX;
|
||||
}
|
||||
} else if(!memcmp("MACHINE=", buffer, 8)) {
|
||||
if(!strcmp("II", buffer+8)) {
|
||||
machine = APPLE_II;
|
||||
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
|
||||
} else if(!strcmp("IIE", buffer+8)) {
|
||||
machine = APPLE_IIE;
|
||||
soft_switches &= ~SOFTSW_IIGS_REGS;
|
||||
soft_switches |= SOFTSW_IIE_REGS;
|
||||
} else if(!strcmp("IIGS", buffer+8)) {
|
||||
machine = APPLE_IIGS;
|
||||
soft_switches |= SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS;
|
||||
}
|
||||
} else if(!memcmp("MUX=", buffer, 4)) {
|
||||
if(!strcmp("USB", buffer+4)) {
|
||||
serialmux = SERIAL_USB;
|
||||
@ -62,6 +79,8 @@ void default_config() {
|
||||
wifimode = WIFI_AP;
|
||||
strcpy(wifi_ssid, "V2RetroNet");
|
||||
strcpy(wifi_psk, "Analog");
|
||||
machine = COMPAT_AUTO;
|
||||
soft_switches = 0;
|
||||
}
|
||||
|
||||
void write_config() {
|
||||
@ -75,6 +94,11 @@ void write_config() {
|
||||
return;
|
||||
|
||||
switch(v2mode) {
|
||||
case MODE_FS:
|
||||
memset(config_temp, 0, sizeof(config_temp));
|
||||
strcpy(config_temp, "MODE=FS");
|
||||
pico_write(file, config_temp, 32);
|
||||
break;
|
||||
case MODE_VGACARD:
|
||||
memset(config_temp, 0, sizeof(config_temp));
|
||||
strcpy(config_temp, "MODE=VGA");
|
||||
@ -106,6 +130,23 @@ void write_config() {
|
||||
pico_write(file, config_temp, 32);
|
||||
break;
|
||||
}
|
||||
switch(machine) {
|
||||
case APPLE_II:
|
||||
memset(config_temp, 0, sizeof(config_temp));
|
||||
strcpy(config_temp, "MACHINE=II");
|
||||
pico_write(file, config_temp, 32);
|
||||
break;
|
||||
case APPLE_IIE:
|
||||
memset(config_temp, 0, sizeof(config_temp));
|
||||
strcpy(config_temp, "MACHINE=IIE");
|
||||
pico_write(file, config_temp, 32);
|
||||
break;
|
||||
case APPLE_IIGS:
|
||||
memset(config_temp, 0, sizeof(config_temp));
|
||||
strcpy(config_temp, "MACHINE=IIGS");
|
||||
pico_write(file, config_temp, 32);
|
||||
break;
|
||||
}
|
||||
switch(serialmux) {
|
||||
case SERIAL_USB:
|
||||
memset(config_temp, 0, sizeof(config_temp));
|
||||
@ -185,10 +226,19 @@ void read_config() {
|
||||
pico_close(file);
|
||||
}
|
||||
|
||||
volatile uint8_t *videx_page_tmp = (private_memory+0xF000);
|
||||
extern uint8_t character_rom[4096];
|
||||
|
||||
void config_handler() {
|
||||
if(config_memory[31] != 0) return;
|
||||
|
||||
if(!strcmp("WRITE_CONFIG", (uint8_t*)config_memory)) {
|
||||
if(!strcmp("BANK=SAVE", (uint8_t*)config_memory)) {
|
||||
videx_page_tmp = videx_page;
|
||||
} else if(!strcmp("BANK=RESTORE", (uint8_t*)config_memory)) {
|
||||
videx_page = videx_page_tmp;
|
||||
} else if(!memcmp("BANK=FONT", (uint8_t*)config_memory, 9)) {
|
||||
videx_page = character_rom + (((config_memory[9] - '0') & 3) * 1024);
|
||||
} else if(!strcmp("WRITE_CONFIG", (uint8_t*)config_memory)) {
|
||||
write_config();
|
||||
} else if(!strcmp("REBOOT", (uint8_t*)config_memory)) {
|
||||
v2mode = MODE_REBOOT;
|
||||
|
@ -20,6 +20,7 @@
|
||||
typedef enum {
|
||||
MODE_REBOOT = 0,
|
||||
MODE_DIAG,
|
||||
MODE_FS,
|
||||
MODE_VGACARD,
|
||||
MODE_APPLICARD,
|
||||
MODE_SERIAL,
|
||||
@ -54,6 +55,15 @@ typedef enum {
|
||||
|
||||
extern wifimode_t wifimode;
|
||||
|
||||
typedef enum {
|
||||
APPLE_II = 0,
|
||||
APPLE_IIE = 1,
|
||||
APPLE_IIGS = 2,
|
||||
COMPAT_AUTO = 0xff
|
||||
} compat_t;
|
||||
|
||||
extern compat_t machine;
|
||||
|
||||
enum {
|
||||
ABUS_MAIN_SM = 0,
|
||||
ABUS_DEVICE_READ_SM = 1,
|
||||
|
@ -1,11 +1,14 @@
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/cyw43_arch.h>
|
||||
#include <pico/multicore.h>
|
||||
#include <hardware/flash.h>
|
||||
#include <hardware/watchdog.h>
|
||||
#include <hardware/resets.h>
|
||||
#include "config.h"
|
||||
|
||||
#ifdef RASPBERRYPI_PICO_W
|
||||
#include <pico/cyw43_arch.h>
|
||||
#endif
|
||||
|
||||
void flash_reboot() __attribute__ ((noreturn));
|
||||
|
||||
// Reboot the Pico
|
||||
|
@ -20,6 +20,11 @@ static void core1_loop() {
|
||||
diag_businterface();
|
||||
core1_running = 0;
|
||||
break;
|
||||
case MODE_FS:
|
||||
core1_running = 1;
|
||||
fs_businterface();
|
||||
core1_running = 0;
|
||||
break;
|
||||
case MODE_VGACARD:
|
||||
core1_running = 1;
|
||||
vga_businterface();
|
||||
@ -53,6 +58,9 @@ static void core0_loop() {
|
||||
case MODE_DIAG:
|
||||
diagmain();
|
||||
break;
|
||||
case MODE_FS:
|
||||
fsmain();
|
||||
break;
|
||||
case MODE_VGACARD:
|
||||
vgamain();
|
||||
break;
|
||||
@ -84,6 +92,8 @@ int main() {
|
||||
// Sensible defaults if there is no config / fs
|
||||
default_config();
|
||||
|
||||
multicore_launch_core1(core1_loop);
|
||||
|
||||
// Try mounting the LittleFS, or format if it isn't there.
|
||||
if(pico_mount(0) == LFS_ERR_OK) {
|
||||
read_config();
|
||||
@ -91,8 +101,6 @@ int main() {
|
||||
read_config();
|
||||
}
|
||||
|
||||
multicore_launch_core1(core1_loop);
|
||||
|
||||
core0_loop();
|
||||
|
||||
return 0;
|
||||
|
@ -14,4 +14,7 @@ void parallel_businterface();
|
||||
void diag_businterface();
|
||||
void diagmain();
|
||||
|
||||
void fs_businterface();
|
||||
void fsmain();
|
||||
|
||||
void flash_reboot() __attribute__ ((noreturn));
|
||||
|
95
v2-analog-rev1/fs/businterface.c
Normal file
95
v2-analog-rev1/fs/businterface.c
Normal file
@ -0,0 +1,95 @@
|
||||
#include <string.h>
|
||||
#include <hardware/pio.h>
|
||||
#include "common/config.h"
|
||||
#include "common/buffers.h"
|
||||
#include "abus.pio.h"
|
||||
#include "fs/businterface.h"
|
||||
#include "fs/fs.h"
|
||||
|
||||
static inline void __time_critical_func(shadow_memory)(uint32_t address, uint32_t value) {
|
||||
// Shadow parts of the Apple's memory by observing the bus write cycles
|
||||
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) {
|
||||
if(address < 0x200) {
|
||||
if((soft_switches & (SOFTSW_80STORE | SOFTSW_AUXZP)) == (SOFTSW_80STORE | SOFTSW_AUXZP)) {
|
||||
private_memory[address] = value & 0xff;
|
||||
} else {
|
||||
apple_memory[address] = value & 0xff;
|
||||
}
|
||||
} else if((address < 0xC000) || (address >= 0xD000)) {
|
||||
if((soft_switches & (SOFTSW_80STORE | SOFTSW_AUX_WRITE)) == (SOFTSW_80STORE | SOFTSW_AUX_WRITE)) {
|
||||
private_memory[address] = value & 0xff;
|
||||
} else {
|
||||
apple_memory[address] = value & 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(CARD_SELECT) {
|
||||
if(CARD_DEVSEL) {
|
||||
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) {
|
||||
apple_memory[address] = value;
|
||||
if((address & 0xCF8F) == 0xC08F)
|
||||
fs_handler((address & 0x70) >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
if(CARD_IOSTROBE) {
|
||||
apple_memory[address] = value;
|
||||
}
|
||||
|
||||
// Config memory in card slot-rom address space
|
||||
if(CARD_IOSEL) {
|
||||
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) {
|
||||
config_memory[address & 0x1F] = value;
|
||||
if((address & 0xFF) == 0xFF)
|
||||
config_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shadow the soft-switches by observing all read & write bus cycles
|
||||
if((soft_switches & SOFTSW_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
if((address & 0xff80) == 0xc000) {
|
||||
switch(address & 0x7f) {
|
||||
case 0x00:
|
||||
soft_switches &= ~SOFTSW_80STORE;
|
||||
break;
|
||||
case 0x01:
|
||||
soft_switches |= SOFTSW_80STORE;
|
||||
break;
|
||||
case 0x04:
|
||||
soft_switches &= ~SOFTSW_AUX_WRITE;
|
||||
break;
|
||||
case 0x05:
|
||||
soft_switches |= SOFTSW_AUX_WRITE;
|
||||
break;
|
||||
case 0x08:
|
||||
soft_switches &= ~SOFTSW_AUXZP;
|
||||
break;
|
||||
case 0x09:
|
||||
soft_switches |= SOFTSW_AUXZP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void __time_critical_func(fs_businterface)() {
|
||||
while(v2mode == MODE_DIAG) {
|
||||
uint32_t value = pio_sm_get_blocking(CONFIG_ABUS_PIO, ABUS_MAIN_SM);
|
||||
uint32_t dout;
|
||||
uint32_t address = (value >> 10) & 0xffff;
|
||||
|
||||
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) != 0) {
|
||||
if(CARD_SELECT) {
|
||||
dout = apple_memory[address];
|
||||
|
||||
// device read access
|
||||
pio_sm_put_blocking(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, dout);
|
||||
}
|
||||
}
|
||||
|
||||
shadow_memory(address, value);
|
||||
}
|
||||
}
|
3
v2-analog-rev1/fs/businterface.h
Normal file
3
v2-analog-rev1/fs/businterface.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void diag_businterface();
|
231
v2-analog-rev1/fs/fs.c
Normal file
231
v2-analog-rev1/fs/fs.c
Normal file
@ -0,0 +1,231 @@
|
||||
#include <string.h>
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/multicore.h>
|
||||
#include "common/config.h"
|
||||
#include "common/buffers.h"
|
||||
#include "fs/businterface.h"
|
||||
#include "fs/fs.h"
|
||||
#include "pico_hal.h"
|
||||
|
||||
typedef struct {
|
||||
int handle;
|
||||
bool valid;
|
||||
} fs_file_t;
|
||||
|
||||
#define FS_MAXFILE 8
|
||||
fs_file_t fs_file[FS_MAXFILE];
|
||||
|
||||
void fs_open(volatile uint8_t *fsregs) {
|
||||
int file;
|
||||
for(int i = 0; i < FS_MAXFILE; i++) {
|
||||
if(!fs_file[i].valid) {
|
||||
int flags = 0;
|
||||
if(fsregs[FS_FLAGS] & FS_O_RD)
|
||||
flags |= LFS_O_RDONLY;
|
||||
if(fsregs[FS_FLAGS] & FS_O_WR)
|
||||
flags |= LFS_O_WRONLY;
|
||||
if(fsregs[FS_FLAGS] & FS_O_CREATE)
|
||||
flags |= LFS_O_CREAT;
|
||||
if(fsregs[FS_FLAGS] & FS_O_APPEND)
|
||||
flags |= LFS_O_APPEND;
|
||||
if(fsregs[FS_FLAGS] & FS_O_EXISTING)
|
||||
flags |= LFS_O_EXCL;
|
||||
if(fsregs[FS_FLAGS] & FS_O_TRUNC)
|
||||
flags |= LFS_O_TRUNC;
|
||||
|
||||
if((flags & LFS_O_RDWR) != 0) {
|
||||
// Ensure pathname is 128 bytes or less.
|
||||
apple_memory[0xC880] = 0x00;
|
||||
file = pico_open((char*)(apple_memory + 0xC800), flags);
|
||||
} else {
|
||||
fsregs[FS_STATUS] = FS_ERR_INVAL;
|
||||
fsregs[FS_FILE] = FS_ERR_INVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
if(file < 0) {
|
||||
fsregs[FS_STATUS] = file;
|
||||
fsregs[FS_FILE] = file;
|
||||
return;
|
||||
} else {
|
||||
fs_file[i].handle = file;
|
||||
fs_file[i].valid = true;
|
||||
fsregs[FS_STATUS] = FS_ERR_OK;
|
||||
fsregs[FS_FILE] = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fsregs[FS_STATUS] = FS_ERR_NOMEM;
|
||||
}
|
||||
|
||||
void fs_close(volatile uint8_t *fsregs) {
|
||||
int i = fsregs[FS_FILE];
|
||||
if((i >= FS_MAXFILE) || (!fs_file[i].valid) || (fs_file[i].handle < 0)) {
|
||||
fsregs[FS_STATUS] = FS_ERR_INVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
pico_close(fs_file[i].handle);
|
||||
fs_file[i].handle = -1;
|
||||
fs_file[i].valid = false;
|
||||
}
|
||||
|
||||
void fs_read(volatile uint8_t *fsregs) {
|
||||
int i = fsregs[FS_FILE];
|
||||
uint16_t size = (((uint16_t)fsregs[FS_OFFMSB]) << 8) | ((uint16_t)fsregs[FS_SIZELSB]);
|
||||
|
||||
if((i >= FS_MAXFILE) || (!fs_file[i].valid) || (fs_file[i].handle < 0) || (size > 512)) {
|
||||
fsregs[FS_STATUS] = FS_ERR_INVAL;
|
||||
return;
|
||||
}
|
||||
if(size == 0) {
|
||||
fsregs[FS_STATUS] = FS_ERR_OK;
|
||||
}
|
||||
|
||||
int rv = pico_read(fs_file[i].handle, (uint8_t*)(apple_memory+0xC800), size);
|
||||
if(rv < 0) {
|
||||
fsregs[FS_STATUS] = rv;
|
||||
} else {
|
||||
fsregs[FS_SIZELSB] = rv & 0xFF;
|
||||
fsregs[FS_SIZEMSB] = (rv >> 8);
|
||||
fsregs[FS_STATUS] = FS_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void fs_write(volatile uint8_t *fsregs) {
|
||||
int i = fsregs[FS_FILE];
|
||||
uint16_t size = (((uint16_t)fsregs[FS_OFFMSB]) << 8) | ((uint16_t)fsregs[FS_SIZELSB]);
|
||||
|
||||
if((i >= FS_MAXFILE) || (!fs_file[i].valid) || (fs_file[i].handle < 0) || (size > 512)) {
|
||||
fsregs[FS_STATUS] = FS_ERR_INVAL;
|
||||
return;
|
||||
}
|
||||
if(size == 0) {
|
||||
fsregs[FS_STATUS] = FS_ERR_OK;
|
||||
}
|
||||
|
||||
int rv = pico_write(fs_file[i].handle, (uint8_t*)(apple_memory+0xC800), size);
|
||||
if(rv < 0) {
|
||||
fsregs[FS_STATUS] = rv;
|
||||
} else {
|
||||
fsregs[FS_SIZELSB] = rv & 0xFF;
|
||||
fsregs[FS_SIZEMSB] = (rv >> 8);
|
||||
fsregs[FS_STATUS] = FS_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void fs_seek(volatile uint8_t *fsregs) {
|
||||
int i = fsregs[FS_FILE];
|
||||
int16_t off = (int16_t)((((uint16_t)fsregs[FS_OFFMSB]) << 8) | ((uint16_t)fsregs[FS_OFFLSB]));
|
||||
int whence = fsregs[FS_WHENCE];
|
||||
|
||||
if((i >= FS_MAXFILE) || (!fs_file[i].valid) || (fs_file[i].handle < 0)) {
|
||||
fsregs[FS_STATUS] = FS_ERR_INVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
int rv = pico_lseek(fs_file[i].handle, off, whence);
|
||||
if(rv < 0) {
|
||||
fsregs[FS_STATUS] = rv;
|
||||
} else {
|
||||
fsregs[FS_OFFLSB] = rv & 0xFF;
|
||||
fsregs[FS_OFFMSB] = (rv >> 8);
|
||||
fsregs[FS_STATUS] = FS_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void fs_tell(volatile uint8_t *fsregs) {
|
||||
int i = fsregs[FS_FILE];
|
||||
|
||||
if((i >= FS_MAXFILE) || (!fs_file[i].valid) || (fs_file[i].handle < 0)) {
|
||||
fsregs[FS_STATUS] = FS_ERR_INVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
int rv = pico_tell(fs_file[i].handle);
|
||||
if(rv < 0) {
|
||||
fsregs[FS_STATUS] = rv;
|
||||
} else {
|
||||
fsregs[FS_OFFLSB] = rv & 0xFF;
|
||||
fsregs[FS_OFFMSB] = (rv >> 8);
|
||||
fsregs[FS_STATUS] = FS_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void prodos_command(volatile uint8_t *fsregs) {
|
||||
}
|
||||
|
||||
void fs_handler(uint8_t slot) {
|
||||
volatile uint8_t *fsregs = apple_memory + 0xC080 + (slot << 4);
|
||||
if(fsregs[FS_EXECUTE] != 0x00) {
|
||||
fsregs[FS_STATUS] = FS_ERR_INVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
fsregs[FS_BUSY] = 0xff;
|
||||
|
||||
switch(fsregs[FS_COMMAND]) {
|
||||
case FS_OPEN:
|
||||
fs_open(fsregs);
|
||||
break;
|
||||
case FS_CLOSE:
|
||||
fs_close(fsregs);
|
||||
break;
|
||||
case FS_READ:
|
||||
fs_read(fsregs);
|
||||
break;
|
||||
case FS_WRITE:
|
||||
fs_write(fsregs);
|
||||
break;
|
||||
case FS_SEEK:
|
||||
fs_seek(fsregs);
|
||||
break;
|
||||
case FS_TELL:
|
||||
fs_tell(fsregs);
|
||||
break;
|
||||
case PRODOS_COMMAND:
|
||||
prodos_command(fsregs);
|
||||
break;
|
||||
}
|
||||
|
||||
fsregs[FS_BUSY] = 0x00;
|
||||
}
|
||||
|
||||
void fsmain() {
|
||||
int i;
|
||||
|
||||
memset((uint8_t*)(apple_memory+0xC000), 0x00, 0x1000);
|
||||
|
||||
for(i = 0; i < FS_MAXFILE; i++) {
|
||||
fs_file[i].handle = -1;
|
||||
fs_file[i].valid = false;
|
||||
}
|
||||
|
||||
// Attempt to open boot disk image
|
||||
fs_file[0].handle = pico_open("boot.dsk", LFS_O_RDONLY);
|
||||
fs_file[0].valid = (fs_file[0].handle >= 0);
|
||||
|
||||
strcpy((uint8_t*)(apple_memory+0xC1E0), "FSREADY.");
|
||||
strcpy((uint8_t*)(apple_memory+0xC2E0), "FSREADY.");
|
||||
strcpy((uint8_t*)(apple_memory+0xC3E0), "FSREADY.");
|
||||
strcpy((uint8_t*)(apple_memory+0xC4E0), "FSREADY.");
|
||||
strcpy((uint8_t*)(apple_memory+0xC5E0), "FSREADY.");
|
||||
strcpy((uint8_t*)(apple_memory+0xC6E0), "FSREADY.");
|
||||
strcpy((uint8_t*)(apple_memory+0xC7E0), "FSREADY.");
|
||||
|
||||
while(v2mode == MODE_FS) {
|
||||
sleep_ms(50);
|
||||
}
|
||||
|
||||
// Close any open handles
|
||||
for(i = 0; i < FS_MAXFILE; i++) {
|
||||
if(fs_file[i].valid) {
|
||||
pico_close(fs_file[i].handle);
|
||||
fs_file[i].handle = -1;
|
||||
fs_file[i].valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
54
v2-analog-rev1/fs/fs.h
Normal file
54
v2-analog-rev1/fs/fs.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#define FS_COMMAND 0x0
|
||||
#define FS_FILE 0x1
|
||||
#define FS_FLAGS 0x1
|
||||
#define FS_SIZELSB 0x2
|
||||
#define FS_SIZEMSB 0x3
|
||||
#define FS_OFFLSB 0x2
|
||||
#define FS_OFFMSB 0x3
|
||||
#define FS_WHENCE 0x4
|
||||
#define FS_BUSY 0xD
|
||||
#define FS_STATUS 0xE
|
||||
#define FS_EXECUTE 0xF
|
||||
|
||||
#define FS_O_RD 1
|
||||
#define FS_O_WR 2
|
||||
#define FS_O_APPEND 4
|
||||
#define FS_O_EXISTING 8
|
||||
#define FS_O_CREATE 16
|
||||
#define FS_O_TRUNC 32
|
||||
|
||||
#define FS_SEEK_SET 0
|
||||
#define FS_SEEK_CUR 1
|
||||
#define FS_SEEK_END 2
|
||||
|
||||
typedef enum {
|
||||
FS_OPEN = 0x10,
|
||||
FS_CLOSE = 0x11,
|
||||
FS_READ = 0x12,
|
||||
FS_WRITE = 0x13,
|
||||
FS_SEEK = 0x14,
|
||||
FS_TELL = 0x15,
|
||||
PRODOS_COMMAND = 0x20,
|
||||
} fscommand_t;
|
||||
|
||||
typedef enum {
|
||||
FS_ERR_OK = 0, // No error
|
||||
FS_ERR_IO = -1, // Error during device operation
|
||||
FS_ERR_CORRUPT = -2, // Corrupted
|
||||
FS_ERR_NOENT = -3, // No directory entry
|
||||
FS_ERR_EXIST = -4, // Entry already exists
|
||||
FS_ERR_NOTDIR = -5, // Entry is not a dir
|
||||
FS_ERR_ISDIR = -5, // Entry is a dir
|
||||
FS_ERR_NOTEMPTY = -7, // Dir is not empty
|
||||
FS_ERR_BADF = -8, // Bad file number
|
||||
FS_ERR_FBIG = -9, // File too large
|
||||
FS_ERR_INVAL = -10, // Invalid parameter
|
||||
FS_ERR_NOSPC = -11, // No space left on device
|
||||
FS_ERR_NOMEM = -12, // No more memory available
|
||||
FS_ERR_NOATTR = -13, // No data/attr available
|
||||
FS_ERR_NAMETOOLONG = -14 // File name too long
|
||||
} fserror_t;
|
||||
|
||||
void fs_handler(uint8_t slot);
|
@ -7,7 +7,7 @@
|
||||
|
||||
|
||||
volatile uint8_t *videx_page = videx_memory;
|
||||
|
||||
uint32_t a2_first_write = 0;
|
||||
|
||||
static inline void __time_critical_func(videx_crtc_addr)(uint32_t value) {
|
||||
}
|
||||
@ -18,23 +18,185 @@ static inline void __time_critical_func(videx_crtc_write)(uint32_t value) {
|
||||
|
||||
|
||||
static inline void __time_critical_func(shadow_memory)(uint32_t address, uint32_t value) {
|
||||
// Shadow the soft-switches by observing all read & write bus cycles
|
||||
if((address & 0xff80) == 0xc000) {
|
||||
switch(address & 0x7f) {
|
||||
case 0x00:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches &= ~SOFTSW_80STORE;
|
||||
}
|
||||
return;
|
||||
case 0x01:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches |= SOFTSW_80STORE;
|
||||
}
|
||||
return;
|
||||
case 0x04:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches &= ~SOFTSW_AUX_WRITE;
|
||||
}
|
||||
return;
|
||||
case 0x05:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches |= SOFTSW_AUX_WRITE;
|
||||
}
|
||||
return;
|
||||
case 0x08:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches &= ~SOFTSW_AUXZP;
|
||||
}
|
||||
return;
|
||||
case 0x09:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches |= SOFTSW_AUXZP;
|
||||
}
|
||||
return;
|
||||
case 0x0c:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches &= ~SOFTSW_80COL;
|
||||
}
|
||||
return;
|
||||
case 0x0d:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches |= SOFTSW_80COL;
|
||||
}
|
||||
return;
|
||||
case 0x0e:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches &= ~SOFTSW_ALTCHAR;
|
||||
}
|
||||
return;
|
||||
case 0x0f:
|
||||
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches |= SOFTSW_ALTCHAR;
|
||||
}
|
||||
return;
|
||||
case 0x21:
|
||||
if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
if(value & 0x80) {
|
||||
soft_switches |= SOFTSW_MONOCHROME;
|
||||
} else {
|
||||
soft_switches &= ~SOFTSW_MONOCHROME;
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 0x22:
|
||||
if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
terminal_tbcolor = value & 0xff;
|
||||
}
|
||||
return;
|
||||
case 0x29:
|
||||
if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches = (soft_switches & ~(SOFTSW_NEWVID_MASK << SOFTSW_NEWVID_SHIFT)) | ((value & SOFTSW_NEWVID_MASK) << SOFTSW_NEWVID_SHIFT);
|
||||
}
|
||||
return;
|
||||
case 0x34:
|
||||
if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
terminal_border = value & 0x0f;
|
||||
}
|
||||
return;
|
||||
case 0x35:
|
||||
if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches = (soft_switches & ~(SOFTSW_SHADOW_MASK << SOFTSW_SHADOW_SHIFT)) | ((value & SOFTSW_SHADOW_MASK) << SOFTSW_SHADOW_SHIFT);
|
||||
}
|
||||
return;
|
||||
case 0x50:
|
||||
soft_switches &= ~SOFTSW_TEXT_MODE;
|
||||
return;
|
||||
case 0x51:
|
||||
soft_switches |= SOFTSW_TEXT_MODE;
|
||||
return;
|
||||
case 0x52:
|
||||
soft_switches &= ~SOFTSW_MIX_MODE;
|
||||
return;
|
||||
case 0x53:
|
||||
soft_switches |= SOFTSW_MIX_MODE;
|
||||
return;
|
||||
case 0x54:
|
||||
soft_switches &= ~SOFTSW_PAGE_2;
|
||||
return;
|
||||
case 0x55:
|
||||
soft_switches |= SOFTSW_PAGE_2;
|
||||
return;
|
||||
case 0x56:
|
||||
soft_switches &= ~SOFTSW_HIRES_MODE;
|
||||
return;
|
||||
case 0x57:
|
||||
soft_switches |= SOFTSW_HIRES_MODE;
|
||||
return;
|
||||
case 0x5e:
|
||||
if(soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) {
|
||||
soft_switches |= SOFTSW_DGR;
|
||||
}
|
||||
return;
|
||||
case 0x5f:
|
||||
if(soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) {
|
||||
soft_switches &= ~SOFTSW_DGR;
|
||||
}
|
||||
return;
|
||||
case 0x7e:
|
||||
if((soft_switches & SOFTSW_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches |= SOFTSW_IOUDIS;
|
||||
}
|
||||
return;
|
||||
case 0x7f:
|
||||
if((soft_switches & SOFTSW_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
|
||||
soft_switches &= ~SOFTSW_IOUDIS;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Shadow parts of the Apple's memory by observing the bus write cycles
|
||||
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) {
|
||||
// Mirror Video Memory from MAIN & AUX banks
|
||||
if(terminal_switches & TERMINAL_AUX_WRITE) {
|
||||
if((address >= 0x400) && (address < 0xC00)) {
|
||||
private_memory[address] = value & 0xff;
|
||||
} else if((address >= 0x2000) && (address < 0x6000)) {
|
||||
private_memory[address] = value & 0xff;
|
||||
}
|
||||
if((machine == COMPAT_AUTO) && (a2_first_write == 0)) {
|
||||
a2_first_write = (address << 16) | (value & 0x3FF);
|
||||
if(a2_first_write == 0xC0330100) { // Apple IIgs ROM03 Clock Access
|
||||
machine = APPLE_IIGS;
|
||||
soft_switches &= ~SOFTSW_IIE_REGS;
|
||||
soft_switches |= SOFTSW_IIGS_REGS;
|
||||
} else if(a2_first_write == 0x01F901FB) { // Apple II Plus
|
||||
machine = APPLE_II;
|
||||
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
|
||||
} else if(a2_first_write == 0x01F5018B) { // Apple IIe Platinum
|
||||
machine = APPLE_IIE;
|
||||
soft_switches |= SOFTSW_IIE_REGS;
|
||||
soft_switches &= ~SOFTSW_IIGS_REGS;
|
||||
} else {
|
||||
if((address >= 0x400) && (address < 0xC00)) {
|
||||
apple_memory[address] = value & 0xff;
|
||||
} else if((address >= 0x2000) && (address < 0x6000)) {
|
||||
apple_memory[address] = value & 0xff;
|
||||
a2_first_write = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Mirror Video Memory from MAIN & AUX banks
|
||||
if(soft_switches & SOFTSW_LINEARIZE) {
|
||||
if((address >= 0x2000) && (address < 0xC000)) {
|
||||
private_memory[address] = value & 0xff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(soft_switches & SOFTSW_80STORE) {
|
||||
if(soft_switches & SOFTSW_PAGE_2) {
|
||||
if((address >= 0x400) && (address < 0x800)) {
|
||||
private_memory[address] = value & 0xff;
|
||||
return;
|
||||
} else if((soft_switches & SOFTSW_HIRES_MODE) && (address >= 0x2000) && (address < 0x4000)) {
|
||||
private_memory[address] = value & 0xff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if(soft_switches & SOFTSW_AUX_WRITE) {
|
||||
if((address >= 0x200) && (address < 0xC000)) {
|
||||
private_memory[address] = value & 0xff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if((address >= 0x200) && (address < 0xC000)) {
|
||||
apple_memory[address] = value & 0xff;
|
||||
return;
|
||||
}
|
||||
|
||||
// Videx 80 Column Card
|
||||
if(CARD_SELECT) {
|
||||
if((address >= 0xCC00) && (address < 0xD000)) {
|
||||
@ -62,63 +224,9 @@ static inline void __time_critical_func(shadow_memory)(uint32_t address, uint32_
|
||||
}
|
||||
|
||||
// Any access to Videx I/O sets the VRAM page visible in 0xCC00-0xD000
|
||||
if(CARD_DEVSEL) {
|
||||
if(CARD_SELECT && CARD_DEVSEL) {
|
||||
videx_page = videx_memory + ((address & 0x0C) << 9);
|
||||
}
|
||||
|
||||
// Shadow the soft-switches by observing all read & write bus cycles
|
||||
if((address & 0xff80) == 0xc000) {
|
||||
switch(address & 0x7f) {
|
||||
case 0x0c:
|
||||
if(terminal_switches & TERMINAL_IIE_REGS)
|
||||
terminal_switches &= ~((uint32_t)TERMINAL_80COL);
|
||||
break;
|
||||
case 0x0d:
|
||||
if(terminal_switches & TERMINAL_IIE_REGS)
|
||||
terminal_switches |= TERMINAL_80COL;
|
||||
break;
|
||||
case 0x22:
|
||||
if((terminal_switches & TERMINAL_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0))
|
||||
terminal_tbcolor = value & 0xff;
|
||||
break;
|
||||
case 0x34:
|
||||
if((terminal_switches & TERMINAL_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0))
|
||||
terminal_border = value & 0x0f;
|
||||
break;
|
||||
case 0x50:
|
||||
soft_switches &= ~((uint32_t)SOFTSW_TEXT_MODE);
|
||||
break;
|
||||
case 0x51:
|
||||
soft_switches |= SOFTSW_TEXT_MODE;
|
||||
break;
|
||||
case 0x52:
|
||||
soft_switches &= ~((uint32_t)SOFTSW_MIX_MODE);
|
||||
break;
|
||||
case 0x53:
|
||||
soft_switches |= SOFTSW_MIX_MODE;
|
||||
break;
|
||||
case 0x54:
|
||||
soft_switches &= ~((uint32_t)SOFTSW_PAGE_2);
|
||||
break;
|
||||
case 0x55:
|
||||
soft_switches |= SOFTSW_PAGE_2;
|
||||
break;
|
||||
case 0x56:
|
||||
soft_switches &= ~((uint32_t)SOFTSW_HIRES_MODE);
|
||||
break;
|
||||
case 0x57:
|
||||
soft_switches |= SOFTSW_HIRES_MODE;
|
||||
break;
|
||||
case 0x5e:
|
||||
if(terminal_switches & TERMINAL_IIE_REGS)
|
||||
terminal_switches |= TERMINAL_DGR;
|
||||
break;
|
||||
case 0x5f:
|
||||
if(terminal_switches & TERMINAL_IIE_REGS)
|
||||
terminal_switches &= ~((uint32_t)TERMINAL_DGR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,5 +2,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
extern const uint8_t default_character_rom[256*8];
|
||||
extern const uint8_t default_character_rom[2048];
|
||||
extern const uint8_t appleiie_character_rom[2048];
|
||||
extern const uint8_t appleiigs_character_rom[2048];
|
||||
|
@ -6,18 +6,61 @@
|
||||
#include "vga/render.h"
|
||||
#include "vga/character_rom.h"
|
||||
#include "vga/vgaout.h"
|
||||
#include "pico_hal.h"
|
||||
|
||||
uint16_t text_fore;
|
||||
uint16_t text_back;
|
||||
uint16_t text_border;
|
||||
|
||||
compat_t machinefont = APPLE_II;
|
||||
bool userfont = false;
|
||||
|
||||
// Initialize the character generator ROM
|
||||
void switch_font() {
|
||||
switch(machine) {
|
||||
default:
|
||||
case APPLE_II:
|
||||
memcpy(character_rom, default_character_rom, 2048);
|
||||
break;
|
||||
case APPLE_IIE:
|
||||
memcpy(character_rom, appleiie_character_rom, 2048);
|
||||
break;
|
||||
case APPLE_IIGS:
|
||||
memcpy(character_rom, appleiigs_character_rom, 2048);
|
||||
break;
|
||||
}
|
||||
machinefont = machine;
|
||||
}
|
||||
|
||||
void load_font() {
|
||||
int file = pico_open("font", LFS_O_RDONLY);
|
||||
int br = 0;
|
||||
|
||||
userfont = false;
|
||||
|
||||
if(file < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
br = pico_read(file, character_rom, 2048);
|
||||
if(br == 2048) {
|
||||
userfont = true;
|
||||
}
|
||||
|
||||
pico_close(file);
|
||||
return;
|
||||
}
|
||||
|
||||
void render_init() {
|
||||
int i;
|
||||
// Initialize the character generator ROM
|
||||
memcpy(character_rom, default_character_rom, sizeof(character_rom));
|
||||
soft_switches = 0;
|
||||
terminal_switches = TERMINAL_TEST | TERMINAL_IIE_REGS | TERMINAL_IIGS_REGS;
|
||||
terminal_tbcolor = 0x0f;
|
||||
|
||||
load_font();
|
||||
if(!userfont)
|
||||
switch_font();
|
||||
|
||||
if((soft_switches & SOFTSW_MODE_MASK) == 0)
|
||||
soft_switches |= SOFTSW_TEST;
|
||||
terminal_tbcolor = 0xf0;
|
||||
terminal_border = 0x00;
|
||||
|
||||
render_test_init();
|
||||
@ -26,58 +69,62 @@ void render_init() {
|
||||
uint32_t testdone=0;
|
||||
void __noinline __time_critical_func(render_loop)() {
|
||||
while(v2mode == MODE_VGACARD) {
|
||||
if(!userfont && (machinefont != machine)) {
|
||||
switch_font();
|
||||
}
|
||||
|
||||
update_text_flasher();
|
||||
|
||||
text_fore = lores_palette[TERMINAL_FORE];
|
||||
text_back = lores_palette[TERMINAL_BACK];
|
||||
text_border = lores_palette[TERMINAL_BORDER];
|
||||
|
||||
if(terminal_switches & TERMINAL_TEST) {
|
||||
if(soft_switches & SOFTSW_TEST) {
|
||||
render_testpattern();
|
||||
|
||||
// Automatically dismiss the test pattern when the Apple II initializes
|
||||
// soft switches during startup.
|
||||
if(((soft_switches & SOFTSW_MODE_MASK) != 0) && (testdone == 0)) {
|
||||
terminal_switches &= (~(uint32_t)TERMINAL_TEST);
|
||||
soft_switches &= ~SOFTSW_TEST;
|
||||
testdone = 1;
|
||||
render_about_init();
|
||||
}
|
||||
} else if(soft_switches & SOFTSW_VIDEX) {
|
||||
render_videx();
|
||||
} else if(soft_switches & SOFTSW_SHR) {
|
||||
render_shr();
|
||||
} else {
|
||||
switch(soft_switches & SOFTSW_MODE_MASK) {
|
||||
case 0:
|
||||
if(terminal_switches & TERMINAL_DGR) {
|
||||
if(soft_switches & SOFTSW_DGR) {
|
||||
render_dgr();
|
||||
} else {
|
||||
render_lores();
|
||||
}
|
||||
break;
|
||||
case SOFTSW_MIX_MODE:
|
||||
if(terminal_switches & (TERMINAL_80COL | TERMINAL_DGR) == (TERMINAL_80COL | TERMINAL_DGR)) {
|
||||
if((soft_switches & (SOFTSW_80COL | SOFTSW_DGR)) == (SOFTSW_80COL | SOFTSW_DGR)) {
|
||||
render_mixed_dgr();
|
||||
} else {
|
||||
render_mixed_lores();
|
||||
}
|
||||
break;
|
||||
case SOFTSW_HIRES_MODE:
|
||||
if(terminal_switches & TERMINAL_DGR) {
|
||||
if(soft_switches & SOFTSW_DGR) {
|
||||
render_dhgr();
|
||||
} else {
|
||||
render_hires();
|
||||
}
|
||||
break;
|
||||
case SOFTSW_HIRES_MODE|SOFTSW_MIX_MODE:
|
||||
if(terminal_switches & TERMINAL_DGR) {
|
||||
if((soft_switches & (SOFTSW_80COL | SOFTSW_DGR)) == (SOFTSW_80COL | SOFTSW_DGR)) {
|
||||
render_mixed_dhgr();
|
||||
} else {
|
||||
render_mixed_hires();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(terminal_switches & TERMINAL_80COL) {
|
||||
render_terminal();
|
||||
} else {
|
||||
render_text();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,11 @@ extern void render_about_init();
|
||||
|
||||
extern void update_text_flasher();
|
||||
extern void render_text();
|
||||
extern void render_text_line(unsigned int line);
|
||||
extern void render_text40_line(bool p2, unsigned int line);
|
||||
extern void render_text80_line(bool p2, unsigned int line);
|
||||
|
||||
extern void render_terminal();
|
||||
extern void render_terminal_line(unsigned int line);
|
||||
extern void render_videx();
|
||||
extern void render_videx_line(unsigned int line);
|
||||
|
||||
extern void render_border();
|
||||
|
||||
@ -36,6 +37,8 @@ extern void render_mixed_dhgr();
|
||||
extern void render_dgr();
|
||||
extern void render_mixed_dgr();
|
||||
|
||||
extern void render_shr();
|
||||
|
||||
extern uint_fast32_t text_flasher_mask;
|
||||
|
||||
extern void flash_dowork();
|
||||
|
@ -6,22 +6,20 @@
|
||||
|
||||
extern uint16_t lores_palette[16];
|
||||
|
||||
static void render_dgr_line(uint line);
|
||||
static void render_dgr_line(bool p2, uint line);
|
||||
|
||||
void __time_critical_func(render_dgr)() {
|
||||
vga_prepare_frame();
|
||||
|
||||
// Skip 48 lines to center vertically
|
||||
struct vga_scanline *skip_sl = vga_prepare_scanline();
|
||||
for(int i=0; i < 48; i++) {
|
||||
skip_sl->data[i] = (uint32_t)THEN_WAIT_HSYNC << 16;
|
||||
}
|
||||
skip_sl->length = 48;
|
||||
vga_submit_scanline(skip_sl);
|
||||
render_border();
|
||||
|
||||
bool p2 = !(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2);
|
||||
|
||||
for(uint line=0; line < 24; line++) {
|
||||
render_dgr_line(line);
|
||||
render_dgr_line(p2, line);
|
||||
}
|
||||
|
||||
render_border();
|
||||
}
|
||||
|
||||
|
||||
@ -30,17 +28,19 @@ void __time_critical_func(render_mixed_dgr)() {
|
||||
|
||||
render_border();
|
||||
|
||||
bool p2 = !(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2);
|
||||
|
||||
for(uint line=0; line < 20; line++) {
|
||||
render_dgr_line(line);
|
||||
render_dgr_line(p2, line);
|
||||
}
|
||||
|
||||
if(terminal_switches & TERMINAL_80COL) {
|
||||
if(soft_switches & SOFTSW_80COL) {
|
||||
for(uint line=20; line < 24; line++) {
|
||||
render_terminal_line(line);
|
||||
render_text80_line(p2, line);
|
||||
}
|
||||
} else {
|
||||
for(uint line=20; line < 24; line++) {
|
||||
render_text_line(line);
|
||||
render_text40_line(p2, line);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,28 +48,28 @@ void __time_critical_func(render_mixed_dgr)() {
|
||||
}
|
||||
|
||||
|
||||
static void __time_critical_func(render_dgr_line)(uint line) {
|
||||
static void __time_critical_func(render_dgr_line)(bool p2, uint line) {
|
||||
// Construct two scanlines for the two different colored cells at the same time
|
||||
struct vga_scanline *sl1 = vga_prepare_scanline();
|
||||
struct vga_scanline *sl2 = vga_prepare_scanline();
|
||||
uint sl_pos = 0;
|
||||
uint i;
|
||||
|
||||
const uint8_t *page = (const uint8_t *)text_memory;
|
||||
const uint8_t *line_buf = page + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40);
|
||||
const uint8_t *line_bufa = (const uint8_t *)((p2 ? text_p2 : text_p1) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
|
||||
const uint8_t *line_bufb = (const uint8_t *)((p2 ? text_p4 : text_p3) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
|
||||
|
||||
// Pad 40 pixels on the left to center horizontally
|
||||
while(sl_pos < 40/8) {
|
||||
for(i = 0; i < 40/8; i++) {
|
||||
sl1->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl2->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
}
|
||||
|
||||
for(i=0; i < 40; i++) {
|
||||
uint32_t color1 = lores_palette[line_buf[i | (1 << 10)] & 0xf];
|
||||
uint32_t color2 = lores_palette[(line_buf[i | (1 << 10)] >> 4) & 0xf];
|
||||
uint32_t color3 = lores_palette[line_buf[i] & 0xf];
|
||||
uint32_t color4 = lores_palette[(line_buf[i] >> 4) & 0xf];
|
||||
uint32_t color1 = lores_palette[line_bufb[i] & 0xf];
|
||||
uint32_t color2 = lores_palette[(line_bufb[i] >> 4) & 0xf];
|
||||
uint32_t color3 = lores_palette[line_bufa[i] & 0xf];
|
||||
uint32_t color4 = lores_palette[(line_bufa[i] >> 4) & 0xf];
|
||||
|
||||
// Each double lores pixel is 7 double hires pixels, or 7 VGA pixels wide
|
||||
sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color3|THEN_EXTEND_6) << 16);
|
||||
@ -77,7 +77,8 @@ static void __time_critical_func(render_dgr_line)(uint line) {
|
||||
sl_pos++;
|
||||
}
|
||||
|
||||
for(i=0; i < 40/8; i++) {
|
||||
// Pad 40 pixels on the right to center horizontally
|
||||
for(i = 0; i < 40/8; i++) {
|
||||
sl1->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl2->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "render.h"
|
||||
#include "vgaout.h"
|
||||
|
||||
static void render_dhgr_line(uint line);
|
||||
static void render_dhgr_line(bool p2, uint line);
|
||||
|
||||
#define _RGB333(r, g, b) ( \
|
||||
(((((uint)(r) * 256 / 36) + 128) / 256) << 6) | \
|
||||
@ -16,18 +16,18 @@ static void render_dhgr_line(uint line);
|
||||
uint16_t dhgr_palette[16] = {
|
||||
_RGB333(0x00,0x00,0x00), // black 0000
|
||||
_RGB333(0x00,0x00,0xb4), // d.blue 1000
|
||||
_RGB333(0x00,0x48,0x00), // d.green 0100
|
||||
_RGB333(0x00,0x90,0xfc), // h.blue 1100
|
||||
_RGB333(0x24,0x24,0x00), // brown 0010
|
||||
_RGB333(0x00,0x90,0x00), // d.green 0100
|
||||
_RGB333(0x00,0x6c,0xd8), // h.blue 1100
|
||||
_RGB333(0x6c,0x6c,0x00), // brown 0010
|
||||
_RGB333(0x90,0x90,0x90), // l.gray 1010
|
||||
_RGB333(0x00,0xd8,0x24), // h.green 0110
|
||||
_RGB333(0x90,0xfc,0xb4), // aqua 1110
|
||||
_RGB333(0x6c,0x00,0x6c), // magenta 0001
|
||||
_RGB333(0x90,0xfc,0x90), // aqua 1110
|
||||
_RGB333(0xd8,0x00,0x6c), // magenta 0001
|
||||
_RGB333(0xb4,0x24,0xfc), // h.violet 1001
|
||||
_RGB333(0x48,0x48,0x48), // d.gray 0101
|
||||
_RGB333(0x6c,0x6c,0xfc), // l.blue 1101
|
||||
_RGB333(0xfc,0x48,0x00), // h.orange 0011
|
||||
_RGB333(0xfc,0x6c,0xfc), // pink 1011
|
||||
_RGB333(0x6c,0x6c,0xff), // l.blue 1101
|
||||
_RGB333(0xfc,0x6c,0x24), // h.orange 0011
|
||||
_RGB333(0xff,0xd8,0xff), // pink 1011
|
||||
_RGB333(0xd8,0xd8,0x00), // yellow 0111
|
||||
_RGB333(0xff,0xff,0xff), // white 1111
|
||||
};
|
||||
@ -43,8 +43,10 @@ void __time_critical_func(render_dhgr)() {
|
||||
|
||||
render_border();
|
||||
|
||||
bool p2 = !(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2);
|
||||
|
||||
for(uint line=0; line < 192; line++) {
|
||||
render_dhgr_line(line);
|
||||
render_dhgr_line(p2, line);
|
||||
}
|
||||
|
||||
render_border();
|
||||
@ -56,17 +58,19 @@ void __time_critical_func(render_mixed_dhgr)() {
|
||||
|
||||
render_border();
|
||||
|
||||
bool p2 = !(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2);
|
||||
|
||||
for(uint line=0; line < 160; line++) {
|
||||
render_dhgr_line(line);
|
||||
render_dhgr_line(p2, line);
|
||||
}
|
||||
|
||||
if(terminal_switches & TERMINAL_80COL) {
|
||||
if(soft_switches & SOFTSW_80COL) {
|
||||
for(uint line=20; line < 24; line++) {
|
||||
render_terminal_line(line);
|
||||
render_text80_line(p2, line);
|
||||
}
|
||||
} else {
|
||||
for(uint line=20; line < 24; line++) {
|
||||
render_text_line(line);
|
||||
render_text40_line(p2, line);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,19 +78,18 @@ void __time_critical_func(render_mixed_dhgr)() {
|
||||
}
|
||||
|
||||
|
||||
static void __time_critical_func(render_dhgr_line)(uint line) {
|
||||
static void __time_critical_func(render_dhgr_line)(bool p2, uint line) {
|
||||
struct vga_scanline *sl = vga_prepare_scanline();
|
||||
uint sl_pos = 0;
|
||||
uint i;
|
||||
|
||||
const uint8_t *page = (const uint8_t *)hires_memory;
|
||||
const uint8_t *line_mem = page + dhgr_line_to_mem_offset(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
|
||||
while(sl_pos < 40/8) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
}
|
||||
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
|
||||
|
||||
// DHGR is weird. Nuff said.
|
||||
uint32_t dots = 0;
|
||||
@ -96,23 +99,24 @@ static void __time_critical_func(render_dhgr_line)(uint line) {
|
||||
i = 0;
|
||||
while(i < 40) {
|
||||
// Load in the next 28 subpixels
|
||||
dots = (line_mem[i | 8192] & 0x7f) << 0;
|
||||
dots |= (line_mem[i] & 0x7f) << 7;
|
||||
dots = (line_memb[i] & 0x7f) << 0;
|
||||
dots |= (line_mema[i] & 0x7f) << 7;
|
||||
i++;
|
||||
dots |= (line_mem[i | 8192] & 0x7f) << 14;
|
||||
dots |= (line_mem[i] & 0x7f) << 21;
|
||||
dots |= (line_memb[i] & 0x7f) << 14;
|
||||
dots |= (line_mema[i] & 0x7f) << 21;
|
||||
i++;
|
||||
|
||||
if(soft_switches & SOFTSW_MONOCHROME) {
|
||||
// Consume 6 pixels (24 subpixel bits)
|
||||
#if 0
|
||||
for(j = 0; j < 12; j++) {
|
||||
pixeldata = ((dots & 1) ? (text_fore) : (text_back));
|
||||
pixeldata = ((dots & 1) ? (0x1ff) : (0x000));
|
||||
dots >>= 1;
|
||||
pixeldata |= (((dots & 1) ? (text_fore) : (text_back))) << 16;
|
||||
pixeldata |= (((dots & 1) ? (0x1ff) : (0x000))) << 16;
|
||||
dots >>= 1;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
#else
|
||||
} else {
|
||||
// Consume 6 pixels (24 subpixel bits)
|
||||
for(j = 0; j < 3; j++) {
|
||||
pixeldata = (dhgr_palette[dots & 0xf] | THEN_EXTEND_3);
|
||||
dots >>= 4;
|
||||
@ -120,27 +124,28 @@ static void __time_critical_func(render_dhgr_line)(uint line) {
|
||||
dots >>= 4;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// 4 subpixels roll over to the next block
|
||||
// Load in the next 28 subpixels
|
||||
dots |= (line_mem[i | 8192] & 0x7f) << 4;
|
||||
dots |= (line_mem[i] & 0x7f) << 11;
|
||||
dots |= (line_memb[i] & 0x7f) << 4;
|
||||
dots |= (line_mema[i] & 0x7f) << 11;
|
||||
i++;
|
||||
dots |= (line_mem[i | 8192] & 0x7f) << 18;
|
||||
dots |= (line_mem[i] & 0x7f) << 25;
|
||||
dots |= (line_memb[i] & 0x7f) << 18;
|
||||
dots |= (line_mema[i] & 0x7f) << 25;
|
||||
i++;
|
||||
|
||||
if(soft_switches & SOFTSW_MONOCHROME) {
|
||||
// Consume 8 pixels (32 subpixel bits)
|
||||
#if 0
|
||||
for(j = 0; j < 16; j++) {
|
||||
pixeldata = ((dots & 1) ? (text_fore) : (text_back));
|
||||
pixeldata = ((dots & 1) ? (0x1ff) : (0x000));
|
||||
dots >>= 1;
|
||||
pixeldata |= (((dots & 1) ? (text_fore) : (text_back))) << 16;
|
||||
pixeldata |= (((dots & 1) ? (0x1ff) : (0x000))) << 16;
|
||||
dots >>= 1;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
#else
|
||||
} else {
|
||||
// Consume 8 pixels (32 subpixel bits)
|
||||
for(j = 0; j < 4; j++) {
|
||||
pixeldata = (dhgr_palette[dots & 0xf] | THEN_EXTEND_3);
|
||||
dots >>= 4;
|
||||
@ -148,16 +153,16 @@ static void __time_critical_func(render_dhgr_line)(uint line) {
|
||||
dots >>= 4;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i < 40/8; i++) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
}
|
||||
// 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
|
||||
|
||||
sl->length = sl_pos;
|
||||
sl->repeat_count = 1;
|
||||
vga_submit_scanline(sl);
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,7 @@
|
||||
#include "vgaout.h"
|
||||
|
||||
|
||||
static void render_hires_line(uint line);
|
||||
|
||||
static void render_hires_line(bool p2, uint line);
|
||||
|
||||
static uint hires_line_to_mem_offset(uint line) {
|
||||
return ((line & 0x07) << 10) | ((line & 0x38) << 4) | (((line & 0xc0) >> 6) * 40);
|
||||
@ -19,8 +18,10 @@ void __time_critical_func(render_hires)() {
|
||||
|
||||
render_border();
|
||||
|
||||
bool p2 = !(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2);
|
||||
|
||||
for(uint line=0; line < 192; line++) {
|
||||
render_hires_line(line);
|
||||
render_hires_line(p2, line);
|
||||
}
|
||||
|
||||
render_border();
|
||||
@ -32,17 +33,19 @@ void __time_critical_func(render_mixed_hires)() {
|
||||
|
||||
render_border();
|
||||
|
||||
bool p2 = !(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2);
|
||||
|
||||
for(uint line=0; line < 160; line++) {
|
||||
render_hires_line(line);
|
||||
render_hires_line(p2, line);
|
||||
}
|
||||
|
||||
if(terminal_switches & TERMINAL_80COL) {
|
||||
if(soft_switches & SOFTSW_80COL) {
|
||||
for(uint line=20; line < 24; line++) {
|
||||
render_terminal_line(line);
|
||||
render_text80_line(p2, line);
|
||||
}
|
||||
} else {
|
||||
for(uint line=20; line < 24; line++) {
|
||||
render_text_line(line);
|
||||
render_text40_line(p2, line);
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,18 +53,16 @@ void __time_critical_func(render_mixed_hires)() {
|
||||
}
|
||||
|
||||
|
||||
static void __time_critical_func(render_hires_line)(uint line) {
|
||||
static void __time_critical_func(render_hires_line)(bool p2, uint line) {
|
||||
struct vga_scanline *sl = vga_prepare_scanline();
|
||||
uint sl_pos = 0;
|
||||
|
||||
const uint8_t *page = (const uint8_t *)((soft_switches & SOFTSW_PAGE_2) ? hgr_p2 : hgr_p1);
|
||||
const uint8_t *line_mem = page + hires_line_to_mem_offset(line);
|
||||
const uint8_t *line_mem = (const uint8_t *)((p2 ? hgr_p2 : hgr_p1) + hires_line_to_mem_offset(line));
|
||||
|
||||
// Pad 40 pixels on the left to center horizontally
|
||||
while(sl_pos < 40/8) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
}
|
||||
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
|
||||
|
||||
// Each hires byte contains 7 pixels which may be shifted right 1/2 a pixel. That is
|
||||
// represented here by 14 'dots' to precisely describe the half-pixel positioning.
|
||||
@ -83,7 +84,7 @@ static void __time_critical_func(render_hires_line)(uint line) {
|
||||
// pixel
|
||||
uint32_t dots = 0;
|
||||
uint oddness = 0;
|
||||
uint i;
|
||||
uint i, j;
|
||||
|
||||
// Load in the first 14 dots
|
||||
dots |= (uint32_t)hires_dot_patterns[line_mem[0]] << 15;
|
||||
@ -97,6 +98,18 @@ static void __time_critical_func(render_hires_line)(uint line) {
|
||||
}
|
||||
dots |= (uint32_t)hires_dot_patterns[b] << 1;
|
||||
|
||||
if(soft_switches & SOFTSW_MONOCHROME) {
|
||||
// Consume 14 dots
|
||||
for(j = 0; j < 14; j++) {
|
||||
uint32_t pixeldata = (dots & 0x2000) ? (0x1ff|THEN_EXTEND_1) : (0x000|THEN_EXTEND_1);
|
||||
pixeldata |= (dots & 0x1000) ?
|
||||
((uint32_t)0x1ff|THEN_EXTEND_1) << 16 :
|
||||
((uint32_t)0x000|THEN_EXTEND_1) << 16;
|
||||
dots <<= 2;
|
||||
sl->data[sl_pos] = pixeldata;
|
||||
sl_pos++;
|
||||
}
|
||||
} else {
|
||||
// Consume 14 dots
|
||||
for(uint j=0; j < 7; j++) {
|
||||
uint dot_pattern = oddness | ((dots >> 24) & 0xff);
|
||||
@ -106,12 +119,13 @@ static void __time_critical_func(render_hires_line)(uint line) {
|
||||
oddness ^= 0x100;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i < 40/8; i++) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
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);
|
||||
|
@ -31,7 +31,7 @@ uint16_t lores_palette[16] = {
|
||||
#undef _RGB333
|
||||
|
||||
|
||||
static void render_lores_line(uint line);
|
||||
static void render_lores_line(bool p2, uint line);
|
||||
|
||||
|
||||
void __time_critical_func(render_lores)() {
|
||||
@ -39,8 +39,10 @@ void __time_critical_func(render_lores)() {
|
||||
|
||||
render_border();
|
||||
|
||||
bool p2 = !(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2);
|
||||
|
||||
for(uint line=0; line < 24; line++) {
|
||||
render_lores_line(line);
|
||||
render_lores_line(p2, line);
|
||||
}
|
||||
|
||||
render_border();
|
||||
@ -52,17 +54,19 @@ void __time_critical_func(render_mixed_lores)() {
|
||||
|
||||
render_border();
|
||||
|
||||
bool p2 = !(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2);
|
||||
|
||||
for(uint line=0; line < 20; line++) {
|
||||
render_lores_line(line);
|
||||
render_lores_line(p2, line);
|
||||
}
|
||||
|
||||
if(terminal_switches & TERMINAL_80COL) {
|
||||
if(soft_switches & SOFTSW_80COL) {
|
||||
for(uint line=20; line < 24; line++) {
|
||||
render_terminal_line(line);
|
||||
render_text80_line(p2, line);
|
||||
}
|
||||
} else {
|
||||
for(uint line=20; line < 24; line++) {
|
||||
render_text_line(line);
|
||||
render_text40_line(p2, line);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,18 +74,17 @@ void __time_critical_func(render_mixed_lores)() {
|
||||
}
|
||||
|
||||
|
||||
static void __time_critical_func(render_lores_line)(uint line) {
|
||||
static void __time_critical_func(render_lores_line)(bool p2, uint line) {
|
||||
// Construct two scanlines for the two different colored cells at the same time
|
||||
struct vga_scanline *sl1 = vga_prepare_scanline();
|
||||
struct vga_scanline *sl2 = vga_prepare_scanline();
|
||||
uint sl_pos = 0;
|
||||
uint i;
|
||||
|
||||
const uint8_t *page = (const uint8_t *)((soft_switches & SOFTSW_PAGE_2) ? text_p2 : text_p1);
|
||||
const uint8_t *line_buf = page + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40);
|
||||
const uint8_t *line_buf = (const uint8_t *)((p2 ? text_p2 : text_p1) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
|
||||
|
||||
// Pad 40 pixels on the left to center horizontally
|
||||
while(sl_pos < 40/8) {
|
||||
for(i = 0; i < 40/8; i++) {
|
||||
sl1->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl2->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
@ -94,8 +97,12 @@ static void __time_critical_func(render_lores_line)(uint line) {
|
||||
uint32_t color4 = lores_palette[(line_buf[i+1] >> 4) & 0xf];
|
||||
|
||||
// Each lores pixel is 7 hires pixels, or 14 VGA pixels wide
|
||||
sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color3|THEN_EXTEND_6) << 16);
|
||||
sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color4|THEN_EXTEND_6) << 16);
|
||||
sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color1|THEN_EXTEND_6) << 16);
|
||||
sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color2|THEN_EXTEND_6) << 16);
|
||||
sl_pos++;
|
||||
|
||||
sl1->data[sl_pos] = (color3|THEN_EXTEND_6) | ((color3|THEN_EXTEND_6) << 16);
|
||||
sl2->data[sl_pos] = (color4|THEN_EXTEND_6) | ((color4|THEN_EXTEND_6) << 16);
|
||||
sl_pos++;
|
||||
}
|
||||
|
||||
|
129
v2-analog-rev1/vga/render_shr.c
Normal file
129
v2-analog-rev1/vga/render_shr.c
Normal file
@ -0,0 +1,129 @@
|
||||
#include <pico/stdlib.h>
|
||||
#include "hires_color_patterns.h"
|
||||
#include "hires_dot_patterns.h"
|
||||
#include "vgabuf.h"
|
||||
#include "render.h"
|
||||
#include "vgaout.h"
|
||||
|
||||
extern uint16_t dhgr_palette[16];
|
||||
|
||||
static void render_shr_line(uint16_t line);
|
||||
|
||||
static uint16_t __time_critical_func(rgb444_to_rgb333)(uint16_t a) {
|
||||
return ((a & 0xe00) >> 3) | ((a & 0xe0) >> 2) | ((a & 0xe) >> 1);
|
||||
}
|
||||
|
||||
// Skip 40 lines to center vertically
|
||||
void __time_critical_func(render_shr_border)() {
|
||||
struct vga_scanline *sl = vga_prepare_scanline();
|
||||
uint sl_pos = 0;
|
||||
|
||||
while(sl_pos < VGA_WIDTH/16) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
}
|
||||
|
||||
sl->length = sl_pos;
|
||||
sl->repeat_count = 39;
|
||||
vga_submit_scanline(sl);
|
||||
}
|
||||
|
||||
void __time_critical_func(render_shr)() {
|
||||
vga_prepare_frame();
|
||||
|
||||
render_shr_border();
|
||||
|
||||
for(uint line=0; line < 200; line++) {
|
||||
render_shr_line(line);
|
||||
}
|
||||
|
||||
render_shr_border();
|
||||
}
|
||||
|
||||
static void __time_critical_func(render_shr_line)(uint16_t line) {
|
||||
struct vga_scanline *sl = vga_prepare_scanline();
|
||||
uint sl_pos = 0;
|
||||
uint i;
|
||||
|
||||
uint8_t control = private_memory[0x9D00 + line];
|
||||
uint32_t line_palette_offset = (control & 0xF) << 5;
|
||||
|
||||
volatile uint16_t *shr_palette = (volatile uint16_t*)(private_memory + 0x9E00 + line_palette_offset);
|
||||
volatile uint8_t *line_mem = (volatile uint8_t *)(private_memory + 0x2000 + (line * 160));
|
||||
|
||||
// SHR is weird. Nuff said.
|
||||
uint32_t dots = 0;
|
||||
uint32_t pixeldata;
|
||||
uint16_t color_a = 0, color_b = 0;
|
||||
int j;
|
||||
|
||||
i = 0;
|
||||
#if 1
|
||||
if(control & 0x80) { // 640 Pixels
|
||||
while(i < 160) {
|
||||
// Load in the next 4 subpixels
|
||||
dots = line_mem[i++];
|
||||
|
||||
pixeldata = (dhgr_palette[(dots >> 6) & 0x3]);
|
||||
pixeldata |= (dhgr_palette[(dots >> 4) & 0x3]) << 16;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
|
||||
pixeldata = (dhgr_palette[(dots >> 2) & 0x3]);
|
||||
pixeldata |= (dhgr_palette[(dots >> 0) & 0x3]) << 16;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
#else
|
||||
if(control & 0x80) { // 640 Pixels
|
||||
while(i < 160) {
|
||||
// Load in the next 2 pixels
|
||||
dots = (line_mem[i++] & 0xff);
|
||||
|
||||
color_a = ((dots >> 4) & 0xf);
|
||||
color_b = ((dots >> 0) & 0xf);
|
||||
|
||||
// Consume 2 pixels
|
||||
pixeldata = rgb444_to_rgb333(shr_palette[color_a]) | THEN_EXTEND_1;
|
||||
pixeldata |= (rgb444_to_rgb333(shr_palette[color_b]) | THEN_EXTEND_1) << 16;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
#endif
|
||||
} else if(control & 0x40) { // 320 Pixels w/ color fill
|
||||
while(i < 160) {
|
||||
// Load in the next 4 subpixels
|
||||
dots = (line_mem[i++] & 0xff);
|
||||
|
||||
// Consume 2 pixels
|
||||
if(dots & 0xf0) {
|
||||
color_a = ((dots >> 4) & 0xf);
|
||||
} else {
|
||||
color_a = color_b;
|
||||
}
|
||||
if(dots & 0x0f) {
|
||||
color_b = ((dots >> 0) & 0xf);
|
||||
} else {
|
||||
color_b = color_a;
|
||||
}
|
||||
|
||||
pixeldata = rgb444_to_rgb333(shr_palette[color_a]) | THEN_EXTEND_1;
|
||||
pixeldata |= (rgb444_to_rgb333(shr_palette[color_b]) | THEN_EXTEND_1) << 16;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
} else { // 320 Pixels
|
||||
while(i < 160) {
|
||||
// Load in the next 2 pixels
|
||||
dots = (line_mem[i++] & 0xff);
|
||||
|
||||
color_a = ((dots >> 4) & 0xf);
|
||||
color_b = ((dots >> 0) & 0xf);
|
||||
|
||||
// Consume 2 pixels
|
||||
pixeldata = rgb444_to_rgb333(shr_palette[color_a]) | THEN_EXTEND_1;
|
||||
pixeldata |= (rgb444_to_rgb333(shr_palette[color_b]) | THEN_EXTEND_1) << 16;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
}
|
||||
|
||||
sl->length = sl_pos;
|
||||
sl->repeat_count = 1;
|
||||
vga_submit_scanline(sl);
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
#include <string.h>
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/unique_id.h>
|
||||
#include <hardware/timer.h>
|
||||
#include "vga/vgabuf.h"
|
||||
#include "vga/render.h"
|
||||
#include "vga/vgaout.h"
|
||||
#include "vga/logo.h"
|
||||
|
||||
#ifdef RASPBERRYPI_PICO_W
|
||||
#include <pico/unique_id.h>
|
||||
#endif
|
||||
|
||||
#define _PIXPAIR(p1, p2) ((uint32_t)(p1) | (((uint32_t)p2) << 16))
|
||||
|
||||
char error_message[16*24+1];
|
||||
@ -14,7 +17,7 @@ char error_message[16*24+1];
|
||||
void render_test_init() {
|
||||
memset(error_message, ' ', 16*24);
|
||||
memcpy(error_message + 0, "HW: ANALOG-REV-1", 16);
|
||||
memcpy(error_message + 16, "FW: 23-01-06-000", 16);
|
||||
memcpy(error_message + 16, "FW: 23-01-16-119", 16);
|
||||
|
||||
memcpy(error_message + 64, " COPYRIGHT (C) ", 16);
|
||||
memcpy(error_message + 80, " DAVID KUDER ", 16);
|
||||
@ -31,10 +34,14 @@ void render_test_init() {
|
||||
memcpy(error_message + 288, "CHECK FOR PROPER", 16);
|
||||
memcpy(error_message + 304, " CARD INSERTION ", 16);
|
||||
|
||||
#ifdef RASPBERRYPI_PICO_W
|
||||
memcpy(error_message + 352, " SERIAL NUMBER: ", 16);
|
||||
|
||||
// Get Pico's Flash Serial Number (Board ID) and terminating null.
|
||||
pico_get_unique_board_id_string(error_message + 368, 17);
|
||||
#else
|
||||
memcpy(error_message + 368, " V2-ANALOG-LC ", 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Clear the error message, in case the user sets 0x20 in terminal switches
|
||||
@ -100,8 +107,8 @@ void __noinline __time_critical_func(render_testpattern)() {
|
||||
uint32_t bits_b = char_text_bits(error_message[(w & 0x1f0) | (i+1)], (w/2) & 0x7);
|
||||
uint32_t bits = (bits_a << 7) | bits_b;
|
||||
for(uint j=0; j < 7; j++) {
|
||||
uint32_t pixeldata = (bits & 0x2000) ? (0x1ff|THEN_EXTEND_1) : (0 | THEN_EXTEND_1);
|
||||
pixeldata |= (bits & 0x1000) ? ((0x1ff|THEN_EXTEND_1) << 16) : ((0 | THEN_EXTEND_1) << 16);
|
||||
uint32_t pixeldata = (bits & 0x2000) ? (0|THEN_EXTEND_1) : (0x1ff | THEN_EXTEND_1);
|
||||
pixeldata |= (bits & 0x1000) ? ((0|THEN_EXTEND_1) << 16) : ((0x1ff | THEN_EXTEND_1) << 16);
|
||||
bits <<= 2;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
@ -162,8 +169,8 @@ void __noinline __time_critical_func(render_testpattern)() {
|
||||
uint32_t bits_b = char_text_bits(error_message[(w & 0x1f0) | (i+1)], (w/2) & 0x7);
|
||||
uint32_t bits = (bits_a << 7) | bits_b;
|
||||
for(uint j=0; j < 7; j++) {
|
||||
uint32_t pixeldata = (bits & 0x2000) ? (0x1ff|THEN_EXTEND_1) : (0 | THEN_EXTEND_1);
|
||||
pixeldata |= (bits & 0x1000) ? ((0x1ff|THEN_EXTEND_1) << 16) : ((0 | THEN_EXTEND_1) << 16);
|
||||
uint32_t pixeldata = (bits & 0x2000) ? (0|THEN_EXTEND_1) : (0x1ff | THEN_EXTEND_1);
|
||||
pixeldata |= (bits & 0x1000) ? ((0|THEN_EXTEND_1) << 16) : ((0x1ff | THEN_EXTEND_1) << 16);
|
||||
bits <<= 2;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
@ -203,8 +210,8 @@ void __noinline __time_critical_func(render_testpattern)() {
|
||||
uint32_t bits_b = char_text_bits(error_message[(w & 0x1f0) | (i+1)], (w/2) & 0x7);
|
||||
uint32_t bits = (bits_a << 7) | bits_b;
|
||||
for(uint j=0; j < 7; j++) {
|
||||
uint32_t pixeldata = (bits & 0x2000) ? (0x1ff|THEN_EXTEND_1) : (0 | THEN_EXTEND_1);
|
||||
pixeldata |= (bits & 0x1000) ? ((0x1ff|THEN_EXTEND_1) << 16) : ((0 | THEN_EXTEND_1) << 16);
|
||||
uint32_t pixeldata = (bits & 0x2000) ? (0|THEN_EXTEND_1) : (0x1ff | THEN_EXTEND_1);
|
||||
pixeldata |= (bits & 0x1000) ? ((0|THEN_EXTEND_1) << 16) : ((0x1ff | THEN_EXTEND_1) << 16);
|
||||
bits <<= 2;
|
||||
sl->data[sl_pos++] = pixeldata;
|
||||
}
|
||||
|
@ -11,26 +11,27 @@ static uint64_t next_flash_tick = 0;
|
||||
void update_text_flasher() {
|
||||
uint64_t now = time_us_64();
|
||||
if(now > next_flash_tick) {
|
||||
text_flasher_mask ^= 0xff;
|
||||
text_flasher_mask ^= 0x7f;
|
||||
next_flash_tick = now + 250000u;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline uint_fast8_t __time_critical_func(char_text_bits)(uint_fast8_t ch, uint_fast8_t glyph_line) {
|
||||
uint_fast8_t bits = character_rom[((uint_fast16_t)ch << 3) | glyph_line];
|
||||
if(ch & 0x80) {
|
||||
uint_fast8_t bits = character_rom[((uint_fast16_t)ch << 3) | glyph_line] & 0x7f;
|
||||
|
||||
if((soft_switches & SOFTSW_ALTCHAR) || (ch & 0x80)) {
|
||||
// normal character
|
||||
return bits & 0x7f;
|
||||
return bits;
|
||||
}
|
||||
|
||||
if((bits & 0x80) == 0) {
|
||||
// inverse character
|
||||
return bits ^ 0x7f;
|
||||
} else {
|
||||
if(ch & 0x40) {
|
||||
// flashing character
|
||||
return (bits ^ text_flasher_mask) & 0x7f;
|
||||
return (bits ^ text_flasher_mask);
|
||||
}
|
||||
|
||||
// inverse character
|
||||
return bits;
|
||||
}
|
||||
|
||||
|
||||
@ -39,8 +40,8 @@ void __time_critical_func(render_border)() {
|
||||
struct vga_scanline *sl = vga_prepare_scanline();
|
||||
uint sl_pos = 0;
|
||||
|
||||
while(sl_pos < VGA_WIDTH/8) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
while(sl_pos < VGA_WIDTH/16) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
}
|
||||
|
||||
@ -54,27 +55,33 @@ void __time_critical_func(render_text)() {
|
||||
|
||||
render_border();
|
||||
|
||||
for(int line=0; line < 24; line++) {
|
||||
render_text_line(line);
|
||||
bool p2 = !(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2);
|
||||
|
||||
if(soft_switches & SOFTSW_80COL) {
|
||||
for(uint line=0; line < 24; line++) {
|
||||
render_text80_line(p2, line);
|
||||
}
|
||||
} else {
|
||||
for(uint line=0; line < 24; line++) {
|
||||
render_text40_line(p2, line);
|
||||
}
|
||||
}
|
||||
|
||||
render_border();
|
||||
}
|
||||
|
||||
|
||||
void __time_critical_func(render_text_line)(unsigned int line) {
|
||||
const uint8_t *page = (const uint8_t *)((soft_switches & SOFTSW_PAGE_2) ? text_p2 : text_p1);
|
||||
const uint8_t *line_buf = page + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40);
|
||||
void __time_critical_func(render_text40_line)(bool p2, unsigned int line) {
|
||||
const uint8_t *page = (const uint8_t *)(p2 ? text_p2 : text_p1);
|
||||
const uint8_t *line_buf = (const uint8_t *)(page + ((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
|
||||
while(sl_pos < 40/8) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
}
|
||||
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
|
||||
@ -87,10 +94,10 @@ void __time_critical_func(render_text_line)(unsigned int line) {
|
||||
|
||||
// Translate each pair of bits into a pair of pixels
|
||||
for(int i=0; i < 7; i++) {
|
||||
uint32_t pixeldata = (bits & 0x2000) ? (text_fore|THEN_EXTEND_1) : (text_back|THEN_EXTEND_1);
|
||||
uint32_t pixeldata = (bits & 0x2000) ? (text_back|THEN_EXTEND_1) : (text_fore|THEN_EXTEND_1);
|
||||
pixeldata |= (bits & 0x1000) ?
|
||||
((uint32_t)text_fore|THEN_EXTEND_1) << 16 :
|
||||
((uint32_t)text_back|THEN_EXTEND_1) << 16;
|
||||
((uint32_t)text_back|THEN_EXTEND_1) << 16 :
|
||||
((uint32_t)text_fore|THEN_EXTEND_1) << 16;
|
||||
bits <<= 2;
|
||||
|
||||
sl->data[sl_pos] = pixeldata;
|
||||
@ -98,10 +105,58 @@ void __time_critical_func(render_text_line)(unsigned int line) {
|
||||
}
|
||||
}
|
||||
|
||||
for(uint i=0; i < 40/8; i++) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
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 __time_critical_func(render_text80_line)(bool p2, unsigned int line) {
|
||||
const uint8_t *page_a = (const uint8_t *)(p2 ? text_p2 : text_p1);
|
||||
const uint8_t *page_b = (const uint8_t *)(p2 ? text_p4 : text_p3);
|
||||
const uint8_t *line_buf_a = page_a + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40);
|
||||
const uint8_t *line_buf_b = page_b + ((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 four 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);
|
||||
col++;
|
||||
|
||||
uint32_t bits = (bits_b << 7) | bits_a;
|
||||
|
||||
// Translate each pair of bits into a pair of pixels
|
||||
for(int i=0; i < 7; i++) {
|
||||
uint32_t pixeldata = (bits & 0x2000) ? (text_back) : (text_fore);
|
||||
pixeldata |= (bits & 0x1000) ?
|
||||
((uint32_t)text_back) << 16 :
|
||||
((uint32_t)text_fore) << 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;
|
||||
|
@ -21,20 +21,20 @@ static inline uint_fast8_t __time_critical_func(char_terminal_bits)(uint_fast8_t
|
||||
}
|
||||
|
||||
|
||||
void __time_critical_func(render_terminal)() {
|
||||
void __time_critical_func(render_videx)() {
|
||||
vga_prepare_frame();
|
||||
|
||||
render_border();
|
||||
|
||||
for(int line=0; line < 24; line++) {
|
||||
render_terminal_line(line);
|
||||
render_videx_line(line);
|
||||
}
|
||||
|
||||
render_border();
|
||||
}
|
||||
|
||||
|
||||
void __time_critical_func(render_terminal_line)(unsigned int line) {
|
||||
void __time_critical_func(render_videx_line)(unsigned int line) {
|
||||
const uint8_t *page = (const uint8_t *)videx_memory;
|
||||
const uint8_t *line_buf = page + (line * 80);
|
||||
|
||||
@ -43,10 +43,9 @@ void __time_critical_func(render_terminal_line)(unsigned int line) {
|
||||
uint sl_pos = 0;
|
||||
|
||||
// Pad 40 pixels on the left to center horizontally
|
||||
while(sl_pos < 40/8) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
}
|
||||
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 < 80; ) {
|
||||
// Grab 14 pixels from the next two characters
|
||||
@ -70,10 +69,10 @@ void __time_critical_func(render_terminal_line)(unsigned int line) {
|
||||
}
|
||||
}
|
||||
|
||||
for(uint i=0; i < 40/8; i++) {
|
||||
sl->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word
|
||||
sl_pos++;
|
||||
}
|
||||
// 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
|
||||
|
||||
sl->length = sl_pos;
|
||||
sl->repeat_count = 1;
|
@ -36,7 +36,7 @@ pixel_out:
|
||||
public wait_vsync:
|
||||
wait 0 irq VSYNC_IRQ_NUM
|
||||
public wait_hsync:
|
||||
wait 0 irq HSYNC_IRQ_NUM [9]
|
||||
wait 0 irq HSYNC_IRQ_NUM [1]
|
||||
public extend_7:
|
||||
nop [1]
|
||||
public extend_6:
|
||||
|
@ -5,7 +5,7 @@
|
||||
volatile uint32_t soft_switches = 0;
|
||||
|
||||
// The currently programmed character generator ROM for text mode
|
||||
uint8_t character_rom[2048];
|
||||
uint8_t character_rom[4096];
|
||||
|
||||
volatile uint8_t videx_crtc_reg;
|
||||
|
||||
|
@ -3,40 +3,20 @@
|
||||
#include <stdint.h>
|
||||
#include "common/buffers.h"
|
||||
|
||||
enum {
|
||||
SOFTSW_TEXT_MODE = 0x01,
|
||||
SOFTSW_MIX_MODE = 0x02,
|
||||
SOFTSW_HIRES_MODE = 0x04,
|
||||
SOFTSW_MODE_MASK = 0x07,
|
||||
|
||||
SOFTSW_PAGE_2 = 0x08,
|
||||
};
|
||||
|
||||
#define text_memory text_p1
|
||||
#define hires_memory hgr_p1
|
||||
#define videx_memory (private_memory+0xF000)
|
||||
|
||||
extern volatile uint32_t soft_switches;
|
||||
extern uint8_t character_rom[2048];
|
||||
extern uint8_t character_rom[4096];
|
||||
extern uint8_t terminal_rom[2048];
|
||||
|
||||
extern volatile uint8_t videx_crtc_reg;
|
||||
extern volatile uint8_t videx_addr;
|
||||
|
||||
extern volatile uint8_t terminal_switches;
|
||||
#define terminal_tbcolor apple_memory[0xC022]
|
||||
#define terminal_border apple_memory[0xC034]
|
||||
|
||||
enum {
|
||||
TERMINAL_80COL = 0x01,
|
||||
TERMINAL_DGR = 0x02,
|
||||
TERMINAL_AUX_WRITE = 0x10,
|
||||
TERMINAL_TEST = 0x20,
|
||||
TERMINAL_IIE_REGS = 0x40,
|
||||
TERMINAL_IIGS_REGS = 0x80,
|
||||
};
|
||||
|
||||
#define TERMINAL_FORE (terminal_tbcolor & 0xf)
|
||||
#define TERMINAL_BACK ((terminal_tbcolor>>4) & 0xf)
|
||||
#define TERMINAL_FORE ((terminal_tbcolor>>4) & 0xf)
|
||||
#define TERMINAL_BACK (terminal_tbcolor & 0xf)
|
||||
#define TERMINAL_BORDER (terminal_border & 0xf)
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#define HSYNC_TIMING_VALUE (((PIXELS_PER_LINE) / 8) - 23)
|
||||
#define VSYNC_TIMING_VALUE ((LINES_PER_FRAME) - 4)
|
||||
|
||||
#define NUM_SCANLINE_BUFFERS 8
|
||||
#define NUM_SCANLINE_BUFFERS 32
|
||||
|
||||
enum {
|
||||
VGA_HSYNC_SM = 0,
|
||||
@ -151,7 +151,7 @@ static void vga_dma_irq_handler() {
|
||||
active_scanline->_flags &= ~(uint_fast8_t)FLAG_BUSY;
|
||||
|
||||
const uint32_t irq_status = spin_lock_blocking(lock);
|
||||
scanline_queue_tail = (scanline_queue_tail + 1) % NUM_SCANLINE_BUFFERS;
|
||||
scanline_queue_tail = (scanline_queue_tail + 1) & (NUM_SCANLINE_BUFFERS-1);
|
||||
trigger_ready_scanline_dma();
|
||||
spin_unlock(lock, irq_status);
|
||||
}
|
||||
@ -244,7 +244,7 @@ struct vga_scanline *vga_prepare_scanline() {
|
||||
scanline->_flags = FLAG_BUSY;
|
||||
scanline->_sync = (uint32_t)THEN_WAIT_HSYNC << 16;
|
||||
|
||||
scanline_queue_head = (scanline_queue_head + 1) % NUM_SCANLINE_BUFFERS;
|
||||
scanline_queue_head = (scanline_queue_head + 1) & (NUM_SCANLINE_BUFFERS-1);
|
||||
|
||||
return scanline;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ struct vga_scanline {
|
||||
volatile uint_fast8_t _flags;
|
||||
|
||||
uint32_t _sync;
|
||||
uint32_t data[(VGA_WIDTH)+1];
|
||||
uint32_t data[(VGA_WIDTH/2)+8];
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user