mbed LPC812 emulator pre-alpha version

Dependencies:   BaseV6M mbed F12RFileSystem F32RFileSystem ROMSLOT SDStorage

320 340

Example

TTB_mbed_LPC812.bin save as "LPC812.IMG" .
internal boot rom image(0x1fff0000-0x1fff1fff) save as "LPC812.ROM".

Tested programs

EMU81x.cpp

Committer:
va009039
Date:
2016-04-09
Revision:
5:f22e2df90a70
Parent:
2:3f3637d7c2bc

File content as of revision 5:f22e2df90a70:

// EMU81x.cpp 2015/8/12
#include "mbed.h"
#include "EMU81x.h"
#define V6M_LOG_LEVEL 2
#include "v6m_log.h"

const int EMU81x_RAM_SIZE = (1024*4);
const int EMU81x_FLASH_SIZE = (1024*16);
const int EMU81x_ROM_SIZE = (1024*8);

const uint32_t EMU81x_FLASH_BASE =     0x00000000;
const uint32_t EMU81x_RAM_BASE =       0x10000000;
const uint32_t EMU81x_ROM_BASE =       0x1fff0000;
const uint32_t EMU81x_APB_BASE =       0x40000000;
const uint32_t EMU81x_AHB_BASE =       0x50000000;
const uint32_t EMU81x_GPIO_PORT_BASE = 0xa0000000;
const uint32_t EMU81x_SCS_BASE =   0xe000e000;

EMU81x_USART::EMU81x_USART(EMU81x& mcu_, int ch_):mcu(mcu_),ch(ch_) {
    V6M_ASSERT(ch >= 0 && ch <= 2);
    CFG = 0x00;
    STAT = 0x0e;
    BRG = 0x00;
}

void EMU81x_USART::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        #define c(OFFSET,NAME) case OFFSET: NAME = d; V6M_INFO("P: LPC_USART%d->%s << %08x", ch, #NAME, d); break;
        c(0x00, CFG);
        c(0x08, STAT);
        c(0x10, INTENCLR);
         case 0x1c:
            mcu.SerialPutc_Callback(ch, d);
            V6M_INFO("P: LPC_USART%d->TXDATA << %08x", ch, d);
            break;
        c(0x20, BRG);
        #undef c
        default:
            V6M_WARN("P: LPC_UART%d %08x << %08x", ch, a, d);
            break;
    }
}

uint32_t EMU81x_USART::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a&0xff) {
        #define c(OFFSET,NAME) case OFFSET: d = NAME; V6M_INFO("P: LPC_USART%d->%s >> %08x", ch, #NAME, d); break;
        c(0x00, CFG);
        case 0x08:
            d = 0x04;
            if (mcu.SerialReadable_Callback(ch)) {
                d |= 0x01;
            }
            V6M_INFO("P: LPC_USART%d->STAT >> %08x", ch, d);
            break;
        case 0x14:
            d = mcu.SerialGetc_Callback(ch);
            V6M_INFO("P: LPC_USART%d->RXDATA >> %08x", ch, d);
            break;
        c(0x20, BRG);
        #undef c
        default:
            V6M_WARN("P: LPC_USART%d %08x >> %08x", ch, a, d);
            break;
    }
    return d;
}

EMU81x_MRT::EMU81x_MRT():timer0(0x7fffffff) {
}

void EMU81x_MRT::clock_in(uint32_t n) {
    V6M_ASSERT(n != 0);
    timer0 = (timer0 - n) & 0x7fffffff;
}

void EMU81x_MRT::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        #define c(OFFSET,NAME) case OFFSET: V6M_INFO("P: LPC_MRT->%s << %08x", #NAME, d); break;
        c(0x00, INTVAL0);
        c(0x08, CTRL0);
        c(0x10, INTVAL1);
        c(0x18, CTRL1);
        #undef c
        default:
            V6M_WARN("P: LPC_MRT %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU81x_MRT::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a&0xff) {
        case 0x04:
            d = timer0;
            V6M_INFO("P: LPC_MRT->TIMER0 >> %u", timer0);
            break;
        default:
            V6M_WARN("P: LPC_MRT %08x >> %02x", a, d);
            break;
    }
    return d;
}

