Also useful, under linux, would be a way to map these addresses to user-space, so that one can test things without need to write drivers.
/dev/mem will do that. Something like:
int fd = open("/dev/mem",O_RDWR|O_SYNC);
unsigned char* RxTxMem1 = (unsigned char *) mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x000D4000);
unsigned char* RxTxMem2 = (unsigned char *) mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x000D5000);
Also, accessing I/O ports from user space is pretty simple:
#include <sys/io.h>
//...
ioperm(0x0100, 0x10, 1);
ioperm(0x0140, 0x30, 1);
//...
uint8_t val8 = inb(0x100); // 8-bit wide read
uint16_t val16 = inw(0x100); // 16-bit wide read
uint32_t val32 = inl(0x100); // 32-bit wide read
outb(val8, 0x100); // 8-bit wide write
outw(val16, 0x100); // 16-bit wide write
outl(val32, 0x100); // 32-bit wide write
Dealing with interrupts from userspace is not as simple. But, writing a very simple driver that can block a userspace process that does a read (or ioctl) on a special file until the interrupt fires isn't that hard. I did it once years ago. The "Linux Device Drivers" O'Reily book is a pretty good resource for these things.