2023-04-06 03:53:21 +00:00
|
|
|
#include "common/config.h"
|
|
|
|
#include "common/buffers.h"
|
|
|
|
#include "common/flash.h"
|
|
|
|
#include "common/build.h"
|
|
|
|
#include "common/dmacopy.h"
|
2023-04-10 03:46:30 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
#include "vga/render.h"
|
|
|
|
#include "vga/vgaout.h"
|
2023-04-14 05:46:32 +00:00
|
|
|
extern volatile uint8_t romx_textbank;
|
|
|
|
extern volatile uint8_t romx_changed;
|
2023-04-10 03:46:30 +00:00
|
|
|
#endif
|
|
|
|
#ifdef FUNCTION_Z80
|
|
|
|
#include "z80/z80buf.h"
|
|
|
|
#endif
|
|
|
|
|
2023-04-06 03:53:21 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
volatile compat_t cfg_machine = MACHINE_AUTO;
|
|
|
|
volatile compat_t current_machine = MACHINE_AUTO;
|
|
|
|
|
|
|
|
#ifdef FUNCTION_Z80
|
|
|
|
volatile usbmux_t usbmux;
|
2023-04-10 03:46:30 +00:00
|
|
|
volatile serialmux_t serialmux[2];
|
2023-04-06 03:53:21 +00:00
|
|
|
volatile wifimode_t wifimode;
|
|
|
|
|
2023-04-10 03:46:30 +00:00
|
|
|
uint8_t wifi_ssid[32];
|
|
|
|
uint8_t wifi_psk[32];
|
|
|
|
|
|
|
|
uint32_t wifi_address;
|
|
|
|
uint32_t wifi_netmask;
|
|
|
|
|
|
|
|
uint8_t jd_host[32];
|
|
|
|
uint16_t jd_port;
|
2023-04-06 03:53:21 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FUNCTION_VGA
|
|
|
|
extern volatile bool userfont;
|
|
|
|
extern uint8_t character_rom[4096];
|
|
|
|
extern uint8_t terminal_character_rom[4096];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern volatile bool businterface_hold;
|
|
|
|
extern volatile bool businterface_lockout;
|
|
|
|
|
|
|
|
volatile uint16_t cfptr = 0;
|
|
|
|
volatile uint8_t cfbuf[4096];
|
|
|
|
|
|
|
|
uint32_t config_temp[1024];
|
|
|
|
|
|
|
|
#define REPLY_OK 0x00
|
|
|
|
#define REPLY_BUSY 0xBB
|
|
|
|
#define REPLY_EOF 0x01
|
|
|
|
#define REPLY_NOFILE 0x02
|
|
|
|
#define REPLY_EPARAM 0x03
|
|
|
|
#define REPLY_ECMD 0x04
|
|
|
|
|
|
|
|
bool DELAYED_COPY_CODE(parse_config)(uint32_t address) {
|
|
|
|
uint32_t *config = (uint32_t*)address;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if(config[0] != NEWCONFIG_MAGIC) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < (CONFIG_SIZE/sizeof(uint32_t)); i++) {
|
|
|
|
if(config[i] == NEWCONFIG_EOF_MARKER) return true;
|
|
|
|
|
|
|
|
switch(config[i] & 0x0000FFFF) {
|
|
|
|
case CFGTOKEN_HOST_AUTO:
|
|
|
|
cfg_machine = MACHINE_AUTO;
|
|
|
|
break;
|
|
|
|
case CFGTOKEN_HOST_II:
|
|
|
|
cfg_machine = MACHINE_II;
|
|
|
|
break;
|
|
|
|
case CFGTOKEN_HOST_IIE:
|
|
|
|
cfg_machine = MACHINE_IIE;
|
|
|
|
break;
|
|
|
|
case CFGTOKEN_HOST_IIGS:
|
|
|
|
cfg_machine = MACHINE_IIGS;
|
|
|
|
break;
|
|
|
|
case CFGTOKEN_HOST_PRAVETZ:
|
|
|
|
cfg_machine = MACHINE_PRAVETZ;
|
|
|
|
break;
|
2023-04-10 03:46:30 +00:00
|
|
|
case CFGTOKEN_HOST_BASIS:
|
|
|
|
cfg_machine = MACHINE_BASIS;
|
|
|
|
break;
|
2023-04-06 03:53:21 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-14 05:46:32 +00:00
|
|
|
case CFGTOKEN_FONT_00:
|
|
|
|
romx_textbank = (config[i] >> 16) & 0x2F;
|
|
|
|
romx_changed = 1;
|
|
|
|
break;
|
2023-04-06 03:53:21 +00:00
|
|
|
case CFGTOKEN_MONO_00:
|
|
|
|
mono_palette = (config[i] >> 16) & 0xF;
|
|
|
|
break;
|
|
|
|
case CFGTOKEN_TBCOLOR:
|
|
|
|
terminal_tbcolor = (config[i] >> 16) & 0xFF;
|
|
|
|
break;
|
|
|
|
case CFGTOKEN_BORDER:
|
|
|
|
terminal_border = (config[i] >> 16) & 0xF;
|
|
|
|
break;
|
2023-04-17 03:24:37 +00:00
|
|
|
#elif defined(FUNCTION_Z80)
|
2023-04-06 03:53:21 +00:00
|
|
|
case CFGTOKEN_MUX_LOOP:
|
2023-04-10 03:46:30 +00:00
|
|
|
serialmux[(config[i] >> 16) & 1] = SERIAL_LOOP;
|
|
|
|
break;
|
|
|
|
case CFGTOKEN_MUX_UART:
|
|
|
|
serialmux[(config[i] >> 16) & 1] = SERIAL_UART;
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
case CFGTOKEN_MUX_USB:
|
2023-04-10 03:46:30 +00:00
|
|
|
serialmux[(config[i] >> 16) & 1] = SERIAL_USB;
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
case CFGTOKEN_MUX_WIFI:
|
2023-04-10 03:46:30 +00:00
|
|
|
serialmux[(config[i] >> 16) & 1] = SERIAL_WIFI;
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
case CFGTOKEN_MUX_PRN:
|
2023-04-10 03:46:30 +00:00
|
|
|
serialmux[(config[i] >> 16) & 1] = SERIAL_PRINTER;
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
case CFGTOKEN_SER_BAUD:
|
2023-04-10 03:46:30 +00:00
|
|
|
sio[(config[i] >> 16) & 1].baudrate = config[i+1];
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
2023-04-10 03:46:30 +00:00
|
|
|
// case CFGTOKEN_USB_HOST:
|
|
|
|
// usbmux = USB_HOST_CDC;
|
|
|
|
// break;
|
|
|
|
// case CFGTOKEN_USB_GUEST:
|
|
|
|
// usbmux = USB_GUEST_CDC;
|
|
|
|
// break;
|
2023-04-06 03:53:21 +00:00
|
|
|
// case CFGTOKEN_USB_MIDI:
|
|
|
|
// usbmux = USB_GUEST_MIDI;
|
|
|
|
// break;
|
|
|
|
case CFGTOKEN_WIFI_AP:
|
|
|
|
wifimode = WIFI_AP;
|
|
|
|
break;
|
|
|
|
case CFGTOKEN_WIFI_CL:
|
|
|
|
wifimode = WIFI_CLIENT;
|
|
|
|
break;
|
|
|
|
case CFGTOKEN_WIFI_SSID:
|
2023-04-10 03:46:30 +00:00
|
|
|
memset((char*)wifi_ssid, 0, sizeof(wifi_ssid));
|
2023-04-14 05:46:32 +00:00
|
|
|
strncpy((char*)wifi_ssid, (char*)(&config[i+1]), (config[i] >> 24));
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
case CFGTOKEN_WIFI_PSK:
|
2023-04-10 03:46:30 +00:00
|
|
|
memset((char*)wifi_psk, 0, sizeof(wifi_psk));
|
2023-04-14 05:46:32 +00:00
|
|
|
strncpy((char*)wifi_psk, (char*)(&config[i+1]), (config[i] >> 24));
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
case CFGTOKEN_WIFI_IP:
|
2023-04-10 03:46:30 +00:00
|
|
|
wifi_address = config[i+1];
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
case CFGTOKEN_WIFI_NM:
|
2023-04-10 03:46:30 +00:00
|
|
|
wifi_netmask = config[i+1];
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
case CFGTOKEN_JD_HOST:
|
2023-04-10 03:46:30 +00:00
|
|
|
memset((uint8_t*)jd_host, 0, sizeof(jd_host));
|
2023-04-14 05:46:32 +00:00
|
|
|
strncpy(jd_host, (char*)(&config[i+1]), (config[i] >> 24));
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
case CFGTOKEN_JD_PORT:
|
2023-04-10 03:46:30 +00:00
|
|
|
jd_port = config[i+1];
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Advance by the number of dwords for this token
|
|
|
|
i += (((config[i] >> 24) + 3) >> 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DELAYED_COPY_CODE(default_config)() {
|
|
|
|
#ifdef FUNCTION_Z80
|
2023-04-10 03:46:30 +00:00
|
|
|
serialmux[0] = SERIAL_USB;
|
|
|
|
serialmux[1] = SERIAL_LOOP;
|
2023-04-06 03:53:21 +00:00
|
|
|
usbmux = USB_GUEST_CDC;
|
|
|
|
wifimode = WIFI_AP;
|
|
|
|
strcpy((char*)wifi_ssid, "V2RetroNet");
|
|
|
|
strcpy((char*)wifi_psk, "Analog");
|
|
|
|
#endif
|
|
|
|
cfg_machine = MACHINE_AUTO;
|
|
|
|
}
|
|
|
|
|
2023-04-14 05:46:32 +00:00
|
|
|
int DELAYED_COPY_CODE(make_config)(uint32_t rev) {
|
2023-04-06 03:53:21 +00:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
memset(config_temp, 0, sizeof(config_temp));
|
|
|
|
|
|
|
|
config_temp[i++] = NEWCONFIG_MAGIC;
|
2023-04-14 05:46:32 +00:00
|
|
|
config_temp[i++] = CFGTOKEN_REVISION | ((rev & 0xff) << 16);
|
2023-04-06 03:53:21 +00:00
|
|
|
|
|
|
|
switch(cfg_machine) {
|
|
|
|
default:
|
|
|
|
case MACHINE_AUTO:
|
|
|
|
config_temp[i++] = CFGTOKEN_HOST_AUTO;
|
|
|
|
break;
|
|
|
|
case MACHINE_II:
|
|
|
|
config_temp[i++] = CFGTOKEN_HOST_II;
|
|
|
|
break;
|
|
|
|
case MACHINE_IIE:
|
|
|
|
config_temp[i++] = CFGTOKEN_HOST_IIE;
|
|
|
|
break;
|
|
|
|
case MACHINE_IIGS:
|
|
|
|
config_temp[i++] = CFGTOKEN_HOST_IIGS;
|
|
|
|
break;
|
2023-04-10 03:46:30 +00:00
|
|
|
case MACHINE_PRAVETZ:
|
|
|
|
config_temp[i++] = CFGTOKEN_HOST_PRAVETZ;
|
|
|
|
break;
|
|
|
|
case MACHINE_BASIS:
|
|
|
|
config_temp[i++] = CFGTOKEN_HOST_BASIS;
|
|
|
|
break;
|
2023-04-06 03:53:21 +00:00
|
|
|
}
|
|
|
|
#ifdef FUNCTION_Z80
|
2023-04-10 03:46:30 +00:00
|
|
|
switch(serialmux[0]) {
|
2023-04-06 03:53:21 +00:00
|
|
|
case SERIAL_USB:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_USB;
|
|
|
|
break;
|
2023-04-10 03:46:30 +00:00
|
|
|
case SERIAL_UART:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_UART;
|
|
|
|
break;
|
2023-04-06 03:53:21 +00:00
|
|
|
case SERIAL_WIFI:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_WIFI;
|
|
|
|
break;
|
|
|
|
case SERIAL_PRINTER:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_PRN;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case SERIAL_LOOP:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_LOOP;
|
|
|
|
break;
|
|
|
|
}
|
2023-04-10 03:46:30 +00:00
|
|
|
switch(serialmux[1]) {
|
|
|
|
case SERIAL_USB:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_USB | 0x10000;
|
|
|
|
break;
|
|
|
|
case SERIAL_UART:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_UART | 0x10000;
|
|
|
|
break;
|
|
|
|
case SERIAL_WIFI:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_WIFI | 0x10000;
|
|
|
|
break;
|
|
|
|
case SERIAL_PRINTER:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_PRN | 0x10000;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case SERIAL_LOOP:
|
|
|
|
config_temp[i++] = CFGTOKEN_MUX_LOOP | 0x10000;
|
|
|
|
break;
|
|
|
|
}
|
2023-04-06 03:53:21 +00:00
|
|
|
switch(usbmux) {
|
|
|
|
case USB_HOST_CDC:
|
|
|
|
config_temp[i++] = CFGTOKEN_USB_HOST;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case USB_GUEST_CDC:
|
|
|
|
config_temp[i++] = CFGTOKEN_USB_GUEST;
|
|
|
|
break;
|
|
|
|
case USB_GUEST_MIDI:
|
|
|
|
config_temp[i++] = CFGTOKEN_USB_MIDI;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(wifimode) {
|
|
|
|
case WIFI_CLIENT:
|
|
|
|
config_temp[i++] = CFGTOKEN_WIFI_AP;
|
|
|
|
break;
|
|
|
|
case WIFI_AP:
|
|
|
|
config_temp[i++] = CFGTOKEN_WIFI_CL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
config_temp[i] = CFGTOKEN_WIFI_SSID | (((uint32_t)strlen((char*)wifi_ssid)+1) << 24);
|
2023-04-14 05:46:32 +00:00
|
|
|
strcpy((char*)(&config_temp[i+1]), (char*)wifi_ssid);
|
2023-04-06 03:53:21 +00:00
|
|
|
i += 1 + (((config_temp[i] >> 24) + 3) >> 2);
|
|
|
|
|
|
|
|
config_temp[i] = CFGTOKEN_WIFI_PSK | (((uint32_t)strlen((char*)wifi_psk)+1) << 24);
|
2023-04-14 05:46:32 +00:00
|
|
|
strcpy((char*)(&config_temp[i+1]), (char*)wifi_psk);
|
2023-04-06 03:53:21 +00:00
|
|
|
i += 1 + (((config_temp[i] >> 24) + 3) >> 2);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-17 03:24:37 +00:00
|
|
|
config_temp[i++] = CFGTOKEN_FONT_00 | ((romx_textbank & 0x2F) << 16);
|
2023-04-06 03:53:21 +00:00
|
|
|
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);
|
|
|
|
#endif
|
|
|
|
config_temp[i++] = NEWCONFIG_EOF_MARKER;
|
|
|
|
|
|
|
|
return i * 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify config block starts with the appropriate magic, has an end marker,
|
|
|
|
// and doesn't have any fields that would overflow the block.
|
|
|
|
bool DELAYED_COPY_CODE(is_config_valid)(uint32_t address) {
|
|
|
|
uint32_t *config = (uint32_t*)address;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(config[0] != NEWCONFIG_MAGIC) return false;
|
|
|
|
|
|
|
|
for(i = 0; i < (CONFIG_SIZE/sizeof(uint32_t)); i++) {
|
|
|
|
if(config[i] == NEWCONFIG_EOF_MARKER) return true;
|
|
|
|
|
|
|
|
i += ((config[i] >> 24) + 3) >> 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find and return the config revision number for the block
|
|
|
|
uint8_t DELAYED_COPY_CODE(get_config_rev)(uint32_t address) {
|
|
|
|
uint32_t *config = (uint32_t*)address;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i = 0; i < (CONFIG_SIZE/sizeof(uint32_t)); i++) {
|
|
|
|
if((config[i] & 0x0000FFFF) == CFGTOKEN_REVISION)
|
|
|
|
return (config[i] >> 16) & 0xFF;
|
|
|
|
|
|
|
|
if(config[i] == NEWCONFIG_EOF_MARKER) return 0x00;
|
|
|
|
|
|
|
|
i += ((config[i] >> 24) + 3) >> 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0x00;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
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);
|
|
|
|
|
2023-04-17 03:24:37 +00:00
|
|
|
return ((int8_t)(a-b)) >= 0;
|
2023-04-06 03:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DELAYED_COPY_CODE(read_config)() {
|
|
|
|
if(is_config_valid(FLASH_CONFIG_ONETIME)) {
|
|
|
|
internal_flags &= ~IFLAGS_TEST;
|
|
|
|
soft_switches |= SOFTSW_TEXT_MODE;
|
|
|
|
if(parse_config(FLASH_CONFIG_ONETIME))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
|
|
|
|
if(!is_config_valid(FLASH_CONFIG_SECONDARY) || (is_primary_config_newer())) {
|
|
|
|
if(parse_config(FLASH_CONFIG_PRIMARY))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(is_config_valid(FLASH_CONFIG_SECONDARY)) {
|
|
|
|
if(parse_config(FLASH_CONFIG_SECONDARY))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
default_config();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DELAYED_COPY_CODE(write_config)(bool onetime) {
|
|
|
|
uint8_t rev = 0xFF;
|
|
|
|
bool write_secondary = false;
|
|
|
|
bool retval = false;
|
|
|
|
|
2023-04-06 04:02:50 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
// Disable video output to stop DMA and IRQs
|
|
|
|
vga_dpms_sleep();
|
2023-04-06 04:02:50 +00:00
|
|
|
#endif
|
2023-04-06 03:53:21 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
} else if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
|
|
|
|
write_secondary = true;
|
|
|
|
rev = get_config_rev(FLASH_CONFIG_PRIMARY);
|
|
|
|
} else if(is_config_valid(FLASH_CONFIG_SECONDARY)) {
|
|
|
|
write_secondary = false;
|
|
|
|
rev = get_config_rev(FLASH_CONFIG_SECONDARY);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
} else if(write_secondary) {
|
|
|
|
flash_range_erase((FLASH_CONFIG_SECONDARY-XIP_BASE), CONFIG_SIZE);
|
|
|
|
flash_range_program((FLASH_CONFIG_SECONDARY-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE);
|
|
|
|
} else {
|
|
|
|
flash_range_erase((FLASH_CONFIG_PRIMARY-XIP_BASE), CONFIG_SIZE);
|
|
|
|
flash_range_program((FLASH_CONFIG_PRIMARY-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = true;
|
|
|
|
}
|
|
|
|
|
2023-04-06 04:02:50 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
// Enable video output now that we are done
|
|
|
|
vga_dpms_wake();
|
2023-04-06 04:02:50 +00:00
|
|
|
#endif
|
2023-04-06 03:53:21 +00:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2023-04-14 05:46:32 +00:00
|
|
|
uint8_t DELAYED_COPY_CODE(get_config_block)() {
|
|
|
|
uint16_t last_config_block;
|
|
|
|
uint16_t next_config_block;
|
2023-04-06 03:53:21 +00:00
|
|
|
|
2023-04-14 05:46:32 +00:00
|
|
|
last_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
|
|
|
|
next_config_block = last_config_block;
|
2023-04-06 03:53:21 +00:00
|
|
|
|
2023-04-14 05:46:32 +00:00
|
|
|
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;
|
|
|
|
next_config_block = (FLASH_CONFIG_SECONDARY-XIP_BASE) / 4096;
|
|
|
|
} else {
|
|
|
|
last_config_block = (FLASH_CONFIG_SECONDARY-XIP_BASE) / 4096;
|
|
|
|
next_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
|
|
|
|
}
|
|
|
|
} else if(is_config_valid(FLASH_CONFIG_SECONDARY)) {
|
|
|
|
last_config_block = (FLASH_CONFIG_SECONDARY-XIP_BASE) / 4096;
|
|
|
|
next_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
|
2023-04-06 03:53:21 +00:00
|
|
|
}
|
2023-04-14 05:46:32 +00:00
|
|
|
|
|
|
|
config_rpybuf[5] = (next_config_block >> 8) & 0xFF;
|
|
|
|
config_rpybuf[4] = (next_config_block >> 0) & 0xFF;
|
|
|
|
config_rpybuf[3] = (last_config_block >> 8) & 0xFF;
|
|
|
|
config_rpybuf[2] = (last_config_block >> 0) & 0xFF;
|
2023-04-06 03:53:21 +00:00
|
|
|
|
|
|
|
return REPLY_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t DELAYED_COPY_CODE(cf_readblock)(uint16_t param0) {
|
|
|
|
if(param0 >= (FLASH_SIZE/4096)) return REPLY_EPARAM;
|
|
|
|
|
2023-04-06 04:02:50 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
// Disable video output to stop DMA and IRQs
|
|
|
|
vga_dpms_sleep();
|
2023-04-06 04:02:50 +00:00
|
|
|
#endif
|
2023-04-06 03:53:21 +00:00
|
|
|
|
2023-04-06 04:02:50 +00:00
|
|
|
memcpy32((void*)cfbuf, (void*)(XIP_BASE+(param0 * 4096)), 4096);
|
2023-04-06 03:53:21 +00:00
|
|
|
|
2023-04-06 04:02:50 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
// Enable video output now that we are done
|
|
|
|
vga_dpms_wake();
|
2023-04-06 04:02:50 +00:00
|
|
|
#endif
|
2023-04-06 03:53:21 +00:00
|
|
|
|
|
|
|
return REPLY_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t DELAYED_COPY_CODE(cf_writeblock)(uint16_t param0) {
|
|
|
|
// Protect bottom 512K of flash
|
|
|
|
if(param0 < 0x080)
|
|
|
|
return REPLY_EPARAM;
|
|
|
|
|
|
|
|
if(param0 >= (FLASH_SIZE/4096))
|
|
|
|
return REPLY_EPARAM;
|
|
|
|
|
2023-04-06 04:02:50 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
// Disable video output to stop DMA and IRQs
|
|
|
|
vga_dpms_sleep();
|
2023-04-06 04:02:50 +00:00
|
|
|
#endif
|
2023-04-06 03:53:21 +00:00
|
|
|
|
2023-04-14 05:46:32 +00:00
|
|
|
flash_range_program(((uint32_t)param0) * 4096, (void*)cfbuf, 4096);
|
2023-04-06 03:53:21 +00:00
|
|
|
|
2023-04-06 04:02:50 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
// Enable video output now that we are done
|
|
|
|
vga_dpms_wake();
|
2023-04-06 04:02:50 +00:00
|
|
|
#endif
|
2023-04-06 03:53:21 +00:00
|
|
|
|
|
|
|
return REPLY_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t DELAYED_COPY_CODE(cf_eraseblock)(uint16_t param0) {
|
|
|
|
// Protect bottom 512K of flash
|
|
|
|
if(param0 < 0x080)
|
|
|
|
return REPLY_EPARAM;
|
|
|
|
|
|
|
|
if(param0 >= (FLASH_SIZE/4096))
|
|
|
|
return REPLY_EPARAM;
|
|
|
|
|
2023-04-06 04:02:50 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
// Disable video output to stop DMA and IRQs
|
|
|
|
vga_dpms_sleep();
|
2023-04-06 04:02:50 +00:00
|
|
|
#endif
|
2023-04-06 03:53:21 +00:00
|
|
|
|
2023-04-14 05:46:32 +00:00
|
|
|
flash_range_erase(((uint32_t)param0) * 4096, 4096);
|
|
|
|
|
|
|
|
#ifdef FUNCTION_VGA
|
|
|
|
// Enable video output now that we are done
|
|
|
|
vga_dpms_wake();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return REPLY_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef FUNCTION_VGA
|
|
|
|
uint8_t DELAYED_COPY_CODE(test_font)() {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i = 0; i < 2048; i++) {
|
|
|
|
character_rom[i] = cfbuf[i];
|
|
|
|
}
|
|
|
|
userfont = true;
|
|
|
|
|
|
|
|
return REPLY_OK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uint8_t DELAYED_COPY_CODE(read_font)(uint16_t param0) {
|
|
|
|
if(param0 > 0x27) return REPLY_EPARAM;
|
|
|
|
|
|
|
|
return cf_readblock((FLASH_FONT(param0)-XIP_BASE) / 4096);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t DELAYED_COPY_CODE(erase_font)(uint16_t param0) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(param0 > 0x27) return REPLY_EPARAM;
|
|
|
|
|
|
|
|
#ifdef FUNCTION_VGA
|
|
|
|
// Disable video output to stop DMA and IRQs
|
|
|
|
vga_dpms_sleep();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
flash_range_erase((FLASH_FONT(param0)-XIP_BASE), FONT_SIZE);
|
|
|
|
|
|
|
|
#ifdef FUNCTION_VGA
|
|
|
|
// Enable video output now that we are done
|
|
|
|
vga_dpms_wake();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return REPLY_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t DELAYED_COPY_CODE(write_font)(uint16_t param0) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(param0 > 0x27) return REPLY_EPARAM;
|
|
|
|
|
|
|
|
#ifdef FUNCTION_VGA
|
|
|
|
// Disable video output to stop DMA and IRQs
|
|
|
|
vga_dpms_sleep();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
flash_range_program((FLASH_FONT(param0)-XIP_BASE), (void*)cfbuf, FONT_SIZE);
|
2023-04-06 03:53:21 +00:00
|
|
|
|
2023-04-06 04:02:50 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
// Enable video output now that we are done
|
|
|
|
vga_dpms_wake();
|
2023-04-06 04:02:50 +00:00
|
|
|
#endif
|
2023-04-06 03:53:21 +00:00
|
|
|
|
|
|
|
return REPLY_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DELAYED_COPY_CODE(config_handler)() {
|
|
|
|
uint8_t retval = 0;
|
|
|
|
uint16_t param0, param1, param2;
|
|
|
|
int rs = 1;
|
|
|
|
|
|
|
|
if(config_cmdbuf[0] == 0xFF) return;
|
|
|
|
|
|
|
|
param0 = config_cmdbuf[3];
|
|
|
|
param0 <<= 8;
|
|
|
|
param0 |= config_cmdbuf[2];
|
|
|
|
|
|
|
|
param1 = config_cmdbuf[5];
|
|
|
|
param1 <<= 8;
|
|
|
|
param1 |= config_cmdbuf[4];
|
|
|
|
|
|
|
|
param2 = config_cmdbuf[7];
|
|
|
|
param2 <<= 8;
|
|
|
|
param2 |= config_cmdbuf[6];
|
|
|
|
|
|
|
|
config_rpybuf[7] = 0x00;
|
|
|
|
config_rpybuf[6] = 0x00;
|
|
|
|
config_rpybuf[5] = 0x00;
|
|
|
|
config_rpybuf[4] = 0x00;
|
|
|
|
config_rpybuf[3] = 0x00;
|
|
|
|
config_rpybuf[2] = 0x00;
|
|
|
|
config_rpybuf[1] = 0x00;
|
|
|
|
config_rpybuf[0] = REPLY_BUSY;
|
|
|
|
|
|
|
|
switch(config_cmdbuf[0]) {
|
|
|
|
case 'C':
|
|
|
|
switch(config_cmdbuf[1]) {
|
|
|
|
default:
|
|
|
|
retval = REPLY_ECMD;
|
|
|
|
break;
|
2023-04-14 05:46:32 +00:00
|
|
|
#ifdef FUNCTION_VGA
|
2023-04-06 03:53:21 +00:00
|
|
|
case 'T':
|
|
|
|
// One-time load of font data (lost at reboot)
|
2023-04-14 05:46:32 +00:00
|
|
|
retval = test_font();
|
|
|
|
case 'S':
|
|
|
|
romx_textbank = param0 & 0x2F;
|
|
|
|
romx_changed = 1;
|
|
|
|
retval = REPLY_OK;
|
|
|
|
#endif
|
|
|
|
case 'r':
|
|
|
|
// Read font from flash
|
|
|
|
retval = read_font(param0);
|
|
|
|
cfptr = 0;
|
|
|
|
break;
|
|
|
|
case 'w':
|
2023-04-06 03:53:21 +00:00
|
|
|
// Save font to flash
|
2023-04-14 05:46:32 +00:00
|
|
|
retval = write_font(param0);
|
|
|
|
cfptr = 0;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
// Erase font from flash
|
|
|
|
retval = erase_font(param0);
|
|
|
|
cfptr = 0;
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
retval = REPLY_OK;
|
|
|
|
switch(config_cmdbuf[1]) {
|
|
|
|
default:
|
|
|
|
retval = REPLY_ECMD;
|
|
|
|
break;
|
|
|
|
case '2':
|
|
|
|
current_machine = MACHINE_II;
|
|
|
|
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
|
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
current_machine = MACHINE_IIE;
|
|
|
|
internal_flags &= ~IFLAGS_IIGS_REGS;
|
|
|
|
internal_flags |= IFLAGS_IIE_REGS;
|
|
|
|
break;
|
|
|
|
case 'G':
|
|
|
|
current_machine = MACHINE_IIGS;
|
|
|
|
internal_flags |= IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS;
|
|
|
|
break;
|
|
|
|
#if 0
|
|
|
|
case 'B':
|
|
|
|
current_machine = MACHINE_BASIS;
|
|
|
|
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
current_machine = MACHINE_PRAVETZ;
|
|
|
|
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
|
|
|
|
break;
|
|
|
|
case '7':
|
|
|
|
current_machine = MACHINE_AGAT7;
|
|
|
|
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
|
|
|
|
break;
|
|
|
|
case '9':
|
|
|
|
current_machine = MACHINE_AGAT9;
|
|
|
|
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
// Flash Commands
|
|
|
|
// All valid flash commands will reset the cf pointer to 0
|
|
|
|
switch(config_cmdbuf[1]) {
|
|
|
|
default:
|
|
|
|
retval = REPLY_ECMD;
|
|
|
|
break;
|
2023-04-14 05:46:32 +00:00
|
|
|
case 'c':
|
|
|
|
// Current Config Block
|
|
|
|
retval = get_config_block();
|
|
|
|
cfptr = 0;
|
|
|
|
break;
|
2023-04-06 03:53:21 +00:00
|
|
|
case 'r':
|
|
|
|
// Read block
|
|
|
|
retval = cf_readblock(param0);
|
|
|
|
cfptr = 0;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
// Write block
|
|
|
|
retval = cf_writeblock(param0);
|
|
|
|
cfptr = 0;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
// Erase block
|
|
|
|
retval = cf_eraseblock(param0);
|
|
|
|
cfptr = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'R':
|
|
|
|
// Reboot and bypass auto-detection of machine type.
|
|
|
|
cfg_machine = current_machine;
|
|
|
|
write_config(true);
|
|
|
|
flash_reboot();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'I':
|
|
|
|
switch(config_cmdbuf[1]) {
|
|
|
|
default:
|
|
|
|
retval = REPLY_ECMD;
|
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
// Identify Current Host Setting
|
|
|
|
retval = REPLY_OK;
|
|
|
|
switch(current_machine) {
|
|
|
|
case MACHINE_II:
|
|
|
|
config_rpybuf[rs++] = '2';
|
|
|
|
break;
|
|
|
|
case MACHINE_IIE:
|
|
|
|
config_rpybuf[rs++] = 'E';
|
|
|
|
break;
|
|
|
|
case MACHINE_IIGS:
|
|
|
|
config_rpybuf[rs++] = 'G';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
config_rpybuf[rs++] = '?';
|
|
|
|
retval = REPLY_EPARAM;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'F':
|
|
|
|
// Identify Current Firmware Function
|
|
|
|
retval = REPLY_OK;
|
|
|
|
#ifdef FUNCTION_VGA
|
|
|
|
config_rpybuf[rs++] = 'V';
|
|
|
|
config_rpybuf[rs++] = 'G';
|
|
|
|
config_rpybuf[rs++] = 'A';
|
|
|
|
#endif
|
|
|
|
#ifdef FUNCTION_Z80
|
|
|
|
config_rpybuf[rs++] = 'Z';
|
|
|
|
config_rpybuf[rs++] = '8';
|
|
|
|
config_rpybuf[rs++] = '0';
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
// Identify Hardware Type
|
|
|
|
retval = REPLY_OK;
|
2023-04-17 03:18:38 +00:00
|
|
|
config_rpybuf[rs++] = 0x02; // V2 Retro Computing
|
|
|
|
config_rpybuf[rs++] = 'A'; // V2 Analog
|
|
|
|
config_rpybuf[rs++] = HWBYTE; // 'G'S / 'W'ifi / 'L'C
|
|
|
|
config_rpybuf[rs++] = HWREV; // '1'
|
2023-04-06 03:53:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
// Identify Date Request
|
|
|
|
retval = REPLY_OK;
|
|
|
|
config_rpybuf[rs++] = (BUILDDATE >> 24) & 0xFF;
|
|
|
|
config_rpybuf[rs++] = (BUILDDATE >> 16) & 0xFF;
|
|
|
|
config_rpybuf[rs++] = (BUILDDATE >> 8) & 0xFF;
|
|
|
|
config_rpybuf[rs++] = (BUILDDATE >> 0) & 0xFF;
|
|
|
|
config_rpybuf[rs++] = (BUILDID >> 8) & 0xFF;
|
|
|
|
config_rpybuf[rs++] = (BUILDID >> 0) & 0xFF;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Unrecognized command
|
|
|
|
retval = REPLY_ECMD;
|
|
|
|
}
|
|
|
|
|
|
|
|
config_cmdbuf[7] = 0xFF;
|
|
|
|
config_cmdbuf[6] = 0xFF;
|
|
|
|
config_cmdbuf[5] = 0xFF;
|
|
|
|
config_cmdbuf[4] = 0xFF;
|
|
|
|
config_cmdbuf[3] = 0xFF;
|
|
|
|
config_cmdbuf[2] = 0xFF;
|
|
|
|
config_cmdbuf[1] = 0xFF;
|
|
|
|
config_cmdbuf[0] = 0xFF;
|
|
|
|
|
|
|
|
config_rpybuf[0] = retval;
|
|
|
|
}
|