EMU81x_IOCON::EMU81x_IOCON() {
    PIO0_17 = 0x90;
    PIO0_13 = 0x90;
    PIO0_12 = 0x90;
    PIO0_5 = 0x90;
    PIO0_4 = 0x90;
    PIO0_3 = 0x90;
    PIO0_2 = 0x90;
    PIO0_11 = 0x80;
    PIO0_10 = 0x80;
    PIO0_16 = 0x90;
    PIO0_15 = 0x90;
    PIO0_1 = 0x90;
    PIO0_9 = 0x90;
    PIO0_8 = 0x90;
    PIO0_7 = 0x90;
    PIO0_6 = 0x90;
    PIO0_0 = 0x90;
    PIO0_14 = 0x90;
}

void EMU81x_IOCON::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        #define c(OFFSET,NAME) case OFFSET: NAME = d; V6M_INFO("P: LPC_IOCON->PIO0_%s << %08x", #NAME, d); break;
        c(0x00, PIO0_17);
        c(0x04, PIO0_13);
        c(0x08, PIO0_12);
        c(0x0c, PIO0_5);
        c(0x10, PIO0_3);
        c(0x14, PIO0_4);
        c(0x18, PIO0_2);
        c(0x1c, PIO0_11);
        c(0x20, PIO0_10);
        c(0x24, PIO0_16);
        c(0x28, PIO0_15);
        c(0x2c, PIO0_1);
        c(0x34, PIO0_9);
        c(0x38, PIO0_8);
        c(0x3c, PIO0_7);
        c(0x40, PIO0_6);
        c(0x44, PIO0_0);
        c(0x48, PIO0_14);
        #undef c
        default:
            V6M_WARN("P: LPC_IOCON %08x << %04x", a, d);
            break;
    }
}

uint32_t EMU81x_IOCON::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a&0xff) {
        #define c(OFFSET,NAME) case OFFSET: d = NAME; V6M_INFO("P: LPC_IOCON->PIO0_%s >> %08x", #NAME, d); break;
        c(0x00, PIO0_17);
        c(0x04, PIO0_13);
        c(0x08, PIO0_12);
        c(0x0c, PIO0_5);
        c(0x10, PIO0_3);
        c(0x14, PIO0_4);
        c(0x18, PIO0_2);
        c(0x1c, PIO0_11);
        c(0x20, PIO0_10);
        c(0x24, PIO0_16);
        c(0x28, PIO0_15);
        c(0x2c, PIO0_1);
        c(0x34, PIO0_9);
        c(0x38, PIO0_8);
        c(0x3c, PIO0_7);
        c(0x40, PIO0_6);
        c(0x44, PIO0_0);
        c(0x48, PIO0_14);
        #undef c
        default:
            V6M_WARN("P: LPC_IOCON %08x >> %04x", a, d);
            break;
    }
    return d;
}

EMU81x_SYSCON::EMU81x_SYSCON() {
}

