Build 0159

Progress on PCPI mode bug fixes. PCPI mode is now working again, but the config interface is still broken enough to prevent the use of the config utility while in this mode.. Sending the FORMAT command from the monitor rom returns the card to defaults.
Replace n with the slot number the card is installed in:

]CALL -151
*CnF0:46 4F 52 4D 41 54 00 00

Correction of mousetext / inverse / flashing handling on IIe
see https://github.com/V2RetroComputing/analog/issues/3

Monochrome mode & color palettes are now implemented.
$C0n1: Monochrome mode & palette
  $80: B&W
  $90: Inverse
  $A0: Amber
  $B0: Inverse Amber
  $C0: Green
  $D0: Inverse Green
  $E0: Commodore 64 Theme
  $F0: Use IIgs palette
$C0n2: Mirror of IIgs TBCOLOR register
$C0n3: Mirror of IIgs BORDER register
This commit is contained in:
David Kuder 2023-03-02 11:05:44 -05:00
parent ecb776e17b
commit 0835003caa
32 changed files with 719 additions and 270 deletions

View File

@ -32,6 +32,7 @@ target_sources(v2-analog-${PICO_BOARD} PUBLIC
common/abus.c
common/config.c
common/main.c
common/usb_descriptors.c
diag/businterface.c
diag/diag.c
fs/businterface.c
@ -43,7 +44,7 @@ target_sources(v2-analog-${PICO_BOARD} PUBLIC
vga/render_hires.c
vga/render_lores.c
vga/render_text.c
vga/render_videx.c
vga/render_80col.c
vga/render_dhgr.c
vga/render_dgr.c
vga/render_shr.c
@ -69,6 +70,10 @@ target_link_libraries(v2-analog-${PICO_BOARD} PUBLIC
pico_multicore
pico_stdlib
littlefs-lib
tinyusb_device
tinyusb_board
hardware_resets
hardware_irq
hardware_dma
hardware_pio
)

View File

@ -1,5 +1,10 @@
#include "buffers.h"
volatile uint32_t soft_switches = 0;
volatile uint32_t internal_flags = 0;
volatile uint8_t reset_state = 0;
volatile uint8_t cardslot = 0;
volatile uint32_t busactive = 0;

View File

@ -2,6 +2,8 @@
#include <stdint.h>
extern volatile uint8_t reset_state;
extern volatile uint8_t cardslot;
extern volatile uint32_t busactive;
@ -57,6 +59,8 @@ extern volatile uint8_t *videx_page;
extern volatile uint32_t soft_switches;
extern volatile uint32_t internal_flags;
#define SOFTSW_TEXT_MODE 0x00000001
#define SOFTSW_MIX_MODE 0x00000002
#define SOFTSW_HIRES_MODE 0x00000004
@ -94,7 +98,7 @@ extern volatile uint32_t soft_switches;
#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
#define SOFTSW_TERMINAL 0x10000000
#define IFLAGS_TEST 0x20000000
#define IFLAGS_IIE_REGS 0x40000000
#define IFLAGS_IIGS_REGS 0x80000000

View File

@ -44,17 +44,17 @@ void parse_config(uint8_t *buffer) {
cfg_machine = MACHINE_AUTO;
} else if(!strcmp("II", buffer+2)) {
cfg_machine = MACHINE_II;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
} else if(!strcmp("IIE", buffer+2)) {
cfg_machine = MACHINE_IIE;
soft_switches &= ~SOFTSW_IIGS_REGS;
soft_switches |= SOFTSW_IIE_REGS;
internal_flags &= ~IFLAGS_IIGS_REGS;
internal_flags |= IFLAGS_IIE_REGS;
} else if(!strcmp("IIGS", buffer+2)) {
cfg_machine = MACHINE_IIGS;
soft_switches |= SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS;
internal_flags |= IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS;
} else if(!strcmp("PRAVETZ", buffer+2)) {
cfg_machine = MACHINE_PRAVETZ;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
}
} else if(!memcmp("S=", buffer, 2)) {
if(!strcmp("USB", buffer+2)) {
@ -97,7 +97,7 @@ void default_config() {
int make_config(uint8_t *buf, uint16_t len) {
uint16_t ptr = 0;
memset(buf, 0, len);
switch(cfg_mode) {
@ -198,7 +198,7 @@ int make_config(uint8_t *buf, uint16_t len) {
strcpy(buf+ptr, "WP=");
strncpy(buf+ptr+2, (char*)wifi_psk, 24);
ptr += 32;
return ptr;
}
@ -206,7 +206,7 @@ void write_config() {
uint8_t config_temp[1024];
int config_len;
config_len = make_config(config_temp, sizeof(config_temp));
int file = pico_open("config", LFS_O_WRONLY | LFS_O_CREAT);
if(file < 0)
return;
@ -246,7 +246,7 @@ void upload_config() {
pico_read(file, (uint8_t*)(apple_memory + 0xC800), 1024);
pico_close(file);
}
memcpy(config_errbuf, ERR_READY, sizeof(ERR_READY));
}
@ -318,27 +318,27 @@ void config_handler() {
if(!memcmp("H=", (uint8_t*)config_cmdbuf, 2)) {
if(!strcmp("II", config_cmdbuf+2)) {
current_machine = MACHINE_II;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
} else if(!strcmp("IIE", config_cmdbuf+2)) {
current_machine = MACHINE_IIE;
soft_switches &= ~SOFTSW_IIGS_REGS;
soft_switches |= SOFTSW_IIE_REGS;
internal_flags &= ~IFLAGS_IIGS_REGS;
internal_flags |= IFLAGS_IIE_REGS;
} else if(!strcmp("IIGS", config_cmdbuf+2)) {
current_machine = MACHINE_IIGS;
soft_switches |= SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS;
internal_flags |= IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS;
#if 0
} else if(!strcmp("B108", config_cmdbuf+2)) {
current_machine = MACHINE_BASIS;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
} else if(!strcmp("P", config_cmdbuf+2)) {
current_machine = MACHINE_PRAVETZ;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
} else if(!strcmp("A7", config_cmdbuf+2)) {
current_machine = MACHINE_AGAT7;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
} else if(!strcmp("A9", config_cmdbuf+2)) {
current_machine = MACHINE_AGAT9;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
#endif
}
} else if(!memcmp("UF", (uint8_t*)config_cmdbuf, 2)) {
@ -354,7 +354,9 @@ void config_handler() {
} else if(!memcmp("FORMAT", (uint8_t*)config_cmdbuf, 6)) {
config_format();
flash_reboot();
} else if(!memcmp("RB", (uint8_t*)config_cmdbuf, 2)) {
flash_reboot();
}
memset(config_cmdbuf, 0x00, 7);
}

View File

@ -13,6 +13,9 @@
#include <pico/cyw43_arch.h>
#endif
typedef void (*businterface_t)(uint32_t address, uint32_t value);
volatile businterface_t businterface = NULL;
static void __time_critical_func(core1_loop)() {
for(;;) {
uint32_t value = pio_sm_get_blocking(CONFIG_ABUS_PIO, ABUS_MAIN_SM);
@ -21,10 +24,11 @@ static void __time_critical_func(core1_loop)() {
// device read access
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) != 0) {
if(CARD_SELECT) {
pio_sm_put_blocking(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, apple_memory[address]);
pio_sm_put(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, apple_memory[address]);
//pio_sm_put_blocking(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, apple_memory[address]);
}
}
busactive = 1;
if(CARD_SELECT) {
@ -38,52 +42,56 @@ static void __time_critical_func(core1_loop)() {
apple_memory[address] = value;
}
}
}
switch(current_mode) {
case MODE_DIAG:
diag_businterface(address, value);
break;
case MODE_FS:
fs_businterface(address, value);
break;
case MODE_VGACARD:
vga_businterface(address, value);
break;
case MODE_APPLICARD:
z80_businterface(address, value);
break;
case MODE_SERIAL:
serial_businterface(address, value);
break;
case MODE_PARALLEL:
parallel_businterface(address, value);
break;
}
if(current_machine == MACHINE_AUTO) {
} else if(current_machine == MACHINE_AUTO) {
if((apple_memory[0x0417] == 0xE7) && (apple_memory[0x416] == 0xC9)) { // Apple IIgs
current_machine = MACHINE_IIGS;
soft_switches &= ~SOFTSW_IIE_REGS;
soft_switches |= SOFTSW_IIGS_REGS;
internal_flags &= ~IFLAGS_IIE_REGS;
internal_flags |= IFLAGS_IIGS_REGS;
} else if((apple_memory[0x0417] == 0xE5) && (apple_memory[0x416] == 0xAF)) { // Apple //e Enhanced
current_machine = MACHINE_IIE;
soft_switches |= SOFTSW_IIE_REGS;
soft_switches &= ~SOFTSW_IIGS_REGS;
internal_flags |= IFLAGS_IIE_REGS;
internal_flags &= ~IFLAGS_IIGS_REGS;
} else if((apple_memory[0x0415] == 0xDD) && (apple_memory[0x413] == 0xE5)) { // Apple //e Unenhanced
current_machine = MACHINE_IIE;
soft_switches |= SOFTSW_IIE_REGS;
soft_switches &= ~SOFTSW_IIGS_REGS;
internal_flags |= IFLAGS_IIE_REGS;
internal_flags &= ~IFLAGS_IIGS_REGS;
} else if(apple_memory[0x0410] == 0xD0) { // Apple II/Plus/J-Plus with Autostart
current_machine = MACHINE_II;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
} else if((apple_memory[0x07D0] == 0xAA) && (apple_memory[0x07D1] == 0x60)) { // Apple II without Autostart
current_machine = MACHINE_II;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
} else if(apple_memory[0x0410] == 0xF2) { // Pravetz!
current_machine = MACHINE_PRAVETZ;
soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS);
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
}
} else switch(reset_state) {
case 0:
if(value == ((0xFFFC << 10) | 0x300 | 0x62))
reset_state++;
break;
case 1:
if(value == ((0xFFFD << 10) | 0x300 | 0xFA))
reset_state++;
else
reset_state=0;
break;
case 2:
if((value & 0x3FFFF00) == ((0xFA62 << 10) | 0x300))
reset_state++;
else
reset_state=0;
break;
case 3:
soft_switches = SOFTSW_TEXT_MODE;
default:
reset_state = 0;
break;
}
if(businterface != NULL) {
(*businterface)(address, value);
}
}
}
@ -92,23 +100,33 @@ static void core0_loop() {
for(;;) {
switch(current_mode) {
case MODE_DIAG:
businterface = &diag_businterface;
diagmain();
break;
case MODE_FS:
businterface = &fs_businterface;
fsmain();
break;
default:
current_mode = MODE_VGACARD;
case MODE_VGACARD:
if(cardslot == 0) cardslot = 3;
businterface = &vga_businterface;
vgamain();
break;
case MODE_APPLICARD:
if(cardslot == 0) cardslot = 4;
businterface = &z80_businterface;
z80main();
break;
case MODE_SERIAL:
if(cardslot == 0) cardslot = 2;
businterface = &serial_businterface;
serialmain();
break;
case MODE_PARALLEL:
if(cardslot == 0) cardslot = 1;
businterface = &parallel_businterface;
parallelmain();
break;
}
@ -130,7 +148,7 @@ int main() {
memcpy((uint8_t*)apple_memory+0xC5F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
memcpy((uint8_t*)apple_memory+0xC6F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
memcpy((uint8_t*)apple_memory+0xC7F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
// Sensible defaults if there is no config / fs
default_config();

View File

@ -0,0 +1,238 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
#define USB_VID 0xCafe
#define USB_BCD 0x0200
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_CDC_0 = 0,
ITF_NUM_CDC_0_DATA,
ITF_NUM_TOTAL
};
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x82
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x83
#else
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x82
#endif
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
//TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
};
#if TUD_OPT_HIGH_SPEED
// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
uint8_t const desc_hs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
};
// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
tusb_desc_device_qualifier_t const desc_device_qualifier =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.bNumConfigurations = 0x01,
.bReserved = 0x00
};
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
uint8_t const* tud_descriptor_device_qualifier_cb(void)
{
return (uint8_t const*) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration;
}
#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"V2Retro", // 1: Manufacturer
"V2 Analog VGA", // 2: Product
"123456", // 3: Serials, should use chip ID
"V2 Analog CDC", // 4: CDC Interface
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if ( index == 0)
{
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
if ( chr_count > 31 ) chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
return _desc_str;
}

View File

@ -39,7 +39,7 @@ void __time_critical_func(fs_businterface)(uint32_t address, uint32_t value) {
}
// 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((internal_flags & IFLAGS_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((address & 0xff80) == 0xc000) {
switch(address & 0x7f) {
case 0x00:

View File

@ -1,4 +1,4 @@
#include <stdint.h>
uint8_t grappler_rom[2048] = {
static const uint8_t grappler_rom[2048] = {
};

View File

@ -7,7 +7,7 @@
#include "serial/serialbuffer.h"
static inline void __time_critical_func(serial_read)(uint32_t address) {
switch(address & 0x7) {
switch(address & 0xF) {
case 8: // Read Data from RX FIFO
serial_rx_advance();
break;
@ -15,7 +15,7 @@ static inline void __time_critical_func(serial_read)(uint32_t address) {
}
static inline void __time_critical_func(serial_write)(uint32_t address, uint32_t value) {
switch(address & 0x7) {
switch(address & 0xF) {
case 8: // Write Data to TX FIFO
serial_tx_push(value & 0xff);
break;

View File

@ -5,34 +5,41 @@
#include "common/config.h"
#include "serial/businterface.h"
#include "serial/serialbuffer.h"
#include "serial/serialrom.h"
#include "bsp/board.h"
#include "tusb.h"
void serialmain() {
int c;
int c, i;
// Copy SSC ROM
memcpy((void*)(apple_memory + 0xC800), (void*)(ssc_rom), 0x800);
memcpy((void*)(apple_memory + 0xC100), (void*)(ssc_rom + 0x700), 0x100);
memcpy((void*)(apple_memory + 0xC200), (void*)(apple_memory + 0xC100), 0x600);
switch(serialmux) {
case SERIAL_USB:
board_init();
tusb_init();
break;
case SERIAL_WIFI:
break;
}
while(current_mode == MODE_SERIAL) {
config_handler();
switch(serialmux) {
#if 0
case SERIAL_USB:
if(!stdio_usb_connected()) {
sleep_ms(100);
} else {
c=getchar_timeout_us(0);
if(c != PICO_ERROR_TIMEOUT) {
serial_rx_push(c);
}
if(!serial_tx_empty()) {
c = serial_tx_pop();
putchar(c);
}
tud_task();
if(tud_cdc_n_available(0)) {
uint8_t buf[64];
uint32_t count = tud_cdc_n_read(0, buf, sizeof(buf));
for(i = 0; i < count; i++)
serial_rx_push(buf[i]);
}
break;
#endif
case SERIAL_WIFI:
break;
case SERIAL_LOOP:

View File

@ -1,5 +1,4 @@
#include "serial/serialbuffer.h"
#include "serial/serialrom.h"
volatile uint8_t *serial_reg = apple_memory + 0xC0A0;

View File

@ -3,8 +3,6 @@
#include <stdint.h>
#include "common/buffers.h"
extern uint8_t ssc_rom[2048];
extern volatile uint8_t *serial_reg;
void serial_rx_advance();

View File

@ -1,2 +1,2 @@
uint8_t ssc_rom[2048] = {
static const uint8_t ssc_rom[2048] = {
};

View File

@ -0,0 +1,114 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by board.mk
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_DEVICE_RHPORT_NUM
#define BOARD_DEVICE_RHPORT_NUM 0
#endif
// RHPort max operational speed can defined by board.mk
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
#else
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#endif
#endif
// Device mode with rhport and speed defined by board.mk
#if BOARD_DEVICE_RHPORT_NUM == 0
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#elif BOARD_DEVICE_RHPORT_NUM == 1
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#else
#error "Incorrect RHPort configuration"
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG 0
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_HID 0
#define CFG_TUD_CDC 1
#define CFG_TUD_MSC 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
//------------- CDC -------------//
// CDC buffer size Should be sufficient to hold data
#define CFG_TUD_CDC_RX_BUFSIZE 16
#define CFG_TUD_CDC_TX_BUFSIZE 16
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

Binary file not shown.

View File

@ -6,14 +6,7 @@
#include "vga/vgabuf.h"
volatile uint8_t *videx_page = videx_memory;
static inline void __time_critical_func(videx_crtc_addr)(uint32_t value) {
}
static inline void __time_critical_func(videx_crtc_write)(uint32_t value) {
}
volatile uint8_t *terminal_page = terminal_memory;
void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
@ -21,57 +14,57 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
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)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_80STORE;
}
break;
case 0x01:
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_80STORE;
}
break;
case 0x04:
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_AUX_WRITE;
}
break;
case 0x05:
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_AUX_WRITE;
}
break;
case 0x08:
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_AUXZP;
}
break;
case 0x09:
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_AUXZP;
}
break;
case 0x0c:
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_80COL;
}
break;
case 0x0d:
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_80COL;
}
break;
case 0x0e:
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_ALTCHAR;
}
break;
case 0x0f:
if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_ALTCHAR;
}
break;
case 0x21:
if((SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if(value & 0x80) {
soft_switches |= SOFTSW_MONOCHROME;
} else {
@ -80,22 +73,22 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
}
break;
case 0x22:
if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
terminal_tbcolor = value & 0xff;
}
break;
case 0x29:
if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_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);
}
break;
case 0x34:
if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
terminal_border = value & 0x0f;
}
break;
case 0x35:
if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_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);
}
break;
@ -124,22 +117,22 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
soft_switches |= SOFTSW_HIRES_MODE;
break;
case 0x5e:
if(soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) {
if(internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) {
soft_switches |= SOFTSW_DGR;
}
break;
case 0x5f:
if(soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) {
if(internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) {
soft_switches &= ~SOFTSW_DGR;
}
break;
case 0x7e:
if((soft_switches & SOFTSW_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_IOUDIS;
}
break;
case 0x7f:
if((soft_switches & SOFTSW_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if((internal_flags & IFLAGS_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_IOUDIS;
}
break;
@ -156,7 +149,7 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
return;
}
}
if(soft_switches & SOFTSW_80STORE) {
if(soft_switches & SOFTSW_PAGE_2) {
if((address >= 0x400) && (address < 0x800)) {
@ -179,31 +172,40 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
return;
}
#if 0
// Videx 80 Column Card
if(CARD_SELECT) {
if((address >= 0xC800) && (address < 0xCC00)) {
videx_page[(address & 0x3FF)] = value & 0xff;
}
if(CARD_DEVSEL) {
switch(address & 0x01) {
case 0x0:
videx_crtc_addr(value & 0xff);
break;
case 0x1:
videx_crtc_write(value & 0xff);
break;
if(CARD_SELECT && CARD_DEVSEL) {
cardslot = (address >> 4) & 0x7;
switch(address & 0x0F) {
case 0x01:
if(value & 0x80) {
soft_switches |= SOFTSW_MONOCHROME;
} else {
soft_switches &= ~SOFTSW_MONOCHROME;
}
mono_palette = (value >> 4) & 0x7;
apple_memory[address] = value;
break;
case 0x02:
terminal_tbcolor = value & 0xff;
apple_memory[address] = terminal_tbcolor;
break;
case 0x03:
terminal_border = value & 0x0f;
apple_memory[address] = terminal_border;
break;
case 0x08:
terminal_row = (value < 24) ? value : 23;
apple_memory[address] = terminal_row;
apple_memory[address+2] = terminal_memory[terminal_row*80+terminal_col];
break;
case 0x09:
terminal_col = (value < 80) ? value : 79;
apple_memory[address] = terminal_col;
apple_memory[address+1] = terminal_memory[terminal_row*80+terminal_col];
break;
case 0x0A:
terminal_memory[terminal_row*80+terminal_col] = value;
break;
}
}
#endif
}
#if 0
// Any access to Videx I/O sets the VRAM page visible in 0xCC00-0xD000
if(CARD_SELECT && CARD_DEVSEL) {
videx_page = videx_memory + ((address & 0x0C) << 9);
}
#endif
}

View File

@ -15,6 +15,16 @@ uint16_t text_border;
compat_t machinefont = MACHINE_II;
bool userfont = false;
uint16_t mono_colors[14] = {
_RGB333(0x00, 0x00, 0x00), _RGB333(0xFF, 0xFF, 0xFF), // White Normal
_RGB333(0xFF, 0xFF, 0xFF), _RGB333(0x00, 0x00, 0x00), // White Inverse
_RGB333(0x00, 0x00, 0x00), _RGB333(0xFE, 0x7F, 0x00), // Amber Normal
_RGB333(0xFE, 0x7F, 0x00), _RGB333(0x00, 0x00, 0x00), // Amber Inverse
_RGB333(0x00, 0x00, 0x00), _RGB333(0x00, 0xBF, 0x00), // Green Normal
_RGB333(0x00, 0xBF, 0x00), _RGB333(0x00, 0x00, 0x00), // Green Inverse
_RGB333(0x35, 0x28, 0x79), _RGB333(0x6C, 0x5E, 0xB5), // Commodore
};
// Initialize the character generator ROM
void switch_font() {
switch(current_machine) {
@ -75,7 +85,7 @@ void update_status_right(const char *str) {
for(i = 0; i < len; i++) {
status_line[(80-len) + i] = str[i];
}
status_timeout = 900;
}
@ -109,11 +119,11 @@ void render_init() {
switch_font();
if((soft_switches & SOFTSW_MODE_MASK) == 0)
soft_switches |= SOFTSW_TEST;
internal_flags |= IFLAGS_TEST;
terminal_tbcolor = 0xf0;
terminal_border = 0x00;
memcpy(videx_character_rom, appleiie_character_rom, 2048);
memcpy(terminal_character_rom, appleiie_character_rom, 2048);
memset(status_line, 0, sizeof(status_line));
render_test_init();
@ -140,6 +150,7 @@ uint32_t testdone = 0;
void __noinline __time_critical_func(render_loop)() {
while(current_mode == MODE_VGACARD) {
config_handler();
if((busactive == 0) && (screentimeout > (15 * 60))) {
vga_prepare_frame();
render_border(480);
@ -170,21 +181,27 @@ void __noinline __time_critical_func(render_loop)() {
update_text_flasher();
text_fore = lores_palette[TERMINAL_FORE];
text_back = lores_palette[TERMINAL_BACK];
text_border = lores_palette[TERMINAL_BORDER];
if((soft_switches & SOFTSW_MONOCHROME) && (mono_palette != 0x7)) {
text_fore = mono_colors[mono_palette*2+1];
text_back = mono_colors[mono_palette*2];
text_border = (mono_palette == 0x6) ? text_fore : text_back;
} else {
text_fore = lores_palette[TERMINAL_FORE];
text_back = lores_palette[TERMINAL_BACK];
text_border = lores_palette[TERMINAL_BORDER];
}
if(soft_switches & SOFTSW_TEST) {
if(internal_flags & IFLAGS_TEST) {
render_testpattern();
// Automatically dismiss the test pattern when the Apple II is seen.
if(((soft_switches & SOFTSW_MODE_MASK) != 0) && (testdone == 0)) {
soft_switches &= ~SOFTSW_TEST;
internal_flags &= ~IFLAGS_TEST;
testdone = 1;
render_about_init();
}
#if 0
} else if(soft_switches & SOFTSW_VIDEX) {
render_videx();
} else if(soft_switches & SOFTSW_TERMINAL) {
render_terminal();
} else if(soft_switches & SOFTSW_SHR) {
render_shr();
#endif

View File

@ -26,8 +26,8 @@ extern void render_text40_line(bool p2, unsigned int line);
extern void render_text80_line(bool p2, unsigned int line);
extern void render_status_line();
extern void render_videx();
extern void render_videx_line(unsigned int line);
extern void render_terminal();
extern void render_terminal_line(unsigned int line);
extern void render_border(uint count);
@ -45,9 +45,17 @@ extern void render_mixed_dgr();
extern void render_shr();
extern uint_fast32_t text_flasher_mask;
extern volatile uint_fast32_t text_flasher_mask;
extern void flash_dowork();
extern void vga_init();
extern void vga_deinit();
#define _RGB333(r, g, b) ( \
(((((uint)(r) * 256 / 36) + 128) / 256) << 6) | \
(((((uint)(g) * 256 / 36) + 128) / 256) << 3) | \
((((uint)(b) * 256 / 36) + 128) / 256) \
)

View File

@ -5,7 +5,7 @@
#include "vgaout.h"
static inline uint_fast8_t __time_critical_func(char_terminal_bits)(uint_fast8_t ch, uint_fast8_t glyph_line) {
uint_fast8_t bits = videx_character_rom[((uint_fast16_t)ch << 3) | glyph_line];
uint_fast8_t bits = terminal_character_rom[((uint_fast16_t)ch << 3) | glyph_line];
if(ch & 0x80) {
// normal character
return bits & 0x7f;
@ -21,15 +21,15 @@ static inline uint_fast8_t __time_critical_func(char_terminal_bits)(uint_fast8_t
}
void __time_critical_func(render_videx)() {
void __time_critical_func(render_terminal)() {
for(int line=0; line < 24; line++) {
render_videx_line(line);
render_terminal_line(line);
}
}
void __time_critical_func(render_videx_line)(unsigned int line) {
const uint8_t *page = (const uint8_t *)videx_memory;
void __time_critical_func(render_terminal_line)(unsigned int line) {
const uint8_t *page = (const uint8_t *)terminal_memory;
const uint8_t *line_buf = page + (line * 80);
for(uint glyph_line=0; glyph_line < 8; glyph_line++) {

View File

@ -7,6 +7,7 @@
#define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2)
extern uint16_t lores_palette[16];
extern uint16_t lores_dot_pattern[16];
static void render_dgr_line(bool p2, uint line);
@ -37,7 +38,8 @@ static void __time_critical_func(render_dgr_line)(bool p2, uint line) {
struct vga_scanline *sl1 = vga_prepare_scanline();
struct vga_scanline *sl2 = vga_prepare_scanline();
uint sl_pos = 0;
uint i;
uint i, j;
uint32_t color1, color2, color3, color4;
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));
@ -49,16 +51,41 @@ static void __time_critical_func(render_dgr_line)(bool p2, uint line) {
sl_pos++;
}
for(i=0; i < 40; i++) {
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];
if(soft_switches & SOFTSW_MONOCHROME) {
for(i = 0; i < 40; i++) {
color1 = lores_dot_pattern[line_bufb[i] & 0xf] << 21;
color2 = lores_dot_pattern[(line_bufb[i] >> 4) & 0xf] << 21;
color1 |= lores_dot_pattern[line_bufa[i] & 0xf] << 7;
color2 |= lores_dot_pattern[(line_bufa[i] >> 4) & 0xf] << 7;
// 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);
sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color4|THEN_EXTEND_6) << 16);
sl_pos++;
for(j = 0; j < 7; j++) {
uint32_t pixeldata;
pixeldata = (color1 & 0x8000000) ? (text_fore) : (text_back);
pixeldata |= (color1 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16);
color1 <<= 2;
sl1->data[sl_pos] = pixeldata;
pixeldata = (color2 & 0x8000000) ? (text_fore) : (text_back);
pixeldata |= (color2 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16);
sl2->data[sl_pos] = pixeldata;
color2 <<= 2;
sl_pos++;
}
}
} else {
for(i=0; i < 40; i++) {
color1 = lores_palette[line_bufb[i] & 0xf];
color2 = lores_palette[(line_bufb[i] >> 4) & 0xf];
color3 = lores_palette[line_bufa[i] & 0xf];
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);
sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color4|THEN_EXTEND_6) << 16);
sl_pos++;
}
}
// Pad 40 pixels on the right to center horizontally

View File

@ -7,12 +7,6 @@
static void render_dhgr_line(bool p2, uint line);
#define _RGB333(r, g, b) ( \
(((((uint)(r) * 256 / 36) + 128) / 256) << 6) | \
(((((uint)(g) * 256 / 36) + 128) / 256) << 3) | \
((((uint)(b) * 256 / 36) + 128) / 256) \
)
uint16_t dhgr_palette[16] = {
_RGB333(0x00,0x00,0x00), // black 0000
_RGB333(0x00,0x00,0xb4), // d.blue 1000
@ -31,7 +25,6 @@ uint16_t dhgr_palette[16] = {
_RGB333(0xd8,0xd8,0x00), // yellow 0111
_RGB333(0xff,0xff,0xff), // white 1111
};
#undef _RGB333
//#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2))
#define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2)
@ -95,9 +88,9 @@ static void __time_critical_func(render_dhgr_line)(bool p2, uint line) {
if(soft_switches & SOFTSW_MONOCHROME) {
// Consume 6 pixels (24 subpixel bits)
for(j = 0; j < 12; j++) {
pixeldata = ((dots & 1) ? (0x1ff) : (0x000));
pixeldata = ((dots & 1) ? (text_fore) : (text_back));
dots >>= 1;
pixeldata |= (((dots & 1) ? (0x1ff) : (0x000))) << 16;
pixeldata |= (((dots & 1) ? (text_fore) : (text_back))) << 16;
dots >>= 1;
sl->data[sl_pos++] = pixeldata;
}
@ -124,9 +117,9 @@ static void __time_critical_func(render_dhgr_line)(bool p2, uint line) {
if(soft_switches & SOFTSW_MONOCHROME) {
// Consume 8 pixels (32 subpixel bits)
for(j = 0; j < 16; j++) {
pixeldata = ((dots & 1) ? (0x1ff) : (0x000));
pixeldata = ((dots & 1) ? (text_fore) : (text_back));
dots >>= 1;
pixeldata |= (((dots & 1) ? (0x1ff) : (0x000))) << 16;
pixeldata |= (((dots & 1) ? (text_fore) : (text_back))) << 16;
dots >>= 1;
sl->data[sl_pos++] = pixeldata;
}

View File

@ -85,10 +85,10 @@ static void __time_critical_func(render_hires_line)(bool p2, uint line) {
if(soft_switches & SOFTSW_MONOCHROME) {
// Consume 14 dots
for(j = 0; j < 7; j++) {
uint32_t pixeldata = (dots & 0x80000000) ? (0x1ff) : (0x000);
pixeldata |= (dots & 0x40000000) ?
((uint32_t)0x1ff) << 16 :
((uint32_t)0x000) << 16;
uint32_t pixeldata = (dots & 0x40000000) ? (text_fore) : (text_back);
pixeldata |= (dots & 0x20000000) ?
((text_fore) << 16) :
((text_back) << 16);
dots <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;

View File

@ -3,12 +3,24 @@
#include "render.h"
#include "vgaout.h"
#define _RGB333(r, g, b) ( \
(((((uint)(r) * 256 / 36) + 128) / 256) << 6) | \
(((((uint)(g) * 256 / 36) + 128) / 256) << 3) | \
((((uint)(b) * 256 / 36) + 128) / 256) \
)
uint16_t lores_dot_pattern[16] = {
0x0000,
0x2222,
0x1111,
0x3333,
0x0888,
0x2AAA,
0x1999,
0x3BBB,
0x0444,
0x2666,
0x1555,
0x3777,
0x0CCC,
0x2EEE,
0x1DDD,
0x3FFF,
};
uint16_t lores_palette[16] = {
_RGB333(0x00,0x00,0x00), // black
@ -28,7 +40,6 @@ uint16_t lores_palette[16] = {
_RGB333(0x90,0xfc,0xb4), // aqua
_RGB333(0xff,0xff,0xff), // white
};
#undef _RGB333
static void render_lores_line(bool p2, uint line);
@ -63,7 +74,8 @@ static void __time_critical_func(render_lores_line)(bool p2, uint line) {
struct vga_scanline *sl1 = vga_prepare_scanline();
struct vga_scanline *sl2 = vga_prepare_scanline();
uint sl_pos = 0;
uint i;
uint i, j;
uint32_t color1, color2;
const uint8_t *line_buf = (const uint8_t *)((p2 ? text_p2 : text_p1) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
@ -74,20 +86,39 @@ static void __time_critical_func(render_lores_line)(bool p2, uint line) {
sl_pos++;
}
for(i=0; i < 40; i+=2) {
uint32_t color1 = lores_palette[line_buf[i] & 0xf];
uint32_t color2 = lores_palette[(line_buf[i] >> 4) & 0xf];
uint32_t color3 = lores_palette[line_buf[i+1] & 0xf];
uint32_t color4 = lores_palette[(line_buf[i+1] >> 4) & 0xf];
if(soft_switches & SOFTSW_MONOCHROME) {
for(i = 0; i < 40; i+=2) {
color1 = lores_dot_pattern[line_buf[i] & 0xf] << 14;
color2 = lores_dot_pattern[(line_buf[i] >> 4) & 0xf] << 14;
color1 |= lores_dot_pattern[line_buf[i+1] & 0xf];
color2 |= lores_dot_pattern[(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) | ((color1|THEN_EXTEND_6) << 16);
sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color2|THEN_EXTEND_6) << 16);
sl_pos++;
for(j = 0; j < 14; j++) {
uint32_t pixeldata;
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++;
pixeldata = (color1 & 0x8000000) ? (text_fore) : (text_back);
pixeldata |= (color1 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16);
color1 <<= 2;
sl1->data[sl_pos] = pixeldata;
pixeldata = (color2 & 0x8000000) ? (text_fore) : (text_back);
pixeldata |= (color2 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16);
sl2->data[sl_pos] = pixeldata;
color2 <<= 2;
sl_pos++;
}
}
} else {
for(i = 0; i < 40; i++) {
color1 = lores_palette[line_buf[i] & 0xf];
color2 = lores_palette[(line_buf[i] >> 4) & 0xf];
// Each lores pixel is 7 hires pixels, or 14 VGA pixels wide
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++;
}
}
for(i = 0; i < 40/8; i++) {

View File

@ -16,8 +16,8 @@ char error_message[32*24+1];
void render_test_init() {
memset(error_message, ' ', 32*24);
memcpy(error_message + 0, "HW: Analog-Rev-1 ", 32);
memcpy(error_message + 32, "FW: 23-01-29-145 ", 32);
memcpy(error_message + 0, "HARDWARE: V2 Analog Rev1", 32);
memcpy(error_message + 32, "FIRMWARE: 1 Mar 2023 Build 0159", 32);
memcpy(error_message + 128, " Copyright (C) 2022-2023 ", 32);
memcpy(error_message + 160, " David Kuder ", 32);
@ -30,16 +30,12 @@ void render_test_init() {
memcpy(error_message + 544, " Turn off power & check ", 32);
memcpy(error_message + 576, " for proper card insertion. ", 32);
#ifdef RASPBERRYPI_PICO_W
memcpy(error_message + 704, " serial number: ", 32);
// Get Pico's Flash Serial Number (Board ID) and terminating null.
memcpy(error_message + 736, " ", 8);
pico_get_unique_board_id_string(error_message + 744, 17);
memcpy(error_message + 760, " ", 8);
#else
memcpy(error_message + 736, " V2-Analog-LC ", 32);
#endif
}
// Clear the error message, in case the user sets 0x20 in terminal switches
@ -50,7 +46,7 @@ void render_about_init() {
}
static inline uint_fast8_t __time_critical_func(char_test_bits)(uint_fast8_t ch, uint_fast8_t glyph_line) {
uint_fast8_t bits = videx_character_rom[((uint_fast16_t)(ch & 0x7f) << 3) | glyph_line | 0x400];
uint_fast8_t bits = terminal_character_rom[((uint_fast16_t)(ch & 0x7f) << 3) | glyph_line | 0x400];
return bits & 0x7f;
}

View File

@ -8,7 +8,7 @@
//#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2))
#define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2)
uint_fast32_t text_flasher_mask = 0;
volatile uint_fast32_t text_flasher_mask = 0;
static uint64_t next_flash_tick = 0;
void update_text_flasher() {
@ -32,20 +32,20 @@ void update_text_flasher() {
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] & 0x7f;
uint_fast8_t bits, invert;
if((soft_switches & SOFTSW_ALTCHAR) || (ch & 0x80)) {
// normal character
return bits;
// normal / mousetext character
invert = 0x00;
} else {
// flashing character or inverse character
invert = (ch & 0x40) ? text_flasher_mask : 0x7f;
ch = (ch & 0x3f) | 0x80;
}
if(ch & 0x40) {
// flashing character
return (bits ^ text_flasher_mask);
}
bits = character_rom[((uint_fast16_t)ch << 3) | glyph_line] & 0x7f;
// inverse character
return bits;
return bits ^ invert;
}
void __time_critical_func(render_text)() {

View File

@ -1,13 +1,10 @@
#include "vgabuf.h"
// Shadow copy of the Apple soft-switches
volatile uint32_t soft_switches = 0;
volatile uint32_t mono_palette = 0;
// The currently programmed character generator ROM for text mode
uint8_t character_rom[2048];
uint8_t videx_character_rom[2048];
uint8_t terminal_character_rom[2048];
volatile uint8_t videx_crtc_reg;
volatile uint8_t terminal_switches;
volatile uint8_t terminal_row = 0;
volatile uint8_t terminal_col = 0;

View File

@ -5,13 +5,14 @@
#define text_memory text_p1
#define hires_memory hgr_p1
#define videx_memory (private_memory+0xF000)
#define terminal_memory (private_memory+0xF000)
extern uint8_t character_rom[2048];
extern uint8_t videx_character_rom[2048];
extern uint8_t terminal_character_rom[2048];
extern volatile uint8_t videx_crtc_reg;
extern volatile uint8_t videx_addr;
extern volatile uint32_t mono_palette;
extern volatile uint8_t terminal_row;
extern volatile uint8_t terminal_col;
#define terminal_tbcolor apple_memory[0xC022]
#define terminal_border apple_memory[0xC034]

View File

@ -11,5 +11,5 @@ void __noinline __time_critical_func(vgamain)() {
vga_init();
render_init();
render_loop();
// vga_deinit();
vga_stop();
}

View File

@ -22,6 +22,8 @@
#define NUM_SCANLINE_BUFFERS 32
static bool vga_initialized = 0;
enum {
VGA_HSYNC_SM = 0,
VGA_VSYNC_SM = 1,
@ -158,29 +160,37 @@ static void vga_dma_irq_handler() {
void vga_init() {
spin_lock_claim(CONFIG_VGA_SPINLOCK_ID);
spin_lock_init(CONFIG_VGA_SPINLOCK_ID);
if(!vga_initialized) {
spin_lock_claim(CONFIG_VGA_SPINLOCK_ID);
spin_lock_init(CONFIG_VGA_SPINLOCK_ID);
// Setup the PIO state machines
vga_hsync_setup(CONFIG_VGA_PIO, VGA_HSYNC_SM);
vga_vsync_setup(CONFIG_VGA_PIO, VGA_VSYNC_SM);
vga_data_setup(CONFIG_VGA_PIO, VGA_DATA_SM);
// Setup the PIO state machines
vga_hsync_setup(CONFIG_VGA_PIO, VGA_HSYNC_SM);
vga_vsync_setup(CONFIG_VGA_PIO, VGA_VSYNC_SM);
vga_data_setup(CONFIG_VGA_PIO, VGA_DATA_SM);
// Setup the DMA channel for writing to the data PIO state machine
vga_dma_channel = dma_claim_unused_channel(true);
dma_channel_config c = dma_channel_get_default_config(vga_dma_channel);
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_dreq(&c, pio_get_dreq(CONFIG_VGA_PIO, VGA_DATA_SM, true));
dma_channel_configure(vga_dma_channel, &c, &CONFIG_VGA_PIO->txf[VGA_DATA_SM], NULL, 0, false);
// Setup the DMA channel for writing to the data PIO state machine
vga_dma_channel = dma_claim_unused_channel(true);
dma_channel_config c = dma_channel_get_default_config(vga_dma_channel);
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_dreq(&c, pio_get_dreq(CONFIG_VGA_PIO, VGA_DATA_SM, true));
dma_channel_configure(vga_dma_channel, &c, &CONFIG_VGA_PIO->txf[VGA_DATA_SM], NULL, 0, false);
dma_channel_set_irq0_enabled(vga_dma_channel, true);
irq_set_exclusive_handler(DMA_IRQ_0, vga_dma_irq_handler);
irq_set_enabled(DMA_IRQ_0, true);
dma_channel_set_irq0_enabled(vga_dma_channel, true);
irq_set_exclusive_handler(DMA_IRQ_0, vga_dma_irq_handler);
irq_set_enabled(DMA_IRQ_0, true);
vga_initialized = 1;
}
// Enable all state machines in sync to ensure their instruction cycles line up
pio_enable_sm_mask_in_sync(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM));
}
void vga_stop() {
pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false);
}
void vga_dpms_sleep() {
pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false);
}
@ -188,34 +198,6 @@ void vga_dpms_sleep() {
void vga_dpms_wake() {
pio_enable_sm_mask_in_sync(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM));
}
void vga_deinit() {
// Disable DMA IRQ
irq_set_enabled(DMA_IRQ_0, false);
dma_channel_set_irq0_enabled(vga_dma_channel, false);
dma_channel_abort(vga_dma_channel);
// Release DMA channel
dma_channel_unclaim(vga_dma_channel);
// Disable VGA state machines
pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false);
// Clear PIO memory
pio_clear_instruction_memory(CONFIG_VGA_PIO);
// Release state machines
pio_sm_unclaim(CONFIG_VGA_PIO, VGA_HSYNC_SM);
pio_sm_unclaim(CONFIG_VGA_PIO, VGA_VSYNC_SM);
pio_sm_unclaim(CONFIG_VGA_PIO, VGA_DATA_SM);
// Release Spin Lock
spin_lock_unclaim(CONFIG_VGA_SPINLOCK_ID);
// Reset the PIO0 block
reset_block((1 << 10));
unreset_block((1 << 10));
}
// Set up for a new display frame
void vga_prepare_frame() {

View File

@ -35,6 +35,6 @@ void vga_prepare_frame();
struct vga_scanline *vga_prepare_scanline();
void vga_submit_scanline(struct vga_scanline *scanline);
void vga_stop();
void vga_dpms_sleep();
void vga_dpms_wake();

View File

@ -46,10 +46,13 @@ static inline void __time_critical_func(pcpi_write)(uint32_t address, uint32_t v
}
void __time_critical_func(z80_businterface)(uint32_t address, uint32_t value) {
pcpi_reg = apple_memory + (0xC080 | (cardslot << 4));
// Reset the Z80 when the Apple II resets
if(reset_state == 3) z80_res = 1;
// Shadow parts of the Apple's memory by observing the bus write cycles
if(CARD_SELECT) {
if(CARD_DEVSEL) {
pcpi_reg = apple_memory + (address & 0xFFF0);
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) {
pcpi_write(address, value);
} else {

View File

@ -88,7 +88,9 @@ void z80main() {
z80_res = 1;
while(current_mode == MODE_APPLICARD) {
config_handler();
if(config_cmdbuf[7] == 0) {
config_handler();
} else
if(cardslot != 0) {
if(z80_res) {
rom_shadow = 1;