#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 rom { const char *data; size_t len; const char *name; }; struct abc_mem_init { int addr; uint32_t flags; enum sysvar_enum enable; struct rom r; }; /* Convenience aliases */ #define MAPS ABCMEMMAP_MAPS #define PAGE_SHIFT ABCMEMMAP_PAGE_SHIFT #define PAGE_SIZE ABCMEMMAP_PAGE_SIZE #define PAGE_MASK ABCMEMMAP_PAGE_MASK #define PAGE_COUNT ABCMEMMAP_PAGE_COUNT #define PERMAP (PAGE_COUNT / MAPS) #define RD ABCMEMMAP_RD #define WR ABCMEMMAP_WR #define XM ABCMEMMAP_XM #define K 1024 #define R(x) { (x), sizeof(x), #x } #define END { -1, 0, sysvar_null, { NULL, 0, NULL } } /* ---- ABC80 memory configurations ---- */ /* Not really NV, but matches NVRAM in some expansions */ static char __dram_bss __aligned(PAGE_SIZE) abc80_nvram[2][2*K]; /* 16K external memory to expand to 512K */ static char __dram_bss __aligned(PAGE_SIZE) 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, R(abc80_nvram[0]) }, { 22*K, RD|WR, config_abc_mem_abc80_nvram_22k, R(abc80_nvram[1]) }, { 16*K, RD, config_abc_mem_abc80_smartaid3, R(rom_abc80_smartaid3) }, { 16*K, RD, config_abc_mem_abc80_superbasic, R(rom_abc80_superbasic16k) }, { 20*K, RD, config_abc_mem_abc80_abc80l, R(rom_abc80_abc80l) }, { 28*K, RD, config_abc_mem_abc80_superbasic, R(rom_abc80_superbasic28k) }, { 32*K, RD|WR, config_abc_mem_abc80_ram, R(abc80_extmem) }, END }; static const struct abc_mem_init mem_init_abc80_nvram_20k[] = { { 24*K, RD, config_abc_mem_abc80_ufddos, R(rom_abc80_nvram_20k_ufddos80) }, { 28*K, RD, config_abc_mem_abc80_pun80_28k, R(rom_abc80_nvram_20k_print80_28) }, { 29*K, RD, config_abc_mem_abc80_pun80_29k, R(rom_abc80_nvram_20k_print80_29) }, { 30*K, RD, config_abc_mem_abc80_pun80_30k, R(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, R(rom_abc80_nvram_22k_ufddos80) }, { 28*K, RD, config_abc_mem_abc80_pun80_28k, R(rom_abc80_nvram_22k_print80_28) }, { 29*K, RD, config_abc_mem_abc80_pun80_29k, R(rom_abc80_nvram_22k_print80_29) }, { 30*K, RD, config_abc_mem_abc80_pun80_30k, R(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, R(rom_abc80_no_nvram_ufddos80) }, { 28*K, RD, config_abc_mem_abc80_pun80_28k, R(rom_abc80_no_nvram_print80_28) }, { 29*K, RD, config_abc_mem_abc80_pun80_29k, R(rom_abc80_no_nvram_print80_29) }, { 30*K, RD, config_abc_mem_abc80_pun80_30k, R(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, R(rom_abc800_ufddos) }, END }; 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->r.data; size_t len = mem->r.len; if (!len) continue; /* Empty range, skip */ uint32_t addr = mem->addr; bool bad = ((addr | len) & ~PAGE_MASK) || (len > 0x10000 - addr) || ((size_t)data & (PAGE_SIZE-1)); con_printf("abcmem: %s %s @ 0x%04x len 0x%04x\n", mem->r.name ? mem->r.name : "(none)", bad ? "invalid" : !enabled ? "disabled" : data ? "mapping" : "unmapping", addr, len); if (enabled) { uint32_t *pg = &memmap[addr >> PAGE_SHIFT]; uint32_t flags = mem->flags; if (data) { /* Mapped range */ size_t pgv = (size_t)data | flags; for (uint32_t bytes = 0; bytes < len; bytes += PAGE_SIZE) *pg++ = pgv + bytes; } else { /* Unmapped range - set to 0 for clarity */ memset(pg, 0, len >> (PAGE_SHIFT-2)); } } mem++; } } void __cold abc_init_memmap(void) { static uint32_t memmap[MAPS][PERMAP]; /* Too big to fit on stack */ const struct abc_mem_init *mem; memset(memmap, 0, sizeof memmap); /* * Currently the only map that gets populated is map 0; the * remaining map(s) get cleared by the memset() above. */ if (is_abc800()) { abc_map_list(memmap[0], 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[0], mem_init_abc80_nvram_22k); else if (getvar_bool(config_abc_mem_abc80_nvram_20k)) abc_map_list(memmap[0], mem_init_abc80_nvram_20k); else abc_map_list(memmap[0], mem_init_abc80_no_nvram); abc_map_list(memmap[0], mem_init_abc80); } /* Install memory map into hardware registers */ memcpy((void *)&ABCMEMMAP_PAGE(0), memmap, sizeof memmap); }