OSDN Git Service

[VM][STATE][WIP] Apply process_state() to some devices.
[csp-qt/common_source_project-fm7.git] / source / src / vm / memory.cpp
index dc026d1..d01e1a8 100644 (file)
-/*\r
-       Skelton for retropc emulator\r
-\r
-       Author : Takeda.Toshiya\r
-       Date   : 2010.09.16-\r
-\r
-       [ memory ]\r
-*/\r
-\r
-#include "memory.h"\r
-#include "../fileio.h"\r
-\r
-#define ADDR_MASK (MEMORY_ADDR_MAX - 1)\r
-#define BANK_MASK (MEMORY_BANK_SIZE - 1)\r
-\r
-void MEMORY::release()\r
-{\r
-       free(read_table);\r
-       free(write_table);\r
-}\r
-\r
-uint32 MEMORY::read_data8(uint32 addr)\r
-{\r
-       int bank = (addr & ADDR_MASK) >> addr_shift;\r
-       \r
-       if(read_table[bank].dev != NULL) {\r
-               return read_table[bank].dev->read_memory_mapped_io8(addr);\r
-       } else {\r
-               return read_table[bank].memory[addr & BANK_MASK];\r
-       }\r
-}\r
-\r
-void MEMORY::write_data8(uint32 addr, uint32 data)\r
-{\r
-       int bank = (addr & ADDR_MASK) >> addr_shift;\r
-       \r
-       if(write_table[bank].dev != NULL) {\r
-               write_table[bank].dev->write_memory_mapped_io8(addr, data);\r
-       } else {\r
-               write_table[bank].memory[addr & BANK_MASK] = data;\r
-       }\r
-}\r
-\r
-uint32 MEMORY::read_data16(uint32 addr)\r
-{\r
-       int bank = (addr & ADDR_MASK) >> addr_shift;\r
-       \r
-       if(read_table[bank].dev != NULL) {\r
-               return read_table[bank].dev->read_memory_mapped_io16(addr);\r
-       } else {\r
-               uint32 val = read_data8(addr);\r
-               val |= read_data8(addr + 1) << 8;\r
-               return val;\r
-       }\r
-}\r
-\r
-void MEMORY::write_data16(uint32 addr, uint32 data)\r
-{\r
-       int bank = (addr & ADDR_MASK) >> addr_shift;\r
-       \r
-       if(write_table[bank].dev != NULL) {\r
-               write_table[bank].dev->write_memory_mapped_io16(addr, data);\r
-       } else {\r
-               write_data8(addr, data & 0xff);\r
-               write_data8(addr + 1, (data >> 8) & 0xff);\r
-       }\r
-}\r
-\r
-uint32 MEMORY::read_data32(uint32 addr)\r
-{\r
-       int bank = (addr & ADDR_MASK) >> addr_shift;\r
-       \r
-       if(read_table[bank].dev != NULL) {\r
-               return read_table[bank].dev->read_memory_mapped_io32(addr);\r
-       } else {\r
-               uint32 val = read_data16(addr);\r
-               val |= read_data16(addr + 2) << 16;\r
-               return val;\r
-       }\r
-}\r
-\r
-void MEMORY::write_data32(uint32 addr, uint32 data)\r
-{\r
-       int bank = (addr & ADDR_MASK) >> addr_shift;\r
-       \r
-       if(write_table[bank].dev != NULL) {\r
-               write_table[bank].dev->write_memory_mapped_io32(addr, data);\r
-       } else {\r
-               write_data16(addr, data & 0xffff);\r
-               write_data16(addr + 2, (data >> 16) & 0xffff);\r
-       }\r
-}\r
-\r
-// register\r
-\r
-void MEMORY::set_memory_r(uint32 start, uint32 end, uint8 *memory)\r
-{\r
-       uint32 start_bank = start >> addr_shift;\r
-       uint32 end_bank = end >> addr_shift;\r
-       \r
-       for(uint32 i = start_bank; i <= end_bank; i++) {\r
-               read_table[i].dev = NULL;\r
-               read_table[i].memory = memory + MEMORY_BANK_SIZE * (i - start_bank);\r
-       }\r
-}\r
-\r
-void MEMORY::set_memory_w(uint32 start, uint32 end, uint8 *memory)\r
-{\r
-       uint32 start_bank = start >> addr_shift;\r
-       uint32 end_bank = end >> addr_shift;\r
-       \r
-       for(uint32 i = start_bank; i <= end_bank; i++) {\r
-               write_table[i].dev = NULL;\r
-               write_table[i].memory = memory + MEMORY_BANK_SIZE * (i - start_bank);\r
-       }\r
-}\r
-\r
-void MEMORY::set_memory_mapped_io_r(uint32 start, uint32 end, DEVICE *device)\r
-{\r
-       uint32 start_bank = start >> addr_shift;\r
-       uint32 end_bank = end >> addr_shift;\r
-       \r
-       for(uint32 i = start_bank; i <= end_bank; i++) {\r
-               read_table[i].dev = device;\r
-       }\r
-}\r
-\r
-void MEMORY::set_memory_mapped_io_w(uint32 start, uint32 end, DEVICE *device)\r
-{\r
-       uint32 start_bank = start >> addr_shift;\r
-       uint32 end_bank = end >> addr_shift;\r
-       \r
-       for(uint32 i = start_bank; i <= end_bank; i++) {\r
-               write_table[i].dev = device;\r
-       }\r
-}\r
-\r
-void MEMORY::unset_memory_r(uint32 start, uint32 end)\r
-{\r
-       uint32 start_bank = start >> addr_shift;\r
-       uint32 end_bank = end >> addr_shift;\r
-       \r
-       for(uint32 i = start_bank; i <= end_bank; i++) {\r
-               read_table[i].dev = NULL;\r
-               read_table[i].memory = read_dummy;\r
-       }\r
-}\r
-\r
-void MEMORY::unset_memory_w(uint32 start, uint32 end)\r
-{\r
-       uint32 start_bank = start >> addr_shift;\r
-       uint32 end_bank = end >> addr_shift;\r
-       \r
-       for(uint32 i = start_bank; i <= end_bank; i++) {\r
-               write_table[i].dev = NULL;\r
-               write_table[i].memory = write_dummy;\r
-       }\r
-}\r
-\r
-// load/save image\r
-\r
-int MEMORY::read_bios(_TCHAR *file_name, uint8 *buffer, int size)\r
-{\r
-       FILEIO* fio = new FILEIO();\r
-       int length = 0;\r
-       \r
-       if(fio->Fopen(emu->bios_path(file_name), FILEIO_READ_BINARY)) {\r
-               fio->Fread(buffer, size, 1);\r
-               length = fio->Ftell();\r
-               fio->Fclose();\r
-       }\r
-       delete fio;\r
-       return length;\r
-}\r
-\r
-bool MEMORY::write_bios(_TCHAR *file_name, uint8 *buffer, int size)\r
-{\r
-       FILEIO* fio = new FILEIO();\r
-       bool result = false;\r
-       \r
-       if(fio->Fopen(emu->bios_path(file_name), FILEIO_WRITE_BINARY)) {\r
-               fio->Fwrite(buffer, size, 1);\r
-               fio->Fclose();\r
-               result = true;\r
-       }\r
-       delete fio;\r
-       return result;\r
-}\r
-\r
-bool MEMORY::read_image(_TCHAR *file_path, uint8 *buffer, int size)\r
-{\r
-       FILEIO* fio = new FILEIO();\r
-       bool result = false;\r
-       \r
-       if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {\r
-               fio->Fread(buffer, size, 1);\r
-               fio->Fclose();\r
-               result = true;\r
-       }\r
-       delete fio;\r
-       return result;\r
-}\r
-\r
-bool MEMORY::write_image(_TCHAR* file_path, uint8* buffer, int size)\r
-{\r
-       FILEIO* fio = new FILEIO();\r
-       bool result = false;\r
-       \r
-       if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {\r
-               fio->Fwrite(buffer, size, 1);\r
-               fio->Fclose();\r
-               result = true;\r
-       }\r
-       delete fio;\r
-       return result;\r
-}\r
+/*
+       Skelton for retropc emulator
+
+       Author : Takeda.Toshiya
+       Date   : 2010.09.16-
+
+       [ memory ]
+*/
+
+#include "memory.h"
+
+#define ADDR_MASK (addr_max - 1)
+#define BANK_MASK (bank_size - 1)
+
+void MEMORY::initialize()
+{
+       // allocate tables here to support multiple instances with different address range
+       if(rd_table == NULL) {
+               int bank_num = addr_max / bank_size;
+               
+               rd_dummy = (uint8_t *)malloc(bank_size);
+               wr_dummy = (uint8_t *)malloc(bank_size);
+               
+               rd_table = (bank_t *)calloc(bank_num, sizeof(bank_t));
+               wr_table = (bank_t *)calloc(bank_num, sizeof(bank_t));
+               
+               for(int i = 0; i < bank_num; i++) {
+                       rd_table[i].dev = NULL;
+                       rd_table[i].memory = rd_dummy;
+                       rd_table[i].wait = 0;
+                       
+                       wr_table[i].dev = NULL;
+                       wr_table[i].memory = wr_dummy;
+                       rd_table[i].wait = 0;
+               }
+               for(int i = 0;; i++) {
+                       if(bank_size == (1 << i)) {
+                               addr_shift = i;
+                               break;
+                       }
+               }
+               memset(rd_dummy, 0xff, bank_size);
+       }
+}
+
+void MEMORY::release()
+{
+       free(rd_table);
+       free(wr_table);
+       free(rd_dummy);
+       free(wr_dummy);
+}
+
+uint32_t MEMORY::read_data8(uint32_t addr)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(rd_table[bank].dev != NULL) {
+               return rd_table[bank].dev->read_memory_mapped_io8(addr);
+       } else {
+               return rd_table[bank].memory[addr & BANK_MASK];
+       }
+}
+
+void MEMORY::write_data8(uint32_t addr, uint32_t data)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(wr_table[bank].dev != NULL) {
+               wr_table[bank].dev->write_memory_mapped_io8(addr, data);
+       } else {
+               wr_table[bank].memory[addr & BANK_MASK] = data;
+       }
+}
+
+uint32_t MEMORY::read_data16(uint32_t addr)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(rd_table[bank].dev != NULL) {
+               return rd_table[bank].dev->read_memory_mapped_io16(addr);
+       } else {
+               uint32_t val = read_data8(addr);
+               val |= read_data8(addr + 1) << 8;
+               return val;
+       }
+}
+
+void MEMORY::write_data16(uint32_t addr, uint32_t data)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(wr_table[bank].dev != NULL) {
+               wr_table[bank].dev->write_memory_mapped_io16(addr, data);
+       } else {
+               write_data8(addr, data & 0xff);
+               write_data8(addr + 1, (data >> 8) & 0xff);
+       }
+}
+
+uint32_t MEMORY::read_data32(uint32_t addr)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(rd_table[bank].dev != NULL) {
+               return rd_table[bank].dev->read_memory_mapped_io32(addr);
+       } else {
+               uint32_t val = read_data16(addr);
+               val |= read_data16(addr + 2) << 16;
+               return val;
+       }
+}
+
+void MEMORY::write_data32(uint32_t addr, uint32_t data)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(wr_table[bank].dev != NULL) {
+               wr_table[bank].dev->write_memory_mapped_io32(addr, data);
+       } else {
+               write_data16(addr, data & 0xffff);
+               write_data16(addr + 2, (data >> 16) & 0xffff);
+       }
+}
+
+uint32_t MEMORY::read_data8w(uint32_t addr, int* wait)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       *wait = rd_table[bank].wait;
+       if(rd_table[bank].dev != NULL) {
+               return rd_table[bank].dev->read_memory_mapped_io8(addr);
+       } else {
+               return rd_table[bank].memory[addr & BANK_MASK];
+       }
+}
+
+void MEMORY::write_data8w(uint32_t addr, uint32_t data, int* wait)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       *wait = wr_table[bank].wait;
+       if(wr_table[bank].dev != NULL) {
+               wr_table[bank].dev->write_memory_mapped_io8(addr, data);
+       } else {
+               wr_table[bank].memory[addr & BANK_MASK] = data;
+       }
+}
+
+uint32_t MEMORY::read_data16w(uint32_t addr, int* wait)
+{
+       int wait_l, wait_h;
+       uint32_t val = read_data8w(addr, &wait_l);
+       val |= read_data8w(addr + 1, &wait_h) << 8;
+       *wait = wait_l + wait_h;
+       return val;
+}
+
+void MEMORY::write_data16w(uint32_t addr, uint32_t data, int* wait)
+{
+       int wait_l, wait_h;
+       write_data8w(addr, data & 0xff, &wait_l);
+       write_data8w(addr + 1, (data >> 8) & 0xff, &wait_h);
+       *wait = wait_l + wait_h;
+}
+
+uint32_t MEMORY::read_data32w(uint32_t addr, int* wait)
+{
+       int wait_l, wait_h;
+       uint32_t val = read_data16w(addr, &wait_l);
+       val |= read_data16w(addr + 2, &wait_h) << 16;
+       *wait = wait_l + wait_h;
+       return val;
+}
+
+void MEMORY::write_data32w(uint32_t addr, uint32_t data, int* wait)
+{
+       int wait_l, wait_h;
+       write_data16w(addr, data & 0xffff, &wait_l);
+       write_data16w(addr + 2, (data >> 16) & 0xffff, &wait_h);
+       *wait = wait_l + wait_h;
+}
+
+#ifdef MEMORY_DISABLE_DMA_MMIO
+uint32_t MEMORY::read_dma_data8(uint32_t addr)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(rd_table[bank].dev != NULL) {
+//             return rd_table[bank].dev->read_memory_mapped_io8(addr);
+               return 0xff;
+       } else {
+               return rd_table[bank].memory[addr & BANK_MASK];
+       }
+}
+
+void MEMORY::write_dma_data8(uint32_t addr, uint32_t data)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(wr_table[bank].dev != NULL) {
+//             wr_table[bank].dev->write_memory_mapped_io8(addr, data);
+       } else {
+               wr_table[bank].memory[addr & BANK_MASK] = data;
+       }
+}
+
+uint32_t MEMORY::read_dma_data16(uint32_t addr)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(rd_table[bank].dev != NULL) {
+//             return rd_table[bank].dev->read_memory_mapped_io16(addr);
+               return 0xffff;
+       } else {
+               uint32_t val = read_dma_data8(addr);
+               val |= read_dma_data8(addr + 1) << 8;
+               return val;
+       }
+}
+
+void MEMORY::write_dma_data16(uint32_t addr, uint32_t data)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(wr_table[bank].dev != NULL) {
+//             wr_table[bank].dev->write_memory_mapped_io16(addr, data);
+       } else {
+               write_dma_data8(addr, data & 0xff);
+               write_dma_data8(addr + 1, (data >> 8) & 0xff);
+       }
+}
+
+uint32_t MEMORY::read_dma_data32(uint32_t addr)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(rd_table[bank].dev != NULL) {
+//             return rd_table[bank].dev->read_memory_mapped_io32(addr);
+               return 0xffffffff;
+       } else {
+               uint32_t val = read_dma_data16(addr);
+               val |= read_dma_data16(addr + 2) << 16;
+               return val;
+       }
+}
+
+void MEMORY::write_dma_data32(uint32_t addr, uint32_t data)
+{
+       int bank = (addr & ADDR_MASK) >> addr_shift;
+       
+       if(wr_table[bank].dev != NULL) {
+//             wr_table[bank].dev->write_memory_mapped_io32(addr, data);
+       } else {
+               write_dma_data16(addr, data & 0xffff);
+               write_dma_data16(addr + 2, (data >> 16) & 0xffff);
+       }
+}
+#endif
+
+// register
+
+void MEMORY::set_memory_r(uint32_t start, uint32_t end, uint8_t *memory)
+{
+       MEMORY::initialize(); // subclass may overload initialize()
+       
+       uint32_t start_bank = start >> addr_shift;
+       uint32_t end_bank = end >> addr_shift;
+       
+       for(uint32_t i = start_bank; i <= end_bank; i++) {
+               rd_table[i].dev = NULL;
+               rd_table[i].memory = memory + bank_size * (i - start_bank);
+       }
+}
+
+void MEMORY::set_memory_w(uint32_t start, uint32_t end, uint8_t *memory)
+{
+       MEMORY::initialize();
+       
+       uint32_t start_bank = start >> addr_shift;
+       uint32_t end_bank = end >> addr_shift;
+       
+       for(uint32_t i = start_bank; i <= end_bank; i++) {
+               wr_table[i].dev = NULL;
+               wr_table[i].memory = memory + bank_size * (i - start_bank);
+       }
+}
+
+void MEMORY::set_memory_mapped_io_r(uint32_t start, uint32_t end, DEVICE *device)
+{
+       MEMORY::initialize();
+       
+       uint32_t start_bank = start >> addr_shift;
+       uint32_t end_bank = end >> addr_shift;
+       
+       for(uint32_t i = start_bank; i <= end_bank; i++) {
+               rd_table[i].dev = device;
+       }
+}
+
+void MEMORY::set_memory_mapped_io_w(uint32_t start, uint32_t end, DEVICE *device)
+{
+       MEMORY::initialize();
+       
+       uint32_t start_bank = start >> addr_shift;
+       uint32_t end_bank = end >> addr_shift;
+       
+       for(uint32_t i = start_bank; i <= end_bank; i++) {
+               wr_table[i].dev = device;
+       }
+}
+
+void MEMORY::set_wait_r(uint32_t start, uint32_t end, int wait)
+{
+       MEMORY::initialize();
+       
+       uint32_t start_bank = start >> addr_shift;
+       uint32_t end_bank = end >> addr_shift;
+       
+       for(uint32_t i = start_bank; i <= end_bank; i++) {
+               rd_table[i].wait = wait;
+       }
+}
+
+void MEMORY::set_wait_w(uint32_t start, uint32_t end, int wait)
+{
+       MEMORY::initialize();
+       
+       uint32_t start_bank = start >> addr_shift;
+       uint32_t end_bank = end >> addr_shift;
+       
+       for(uint32_t i = start_bank; i <= end_bank; i++) {
+               wr_table[i].wait = wait;
+       }
+}
+
+void MEMORY::unset_memory_r(uint32_t start, uint32_t end)
+{
+       MEMORY::initialize();
+       
+       uint32_t start_bank = start >> addr_shift;
+       uint32_t end_bank = end >> addr_shift;
+       
+       for(uint32_t i = start_bank; i <= end_bank; i++) {
+               rd_table[i].dev = NULL;
+               rd_table[i].memory = rd_dummy;
+       }
+}
+
+void MEMORY::unset_memory_w(uint32_t start, uint32_t end)
+{
+       MEMORY::initialize();
+       
+       uint32_t start_bank = start >> addr_shift;
+       uint32_t end_bank = end >> addr_shift;
+       
+       for(uint32_t i = start_bank; i <= end_bank; i++) {
+               wr_table[i].dev = NULL;
+               wr_table[i].memory = wr_dummy;
+       }
+}
+
+// load/save image
+
+int MEMORY::read_bios(const _TCHAR *file_name, uint8_t *buffer, int size)
+{
+       FILEIO* fio = new FILEIO();
+       int length = 0;
+       
+       if(fio->Fopen(create_local_path(file_name), FILEIO_READ_BINARY)) {
+               fio->Fread(buffer, size, 1);
+               length = fio->Ftell();
+               fio->Fclose();
+       }
+       delete fio;
+       return length;
+}
+
+bool MEMORY::write_bios(const _TCHAR *file_name, uint8_t *buffer, int size)
+{
+       FILEIO* fio = new FILEIO();
+       bool result = false;
+       
+       if(fio->Fopen(create_local_path(file_name), FILEIO_WRITE_BINARY)) {
+               fio->Fwrite(buffer, size, 1);
+               fio->Fclose();
+               result = true;
+       }
+       delete fio;
+       return result;
+}
+
+bool MEMORY::read_image(const _TCHAR *file_path, uint8_t *buffer, int size)
+{
+       FILEIO* fio = new FILEIO();
+       bool result = false;
+       
+       if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
+               fio->Fread(buffer, size, 1);
+               fio->Fclose();
+               result = true;
+       }
+       delete fio;
+       return result;
+}
+
+bool MEMORY::write_image(const _TCHAR* file_path, uint8_t* buffer, int size)
+{
+       FILEIO* fio = new FILEIO();
+       bool result = false;
+       
+       if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
+               fio->Fwrite(buffer, size, 1);
+               fio->Fclose();
+               result = true;
+       }
+       delete fio;
+       return result;
+}