void EMU81x_SYSCON::poke32(uint32_t a, uint32_t d) {
    switch(a&0xfff) {
        #define c(OFFSET,NAME) case OFFSET: V6M_INFO("P: LPC_SYSCON->%s << %08x", #NAME, d); break;
        c(0x004, PRESETCTRL);
        c(0x008, SYSPLLCTRL);
        c(0x040, SYSPLLCLKSEL);
        c(0x044, SYSPLLCLKUEN);
        c(0x070, MAINCLKSEL);
        c(0x074, MAINCLKUEN);
        c(0x078, SYSAHBCLKDIV);
        c(0x080, SYSAHBCLKCTRL);
        c(0x094, UARTCLKDIV);
        c(0x0f0, UARTFRGDIV);
        c(0x0f4, UARTFRGMULT);
        c(0x238, PDRUNCFG);
        #undef c
        default:
            V6M_WARN("P: LPC_SYSCON %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU81x_SYSCON::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a&0xfff) {
        #define c(OFFSET,NAME) case OFFSET: V6M_INFO("P: LPC_SYSCON->%s >> %08x", #NAME, d); break;
        c(0x004, PRESETCTRL);
        case 0x00c:
            d = 0x01;
            V6M_INFO("P: LPC_SYSCON->SYSPLLSTAT >> %08x", d);
            break;
        case 0x044:
            d = 0x01;
            V6M_INFO("P: LPC_SYSCON->SYSPLLCLKUEN >> %08x", d);
            break;
        case 0x074:
            d = 0x01;
            V6M_INFO("P: LPC_SYSCON->MAINCLKUEN >> %08x", d);
            break;
        c(0x080, SYSAHBCLKCTRL);
        c(0x094, UARTCLKDIV);
        c(0x0f0, UARTFRGDIV);
        c(0x0f4, UARTFRGMULT);
        c(0x238, PDRUNCFG);
        #undef c
        default:
            V6M_WARN("P: LPC_SYSCON %08x >> %08x", a, d);
            break;
    }
    return d;
}

EMU81x_SWM::EMU81x_SWM() {
    memset(pinassign, 0xff, sizeof(pinassign));
    pinenable0 = 0x1b3;
}

void EMU81x_SWM::poke32(uint32_t a, uint32_t d) {
    int n = (a&0xff) / 4;
    switch(a&0xfff) {
        case 0x00: case 0x04: case 0x08: case 0x0c: case 0x10: case 0x14: case 0x1c: case 0x20:
            pinassign[n] = d;
            V6M_INFO("P: LPC_SWM->PINASSIGN%d << %08x", n, d);
            break;
        case 0x1c0:
            pinenable0 = d;
            V6M_INFO("P: LPC_SWM->PINENABLE0 << %08x", d);
            break;
        default:
            V6M_INFO("P: LPC_SWM %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU81x_SWM::peek32(uint32_t a) {
    int n = (a&0xff) / 4;
    uint32_t d = 0x00;
    switch(a&0xfff) {
        case 0x00: case 0x04: case 0x08: case 0x0c: case 0x10: case 0x14: case 0x1c: case 0x20:
            d = pinassign[n];
            V6M_INFO("P: LPC_SWM->PINASSIGN%d >> %08x", n, d);
            break;
        case 0x1c0:
            d = pinenable0;
            V6M_INFO("P: LPC_SWM->PINENABLE0 >> %08x", d);
            break;
        default:
            V6M_INFO("P: LPC_SWM %08x >> %08x", a, d);
            break;
    }
    return d;
}

EMU81x_GPIO::EMU81x_GPIO(EMU81x& mcu_):mcu(mcu_) {
    dir0 = 0;
    data0 = 0;
}

void EMU81x_GPIO::poke32(uint32_t a, uint32_t d) {
    V6M_ASSERT((a&0xffff0000) == 0xa0000000);
    switch(a&0xffff) {
        case 0x2000:
            dir0 = d;
            V6M_INFO("P: LPC_GPIO_PORT->DIR0 << %08x", d);
            break;
        case 0x2200:
            data0 |= d;
            for(int pin = 0; pin <24; pin++) {
                if (d & (1UL<<pin)) {
                    mcu.DigitalWrite_Callback(0, pin, 1);
                }
            }
            V6M_INFO("P: LPC_GPIO_PORT->SET0 << %08x", d);
            break;
        case 0x2280:
            data0 &= (~d)&0xffffffff;
            for(int pin = 0; pin <24; pin++) {
                if (d & (1UL<<pin)) {
                    mcu.DigitalWrite_Callback(0, pin, 0);
                }
            }
            V6M_INFO("P: LPC_GPIO_PORT->CLR0 << %08x", d);
            break;
        default:
            V6M_WARN("P: LPC_GPIO_PORT %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU81x_GPIO::peek32(uint32_t a) {
    V6M_ASSERT((a&0xffff0000) == 0xa0000000);
    uint32_t d = 0x00000000;
    switch(a&0xffff) {
        case 0x2000:
            d = dir0;
            V6M_INFO("P: LPC_GPIO_PORT->DIR0 >> %08x", d);
            break;
        case 0x2100:
            d = data0;
            V6M_INFO("P: LPC_GPIO_PORT->PIN0 >> %08x", d);
            break;
        default:
            V6M_WARN("P: LPC_GPIO_PORT %08x >> %08x", a, d);
            break;
    }
    return d;
}

EMU81x_I2C::EMU81x_I2C(EMU81x& mcu_):mcu(mcu_) {
    cfg = 0x00;
    mststate = 0;
}

void EMU81x_I2C::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        case 0x00:
            cfg = d;
            V6M_INFO("P: LPC_I2C->CFG << %08x", d);
            break;
        case 0x0c:
            V6M_INFO("P: LPC_I2C->INTENCLR << %08x", d);
            break;
        case 0x14:
            V6M_INFO("P: LPC_I2C->DIV << %08x", d);
            break;
        case 0x20:
            if (d & 0x02) { // master start
                i2c_addr = mstdat;
                if (i2c_addr & 0x01) {
                    mcu.I2CRead_Callback(i2c_addr, i2c_data, sizeof(i2c_data));
                    mststate = 1; // receive ready
                    i2c_pos = 0;
                } else {
                    i2c_pos = 0;
                    mststate = 2; // transmit ready
                }
            } else if (d & 0x04) { // master stop
                if (i2c_addr & 0x01) {
                    mststate = 0; // idle
                } else {
                    mcu.I2CWrite_Callback(i2c_addr, i2c_data, i2c_pos);
                    mststate = 0;
                }
            } else if (d & 0x01) { // master continue
                if (i2c_pos < sizeof(i2c_data)) {
                    i2c_data[i2c_pos++] = mstdat;
                }
                mststate = 2; // transmit ready
            } else {
                V6M_ERROR("MSTCTL=%02x", d);
            }
            V6M_INFO("P: LPC_I2C->MSTCTL << %08x", d);
            break;
        case 0x24:
            V6M_INFO("P: LPC_I2C->MSTTIME << %08x", d);
            break;
        case 0x28:
            mstdat = d & 0xff;
            V6M_INFO("P: LPC_I2C->MSTDAT << %08x", d);
            break;
        default:
            V6M_WARN("P: LPC_I2C %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU81x_I2C::peek32(uint32_t a) {
    uint32_t d = 0x00000000;
    switch(a&0xff) {
        case 0x00:
            d = cfg;
            V6M_INFO("P: LPC_I2C->CFG >> %08x", d);
            break;
        case 0x04:
            d = 0x801|mststate<<1;
            V6M_INFO("P: LPC_I2C->STAT >> %08x", d);
            break;
        case 0x28:
            if (i2c_pos < sizeof(i2c_data)) {
                d = i2c_data[i2c_pos++];
            }
            V6M_INFO("P: LPC_I2C->MSTDAT >> %08x", d);
            break;
        default:
            V6M_INFO("P: LPC_I2C %08x >> %08x", a, d);
            break;
    }
    return d;
}

EMU81x_SPI::EMU81x_SPI(EMU81x& mcu_, int ch_):mcu(mcu_),ch(ch_) {
}

void EMU81x_SPI::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        case 0x00:
            V6M_INFO("P: LPC_SPI%d->CFG << %08x", ch, d);
            break;
        case 0x04:
            V6M_INFO("P: LPC_SPI%d->DLY << %08x", ch, d);
            break;
        case 0x10:
            V6M_INFO("P: LPC_SPI%d->INTENCLR << %08x", ch, d);
            break;
        case 0x18:
            V6M_INFO("P: LPC_SPI%d->TXDATCTL << %08x", ch, d);
            break;
        case 0x1c:
            rxdat = mcu.SPIWrite_Callback(ch, d);
            V6M_INFO("P: LPC_SPI%d->TXDAT << %08x", ch, d);
            break;
        case 0x24:
            V6M_INFO("P: LPC_SPI%d->DIV << %08x", ch, d);
            break;
        default:
            V6M_WARN("P: LPC_SPI%d %08x << %08x", ch, a, d);
            break;
    }
}

uint32_t EMU81x_SPI::peek32(uint32_t a) {
    uint32_t d = 0;
    switch(a&0xff) {
        case 0x00:
            V6M_INFO("P: LPC_SPI%d->CFG >> %08x", ch, d);
            break;
        case 0x08:
            d = 0x03;
            V6M_INFO("P: LPC_SPI%d->STAT >> %08x", ch, d);
            break;
        case 0x14:
            d = rxdat;
            V6M_INFO("P: LPC_SPI%d->RXDAT >> %08x", ch, d);
            break;
        case 0x18:
            V6M_INFO("P: LPC_SPI%d->TXDATCTL >> %08x", ch, d);
            break;
        default:
            V6M_WARN("P: LPC_SPI%d %08x >> %08x", ch, a, d);
            break;
    }
    return d;
}

EMU81x_SCB::EMU81x_SCB() {
    vtor = 0;
}

void EMU81x_SCB::poke32(uint32_t a, uint32_t d) {
    switch(a&0xfff) {
        case 0xd08:
            vtor = d;
            V6M_INFO("P: SCB->VTOR << %08x", d);
            break;
        default:
            V6M_WARN("P: SCB %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU81x_SCB::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a&0xfff) {
        case 0xd08:
            d = vtor;
            V6M_INFO("P: SCB->VTOR >> %08x", d);
            break;
        default:
            V6M_WARN("P: SCB %08x >> %08x", a, d);
            break;
    }
    return d;
}

void EMU81x_NVIC::poke32(uint32_t a, uint32_t d) {
    switch(a) {
        case 0xe000e100:
            iser = d;
            V6M_INFO("P: NVIC->ISER[0] << %08x", d);
            break;
        case 0xe000e180:
            V6M_INFO("P: NVIC->ICPR[0] << %08x", d);
            break;
        default:
            V6M_WARN("P: NVIC %08x >> %08x", a, d);
            break;
    }
}

EMU81x::EMU81x():_uart0(*this,0),_uart1(*this,1),_uart2(*this,2),gpio(*this)
                ,_i2c(*this), _spi0(*this, 0), _spi1(*this, 1) {
    flash = NULL;
    rom = NULL;
    ram = new uint8_t[EMU81x_RAM_SIZE];
}

EMU81x::~EMU81x() {
    delete[] ram;
}

void EMU81x::poke32(uint32_t a, uint32_t d) {
    switch(a>>24) {
        case EMU81x_RAM_BASE>>24:
            V6M_ASSERT(a < (EMU81x_RAM_BASE+EMU81x_RAM_SIZE));
            V6M_ASSERT(ram);
            ram[a - EMU81x_RAM_BASE + 0] = d>>0;
            ram[a - EMU81x_RAM_BASE + 1] = d>>8;
            ram[a - EMU81x_RAM_BASE + 2] = d>>16;
            ram[a - EMU81x_RAM_BASE + 3] = d>>24;
            V6M_INFO("W: %08x << %08x", a, d);
            break;
        case EMU81x_APB_BASE>>24:
            switch((a>>12)&0xff) {
                case 0x04: mrt.poke32(a, d); break;
                case 0x0c: swm.poke32(a, d); break;
                case 0x48: syscon.poke32(a, d); break;
                case 0x44: iocon.poke32(a, d); break;
                case 0x50: _i2c.poke32(a, d); break;
                case 0x58: _spi0.poke32(a, d); break;
                case 0x5c: _spi1.poke32(a, d); break;
                case 0x64: _uart0.poke32(a, d); break;
                case 0x68: _uart1.poke32(a, d); break;
                case 0x6c: _uart2.poke32(a, d); break;
                default:
                    V6M_WARN("P: %08x << %08x", a, d);
                    break;
            }
            break;
        case EMU81x_AHB_BASE>>24:
            V6M_WARN("P: %08x << %08x", a, d);
            break;
        case EMU81x_FLASH_BASE>>24:
        case EMU81x_ROM_BASE>>24:
            V6M_ASSERT(0);
            break;
        case EMU81x_GPIO_PORT_BASE>>24:
            gpio.poke32(a, d);
            break;
        case EMU81x_SCS_BASE>>24:
            switch(a&0xffffff) {
                case 0x00e100:
                case 0x00e180:
                    nvic.poke32(a, d);
                    break;
                case 0x00ed08:
                    scb.poke32(a, d);
                    break;
                default:
                    V6M_WARN("P: %08x << %08x", a, d);
                    break;
            }
            break;
        default:
            V6M_WARN("P: %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU81x::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a>>24) {
        case EMU81x_RAM_BASE>>24:
            V6M_ASSERT(a < (EMU81x_RAM_BASE+EMU81x_RAM_SIZE));
            d = ram[a - EMU81x_RAM_BASE];
            d |= ram[a - EMU81x_RAM_BASE + 1]<<8;
            d |= ram[a - EMU81x_RAM_BASE + 2]<<16;
            d |= ram[a - EMU81x_RAM_BASE + 3]<<24;
            V6M_INFO("R: %08x >> %08x", a, d);
            break;
        case EMU81x_FLASH_BASE>>24:
            V6M_ASSERT(a < (EMU81x_FLASH_BASE+EMU81x_FLASH_SIZE));
            V6M_ASSERT(flash);
            d = flash[a - EMU81x_FLASH_BASE];
            d |= flash[a - EMU81x_FLASH_BASE + 1]<<8;
            d |= flash[a - EMU81x_FLASH_BASE + 2]<<16;
            d |= flash[a - EMU81x_FLASH_BASE + 3]<<24;
            break;
        case EMU81x_ROM_BASE>>24:
            V6M_ASSERT(a < (EMU81x_ROM_BASE+EMU81x_ROM_SIZE));
            V6M_ASSERT(rom);
            d = rom[a - EMU81x_ROM_BASE];
            d |= rom[a - EMU81x_ROM_BASE + 1]<<8;
            d |= rom[a - EMU81x_ROM_BASE + 2]<<16;
            d |= rom[a - EMU81x_ROM_BASE + 3]<<24;
            break;
        case EMU81x_APB_BASE>>24:
            switch((a>>12)&0xff) {
                case 0x04: d = mrt.peek32(a); break;
                case 0x0c: d = swm.peek32(a); break;
                case 0x44: d = iocon.peek32(a); break;
                case 0x48: d = syscon.peek32(a); break;
                case 0x50: d = _i2c.peek32(a); break;
                case 0x58: d = _spi0.peek32(a); break;
                case 0x5c: d = _spi1.peek32(a); break;
                case 0x64: d = _uart0.peek32(a); break;
                case 0x68: d = _uart1.peek32(a); break;
                case 0x6c: d = _uart2.peek32(a); break;
                default:
                    V6M_WARN("P: %08x >> %08x", a, d);
                    break;
            }
            break;
        case EMU81x_GPIO_PORT_BASE>>24:
            d = gpio.peek32(a);
            break;
        case 0xe0:
            switch(a&0xffffff) {
                case 0x00ed08:
                    d = scb.peek32(a);
                    break;
                default:
                    V6M_WARN("P: %08x >> %08x", a, d);
                    break;
            }
            break;
        default:
            V6M_WARN("P: %08x >> %08x", a, d);
            break;
    }
    return d;
}

void EMU81x::poke8(uint32_t a, uint8_t d) {
    switch(a>>24) {
        case EMU81x_RAM_BASE>>24:
            V6M_ASSERT(a < (EMU81x_RAM_BASE+EMU81x_RAM_SIZE));
            V6M_ASSERT(ram);
            ram[a - EMU81x_RAM_BASE] = d;
            V6M_INFO("W: %08x << %02x", a, d);
            break;
        default:
            V6M_ASSERT(0);
            break;
    }
}

uint8_t EMU81x::peek8(uint32_t a) {
    uint8_t d = 0x00;
    switch(a>>24) {
        case EMU81x_RAM_BASE>>24:
            V6M_ASSERT(a < (EMU81x_RAM_BASE+EMU81x_RAM_SIZE));
            d = ram[a - EMU81x_RAM_BASE];
            V6M_INFO("R: %08x >> %02x", a, d);
            break;
        case EMU81x_FLASH_BASE>>24:
            V6M_ASSERT(a < (EMU81x_FLASH_BASE+EMU81x_FLASH_SIZE));
            d = flash[a - EMU81x_FLASH_BASE];
            break;
        case EMU81x_ROM_BASE>>24:
            V6M_ASSERT(a < (EMU81x_ROM_BASE+EMU81x_ROM_SIZE));
            d = rom[a - EMU81x_ROM_BASE];
            break;
        default:
            V6M_ASSERT(0);
            break;
    }
    return d;
}

void EMU81x::clock_in(uint32_t n) {
    mrt.clock_in(n);
}

void EMU81x::trace() {
    V6M_INFO("S: r0=%08x r1=%08x  r2=%08x  r3=%08x  r4=%08x r5=%08x r6=%08x r7=%08x", R[0],R[1],R[2],R[3],R[4],R[5],R[6],R[7]);
    V6M_INFO("S: r8=%08x r9=%08x r10=%08x r11=%08x r12=%08x sp=%08x lr=%08x pc=%08x", R[8],R[9],R[10],R[11],R[12],R[13],R[14],R[15]);
    V6M_INFO("S: xPSR=%08x N=%d Z=%d C=%d V=%d", R[16], N(), Z(), C(), V());
    V6M_DEBUG("S: cycle=%d code=%02x code2nd=%02x im=%08x d=%d n=%d m=%d", cycle, code, code2nd, R[17], GetRegIndex(Rd), GetRegIndex(Rn), GetRegIndex(Rm));

}