#include "common.h" #include "io.h" #include "abcio.h" #include "sys.h" #include "console.h" #include "config.h" #include "roms.h" /* Configure ABC memory map */ struct data_len { const char *data; size_t len; }; struct abc_mem_init { int addr; uint32_t flags; enum sysvar_enum enable; struct data_len dl; }; #define RD ABCMEMMAP_RD #define WR ABCMEMMAP_WR #define K 1024 #define DD(x) { (x), sizeof(x) } #define END { -1, 0, sysvar_null, { NULL, 0 } } /* ---- ABC80 memory configurations ---- */ /* Not really NV, but matches NVRAM in some expansions */ static char __dram_bss __aligned(512) abc80_nvram[2][2*K]; /* 16K external memory to expand to 512K */ static char __dram_bss __aligned(512) abc80_extmem[16*K]; static const struct abc_mem_init mem_init_abc80[] = { /* Put these here in case someone wants to enable both */ { 20*K, RD|WR, config_abc_mem_abc80_nvram_20k, DD(abc80_nvram[0]) }, { 22*K, RD|WR, config_abc_mem_abc80_nvram_22k, DD(abc80_nvram[1]) }, { 16*K, RD, config_abc_mem_abc80_smartaid3, DD(rom_abc80_smartaid3) }, { 16*K, RD, config_abc_mem_abc80_superbasic, DD(rom_abc80_superbasic16k) }, { 28*K, RD, config_abc_mem_abc80_superbasic, DD(rom_abc80_superbasic28k) }, { 32*K, RD|WR, config_abc_mem_abc80_ram, DD(abc80_extmem) }, END }; static const struct abc_mem_init mem_init_abc80_nvram_20k[] = { { 24*K, RD, config_abc_mem_abc80_ufddos, DD(rom_abc80_nvram_20k_ufddos80) }, { 28*K, RD, config_abc_mem_abc80_pun80_28k, DD(rom_abc80_nvram_20k_print80_28) }, { 29*K, RD, config_abc_mem_abc80_pun80_29k, DD(rom_abc80_nvram_20k_print80_29) }, { 30*K, RD, config_abc_mem_abc80_pun80_30k, DD(rom_abc80_nvram_20k_print80_30) }, END }; static const struct abc_mem_init mem_init_abc80_nvram_22k[] = { { 24*K, RD, config_abc_mem_abc80_ufddos, DD(rom_abc80_nvram_22k_ufddos80) }, { 28*K, RD, config_abc_mem_abc80_pun80_28k, DD(rom_abc80_nvram_22k_print80_28) }, { 29*K, RD, config_abc_mem_abc80_pun80_29k, DD(rom_abc80_nvram_22k_print80_29) }, { 30*K, RD, config_abc_mem_abc80_pun80_30k, DD(rom_abc80_nvram_22k_print80_30) }, END }; static const struct abc_mem_init mem_init_abc80_no_nvram[] = { { 24*K, RD, config_abc_mem_abc80_ufddos, DD(rom_abc80_no_nvram_ufddos80) }, { 28*K, RD, config_abc_mem_abc80_pun80_28k, DD(rom_abc80_no_nvram_print80_28) }, { 29*K, RD, config_abc_mem_abc80_pun80_29k, DD(rom_abc80_no_nvram_print80_29) }, { 30*K, RD, config_abc_mem_abc80_pun80_30k, DD(rom_abc80_no_nvram_print80_30) }, END }; /* ---- ABC800 memory configurations ---- */ static const struct abc_mem_init mem_init_abc800[] = { { 24*K, RD, config_abc_mem_abc800_ufddos, DD(rom_abc800_ufddos) }, END }; #define ABC_PAGE_SHIFT 9 #define ABC_PAGE_SIZE (1U << ABC_PAGE_SHIFT) #define ABC_PAGE_MASK (0xffff & ~(ABC_PAGE_SIZE-1)) #define ABC_PAGE_COUNT (0x10000 >> ABC_PAGE_SHIFT) static void abc_map_list(uint32_t *memmap, const struct abc_mem_init *mem) { while (mem->addr >= 0) { bool enabled = !mem->enable || getvar_bool(mem->enable); const void *data = mem->dl.data; size_t len = mem->dl.len; if (!len) continue; /* Empty range, skip */ uint32_t addr = mem->addr; bool bad = ((addr | len) & ~ABC_PAGE_MASK) || len > 0x10000 - addr || (size_t)data & (ABC_PAGE_SIZE-1); con_printf("abcmem: %s memory range @ 0x%04x len 0x%04x\n", bad ? "invalid" : !enabled ? "ignoring" : data ? "mapping" : "unmapping", addr, len); if (enabled) { uint32_t *pg = &memmap[addr >> ABC_PAGE_SHIFT]; uint32_t flags = mem->flags; if (!data) { /* Mapped range */ for (uint32_t bytes = 0; bytes < len; bytes += ABC_PAGE_SIZE) *pg++ = ((size_t)(data + bytes) & SDRAM_MASK) | flags; } else { /* Unmapped range - set to 0 for clarity */ memset(pg, 0, len >> (ABC_PAGE_SHIFT-2)); } } mem++; } } void __cold abc_init_memmap(void) { uint32_t *memmap = calloc(sizeof(uint32_t), ABC_PAGE_COUNT); const struct abc_mem_init *mem; if (!memmap) { con_printf("abcmem: memory map initialization failure\n"); return; } if (is_abc800()) { abc_map_list(memmap, mem_init_abc800); } else { /* Put 22K first so UFD-DOS/PUN80 memory always is put at the end */ if (getvar_bool(config_abc_mem_abc80_nvram_22k)) abc_map_list(memmap, mem_init_abc80_nvram_22k); else if (getvar_bool(config_abc_mem_abc80_nvram_20k)) abc_map_list(memmap, mem_init_abc80_nvram_20k); else abc_map_list(memmap, mem_init_abc80_no_nvram); abc_map_list(memmap, mem_init_abc80); } /* Install memory map into hardware registers */ memcpy((void *)&ABCMEMMAP_PAGE(0), memmap, ABC_PAGE_COUNT*sizeof(uint32_t)); free(memmap); }