nkeynes@31: /** nkeynes@561: * $Id$ nkeynes@31: * nkeynes@31: * mmio.h defines a complicated batch of macros used to build up the nkeynes@31: * memory-mapped I/O regions in a reasonably readable fashion. nkeynes@31: * nkeynes@31: * Copyright (c) 2005 Nathan Keynes. nkeynes@31: * nkeynes@31: * This program is free software; you can redistribute it and/or modify nkeynes@31: * it under the terms of the GNU General Public License as published by nkeynes@31: * the Free Software Foundation; either version 2 of the License, or nkeynes@31: * (at your option) any later version. nkeynes@31: * nkeynes@31: * This program is distributed in the hope that it will be useful, nkeynes@31: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@31: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@31: * GNU General Public License for more details. nkeynes@31: */ nkeynes@10: #ifndef dream_mmio_H nkeynes@10: #define dream_mmio_H 1 nkeynes@10: nkeynes@10: #ifdef __cplusplus nkeynes@10: extern "C" { nkeynes@10: #if 0 nkeynes@10: } nkeynes@10: #endif nkeynes@10: #endif nkeynes@10: nkeynes@10: #include nkeynes@10: #include nkeynes@10: nkeynes@796: #define LXDREAM_PAGE_TABLE_ENTRIES 128*1024 nkeynes@796: #define LXDREAM_PAGE_SIZE 4096 nkeynes@796: #define LXDREAM_PAGE_BITS 12 nkeynes@10: nkeynes@10: #define PORT_R 1 nkeynes@10: #define PORT_W 2 nkeynes@10: #define PORT_MEM 4 /* store written value */ nkeynes@10: #define PORT_RW 3 nkeynes@10: #define PORT_MR 5 nkeynes@10: #define PORT_MRW 7 nkeynes@172: #define PORT_NOTRACE 16 nkeynes@10: #define UNDEFINED 0xDEADBEEF /* This has to be a value that nothing inits to */ nkeynes@10: nkeynes@10: struct mmio_region { nkeynes@10: char *id, *desc; nkeynes@10: uint32_t base; nkeynes@10: int32_t (*io_read)(uint32_t addr); nkeynes@10: void (*io_write)(uint32_t addr, uint32_t val); nkeynes@10: char *mem; nkeynes@10: char *save_mem; /* Used to compare for gui updates */ nkeynes@10: struct mmio_port { nkeynes@10: char *id, *desc; nkeynes@10: int width; nkeynes@10: uint32_t offset; nkeynes@10: uint32_t def_val; nkeynes@10: int flags; nkeynes@10: uint32_t *val; nkeynes@10: } ports[80]; nkeynes@10: struct mmio_port **index; /* reverse lookup by address */ nkeynes@10: int trace_flag; /* set to 1 to enable transfer traces */ nkeynes@10: }; nkeynes@10: nkeynes@10: void register_io_region( struct mmio_region *mmio ); nkeynes@10: void register_io_regions( struct mmio_region **mmiolist ); nkeynes@10: nkeynes@10: extern struct mmio_region *io_rgn[]; nkeynes@674: extern uint32_t num_io_rgns; nkeynes@10: nkeynes@10: #define MMIO_READ( id, r ) *((int32_t *)(mmio_region_##id.mem + (r))) nkeynes@136: #define MMIO_READF( id, r ) *((float *)(mmio_region_##id.mem + (r))) nkeynes@10: #define MMIO_WRITE( id, r, v ) *((int32_t *)(mmio_region_##id.mem + (r))) = (v) nkeynes@474: #define MMIO_ADDR( id, r) ((int32_t *)(mmio_region_##id.mem + (r))) nkeynes@10: #define MMIO_REG( id, r ) ((int32_t *)(mmio_region_##id.mem + (r))) nkeynes@10: #define MMIO_REGID( mid, r ) (mmio_region_##mid.index[(r)>>2] != NULL ? \ nkeynes@10: mmio_region_##mid.index[(r)>>2]->id : "" ) nkeynes@10: #define MMIO_REGDESC( mid, r) (mmio_region_##mid.index[(r)>>2] != NULL ? \ nkeynes@10: mmio_region_##mid.index[(r)>>2]->desc : "Undefined register" ) nkeynes@10: #define MMIO_TRACE( mid ) mmio_region_##mid.trace_flag = 1 nkeynes@10: #define MMIO_NOTRACE( mid ) mmio_region_##mid.trace_flag = 0 nkeynes@10: nkeynes@10: #define MMIO_REGID_BYNUM( mid, r ) (io_rgn[mid]->index[(r)>>2] != NULL ? \ nkeynes@10: io_rgn[mid]->index[(r)>>2]->id : "" ) nkeynes@10: #define MMIO_REGDESC_BYNUM( mid, r ) (io_rgn[mid]->index[(r)>>2] != NULL ? \ nkeynes@10: io_rgn[mid]->index[(r)>>2]->desc : "Undefined register" ) nkeynes@172: #define MMIO_NOTRACE_BYNUM( mid, r ) (io_rgn[mid]->index[(r)>>2] != NULL ? \ nkeynes@172: (io_rgn[mid]->index[(r)>>2]->flags & PORT_NOTRACE) : 0 ) nkeynes@10: #define MMIO_NAME_BYNUM( mid ) (io_rgn[mid]->id) nkeynes@10: nkeynes@156: #define MMIO_REGID_IOBYNUM( io, r ) (io->index[(r)>>2] != NULL ? \ nkeynes@156: io->index[(r)>>2]->id : "" ) nkeynes@156: #define MMIO_REGDESC_IOBYNUM( io, r ) (io->index[(r)>>2] != NULL ? \ nkeynes@156: io->index[(r)>>2]->desc : "Undefined register" ) nkeynes@172: #define MMIO_NOTRACE_IOBYNUM( io, r ) (io->index[(r)>>2] != NULL ? \ nkeynes@172: (io->index[(r)>>2]->flags & PORT_NOTRACE) : 0 ) nkeynes@156: nkeynes@10: #ifdef __cplusplus nkeynes@10: } nkeynes@10: #endif nkeynes@10: nkeynes@10: #endif nkeynes@10: nkeynes@10: #ifdef MMIO_IMPL nkeynes@10: nkeynes@10: #ifndef MMIO_IMPL_INCLUDED nkeynes@10: #define MMIO_IMPL_INCLUDED nkeynes@10: #undef MMIO_REGION_BEGIN nkeynes@10: #undef LONG_PORT nkeynes@10: #undef WORD_PORT nkeynes@10: #undef BYTE_PORT nkeynes@10: #undef MMIO_REGION_END nkeynes@10: #undef MMIO_REGION_LIST_BEGIN nkeynes@10: #undef MMIO_REGION nkeynes@10: #undef MMIO_REGION_LIST_END nkeynes@10: #define MMIO_REGION_BEGIN(b,id,d) struct mmio_region mmio_region_##id = { #id, d, b, mmio_region_##id##_read, mmio_region_##id##_write, 0, 0, { nkeynes@10: #define LONG_PORT( o,id,f,def,d ) { #id, d, 32, o, def, f }, nkeynes@10: #define WORD_PORT( o,id,f,def,d ) { #id, d, 16, o, def, f }, nkeynes@10: #define BYTE_PORT( o,id,f,def,d ) { #id, d, 8, o, def, f }, nkeynes@10: #define MMIO_REGION_END {NULL, NULL, 0, 0, 0, 0} } }; nkeynes@10: #define MMIO_REGION_LIST_BEGIN(id) struct mmio_region *mmio_list_##id[] = { nkeynes@10: #define MMIO_REGION( id ) &mmio_region_##id, nkeynes@10: #define MMIO_REGION_LIST_END NULL}; nkeynes@10: nkeynes@10: /* Stub defines for modules we haven't got to yet, or ones which don't nkeynes@10: * actually need any direct code on read and/or write nkeynes@10: */ nkeynes@10: #define MMIO_REGION_READ_STUBFN( id ) \ nkeynes@10: int32_t mmio_region_##id##_read( uint32_t reg ) { \ nkeynes@10: int32_t val = MMIO_READ( id, reg ); \ nkeynes@10: WARN( "Read from unimplemented module %s (%03X => %08X) [%s: %s]",\ nkeynes@10: #id, reg, val, MMIO_REGID(id,reg), MMIO_REGDESC(id,reg) ); \ nkeynes@10: return val; \ nkeynes@10: } nkeynes@10: #define MMIO_REGION_WRITE_STUBFN( id ) \ nkeynes@10: void mmio_region_##id##_write( uint32_t reg, uint32_t val ) { \ nkeynes@10: WARN( "Write to unimplemented module %s (%03X <= %08X) [%s: %s]", \ nkeynes@10: #id, reg, val, MMIO_REGID(id,reg), MMIO_REGDESC(id,reg) ); \ nkeynes@10: MMIO_WRITE( id, reg, val ); \ nkeynes@10: } nkeynes@10: #define MMIO_REGION_STUBFNS( id ) \ nkeynes@10: MMIO_REGION_READ_STUBFN( id ) \ nkeynes@10: MMIO_REGION_WRITE_STUBFN( id ) nkeynes@10: #define MMIO_REGION_READ_DEFFN( id ) \ nkeynes@10: int32_t mmio_region_##id##_read( uint32_t reg ) { \ nkeynes@10: return MMIO_READ( id, reg ); \ nkeynes@10: } nkeynes@10: #define MMIO_REGION_WRITE_DEFFN( id ) \ nkeynes@10: void mmio_region_##id##_write( uint32_t reg, uint32_t val ) { \ nkeynes@10: MMIO_WRITE( id, reg, val ); \ nkeynes@10: } nkeynes@10: #define MMIO_REGION_DEFFNS( id ) \ nkeynes@10: MMIO_REGION_READ_DEFFN( id ) \ nkeynes@10: MMIO_REGION_WRITE_DEFFN( id ) nkeynes@10: #endif nkeynes@10: nkeynes@10: #define MMIO_REGION_WRITE_FN( id, reg, val ) \ nkeynes@10: void mmio_region_##id##_write( uint32_t reg, uint32_t val ) nkeynes@10: nkeynes@10: #define MMIO_REGION_READ_FN( id, reg ) \ nkeynes@10: int32_t mmio_region_##id##_read( uint32_t reg ) nkeynes@10: nkeynes@10: #else nkeynes@10: nkeynes@10: #ifndef MMIO_IFACE_INCLUDED nkeynes@10: #define MMIO_IFACE_INCLUDED nkeynes@10: #define MMIO_REGION_BEGIN(b,id,d) \ nkeynes@10: extern struct mmio_region mmio_region_##id; \ nkeynes@10: int32_t mmio_region_##id##_read(uint32_t); \ nkeynes@10: void mmio_region_##id##_write(uint32_t, uint32_t); \ nkeynes@10: enum mmio_region_##id##_port_t { nkeynes@10: #define LONG_PORT( o,id,f,def,d ) id = o, nkeynes@10: #define WORD_PORT( o,id,f,def,d ) id = o, nkeynes@10: #define BYTE_PORT( o,id,f,def,d ) id = o, nkeynes@10: #define MMIO_REGION_END }; nkeynes@10: #define MMIO_REGION_LIST_BEGIN(id) extern struct mmio_region *mmio_list_##id[]; nkeynes@10: #define MMIO_REGION( id ) nkeynes@10: #define MMIO_REGION_LIST_END nkeynes@10: #endif nkeynes@10: nkeynes@10: #endif nkeynes@10: