#include "zx_mem.h" #include "stdlib.h" #include "z80.h" #include "zx_screen.h" #define ZX_128MEM_PAGE 0x07 #define ZX_128MEM_SCREEN 0x08 #define ZX_128MEM_ROM 0x10 #define ZX_128MEM_DISPAG 0x20 #define ZX_2A_3_PAGING_MODE 0x01 #define ZX_2A_3_HROM 0x04 #define ZX_2A_3_SPECIAL 0x06 namespace mem { uint8_t mode = ZX_48K; uint32_t ram_size = 48*1024; uint32_t rom_size = 16*1024; uint8_t *ram = nullptr; uint8_t *rom = nullptr; uint8_t *slot[8]; bool writable[8]; uint8_t config_128K = 0; uint8_t config_2A_3 = 0; void zx_128_port_out(int port, int val); void zx_2A_3_port_out(int port, int val); void init(uint8_t mode) { mem::mode = mode; reset(); } void reset() { if (ram) free(ram); if (rom) free(rom); FILE* f; switch(mode) { case ZX_48K: ram_size = 48*1024; ram = (uint8_t*)malloc(ram_size); for (int i=0; i> 13; const uint16_t displacement = address & 0x1fff; return slot[slot_num][displacement]; } void writeMem(uint16_t address, uint8_t value) { const uint8_t slot_num = address >> 13; if (!writable[slot_num]) return; const uint16_t displacement = address & 0x1fff; slot[slot_num][displacement] = value; } void loadMem(uint16_t address, uint16_t len, uint8_t *buffer) { } uint8_t getTag(uint16_t address) { return 0; } void setTag(uint16_t address, uint8_t value) { } void saveState(FILE* f) { fwrite(ram, 0xc000, 1, f); } void loadState(FILE* f) { fread(ram, 0xc000, 1, f); } uint32_t getSize() { return 0; } uint8_t *rawPtr(uint32_t address) { return &ram[address]; } uint8_t *rawTagPtr(uint32_t address) { return nullptr; } void zx_128_port_out(int port, int val) { if (port != 0x7ffd) return; if (config_128K & ZX_128MEM_DISPAG) return; const bool shadow = config_128K & ZX_128MEM_SCREEN; config_128K = val; if (config_2A_3 & ZX_2A_3_PAGING_MODE) return; if (config_128K & ZX_128MEM_SCREEN) { if (!shadow) zxscreen::setBaseAddresses(0x4000*7, 0x1800+0x4000*7); } else { if (shadow) zxscreen::setBaseAddresses(0x4000*5, 0x1800+0x4000*5); } uint8_t hrom = (config_2A_3 & ZX_2A_3_HROM) ? 4 : 0; if (config_128K & ZX_128MEM_ROM) { slot[0] = &rom[(hrom+2)*8192]; slot[1] = &rom[(hrom+3)*8192]; } else { slot[0] = &rom[(hrom+0)*8192]; slot[1] = &rom[(hrom+1)*8192]; } const uint8_t slot3 = (config_128K&ZX_128MEM_PAGE)*2; slot[6] = &ram[slot3*8192]; slot[7] = &ram[(slot3+1)*8192]; } void zx_2A_3_port_out(int port, int val) { if (port != 0x1ffd) return; if (config_128K & ZX_128MEM_DISPAG) return; config_2A_3 = val; if (config_2A_3 & ZX_2A_3_PAGING_MODE) { for (int i=0;i<8;++i) writable[i] = true; switch ((config_2A_3 & ZX_2A_3_SPECIAL)>>1) { case 0: slot[0] = &ram[0*8192]; slot[1] = &ram[1*8192]; slot[2] = &ram[2*8192]; slot[3] = &ram[3*8192]; slot[4] = &ram[4*8192]; slot[5] = &ram[5*8192]; slot[6] = &ram[6*8192]; slot[7] = &ram[7*8192]; break; case 1: slot[0] = &ram[8*8192]; slot[1] = &ram[9*8192]; slot[2] = &ram[10*8192]; slot[3] = &ram[11*8192]; slot[4] = &ram[12*8192]; slot[5] = &ram[13*8192]; slot[6] = &ram[14*8192]; slot[7] = &ram[15*8192]; break; case 2: slot[0] = &ram[8*8192]; slot[1] = &ram[9*8192]; slot[2] = &ram[10*8192]; slot[3] = &ram[11*8192]; slot[4] = &ram[12*8192]; slot[5] = &ram[13*8192]; slot[6] = &ram[6*8192]; slot[7] = &ram[7*8192]; break; case 3: slot[0] = &ram[8*8192]; slot[1] = &ram[9*8192]; slot[2] = &ram[14*8192]; slot[3] = &ram[15*8192]; slot[4] = &ram[12*8192]; slot[5] = &ram[13*8192]; slot[6] = &ram[6*8192]; slot[7] = &ram[7*8192]; break; } } else { writable[0] = writable[1] = false; for (int i=2;i<8;++i) writable[i] = true; uint8_t hrom = (config_2A_3 & ZX_2A_3_HROM) ? 4 : 0; if (config_128K & ZX_128MEM_ROM) { slot[0] = &rom[(hrom+2)*8192]; slot[1] = &rom[(hrom+3)*8192]; } else { slot[0] = &rom[(hrom+0)*8192]; slot[1] = &rom[(hrom+1)*8192]; } } } }