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:
2015-08-10
Revision:
1:913dfd59e25a
Child:
2:3f3637d7c2bc

File content as of revision 1:913dfd59e25a:

// EMU81x.cpp 2015/8/8
#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;
}

void EMU81x_USART::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        case 0x00:
            cfg = d;
            V6M_INFO("P: LPC_USART%d->CFG << %08x", ch, d);
            break;
        case 0x08:
            V6M_INFO("P: LPC_USART%d->STAT << %08x", ch, d);
            break;
        case 0x10:
            V6M_INFO("P: LPC_USART%d->INTENCLR << %08x", ch, d);
            break;
        case 0x1c:
            mcu.SerialPutc_Callback(ch, d);
            V6M_INFO("P: LPC_USART%d->TXDATA << %08x", ch, d);
            break;
        case 0x20:
            V6M_INFO("P: LPC_USART%d->TXCTRL << %08x", ch, d);
            break;
         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) {
        case 0x00:
            d = cfg;
            V6M_INFO("P: LPC_USART%d->CFG >> %08x", ch, d);
            break;
        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;
        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) {
        case 0x00:
            V6M_INFO("P: LPC_MRT->INTVAL0 << %08x", d);
            break;
        case 0x08:
            V6M_INFO("P: LPC_MRT->CTRL0 << %08x", d);
            break;
        case 0x10:
            V6M_INFO("P: LPC_MRT->INTVAL1 << %08x", d);
            break;
        case 0x18:
            V6M_INFO("P: LPC_MRT->CTRL1 << %08x", d);
            break;
        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) {
    int pin = -1;
    switch(a&0xff) {
        case 0x00: pio0_17 = d; pin = 17; break;
        case 0x04: pio0_13 = d; pin = 13; break;
        case 0x08: pio0_12 = d; pin = 12; break;
        case 0x0c: pio0_5 = d; pin = 5; break;
        case 0x10: pio0_3 = d; pin = 3; break;
        case 0x14: pio0_4 = d; pin = 4; break;
        case 0x18: pio0_2 = d; pin = 2; break;
        case 0x1c: pio0_11 = d; pin = 11; break;
        case 0x20: pio0_10 = d; pin = 10; break;
        case 0x24: pio0_16 = d; pin = 16; break;
        case 0x28: pio0_15 = d; pin = 15; break;
        case 0x2c: pio0_1 = d; pin = 1; break;
        case 0x34: pio0_9 = d; pin = 9; break;
        case 0x38: pio0_8 = d; pin = 8; break;
        case 0x3c: pio0_7 = d; pin = 7; break;
        case 0x40: pio0_6 = d; pin = 6; break;
        case 0x44: pio0_0 = d; pin = 0; break;
        case 0x48: pio0_14 = d; pin = 14; break;
    }
    if (pin >= 0) {
        V6M_INFO("P: LPC_IOCON->PIO0_%d << %04x", pin, d);
    } else {
        V6M_WARN("P: LPC_IOCON %08x << %04x", a, d);
    }
}

uint32_t EMU81x_IOCON::peek32(uint32_t a) {
    int pin = -1;
    uint32_t d = 0x00;
    switch(a&0xff) {
        case 0x00: d = pio0_17; pin = 17; break;
        case 0x04: d = pio0_13; pin = 13; break;
        case 0x08: d = pio0_12; pin = 12; break;
        case 0x0c: d = pio0_5; pin = 5; break;
        case 0x10: d = pio0_3; pin = 3; break;
        case 0x14: d = pio0_4; pin = 4; break;
        case 0x18: d = pio0_2; pin = 2; break;
        case 0x1c: d = pio0_11; pin = 11; break;
        case 0x20: d = pio0_10; pin = 10; break;
        case 0x24: d = pio0_16; pin = 16; break;
        case 0x28: d = pio0_15; pin = 15; break;
        case 0x2c: d = pio0_1; pin = 1; break;
        case 0x34: d = pio0_9; pin = 9; break;
        case 0x38: d = pio0_8; pin = 8; break;
        case 0x3c: d = pio0_7; pin = 7; break;
        case 0x40: d = pio0_6; pin = 6; break;
        case 0x44: d = pio0_0; pin = 0; break;
        case 0x48: d = pio0_14; pin = 14; break;
    }
    if (pin >= 0) {
        V6M_INFO("P: LPC_IOCON->PIO0_%d >> %04x", pin, d);
    } else {
        V6M_WARN("P: LPC_IOCON %08x >> %04x", a, d);
    }
    return d;
}

EMU81x_SYSCON::EMU81x_SYSCON() {
}

void EMU81x_SYSCON::poke32(uint32_t a, uint32_t d) {
    switch(a&0xfff) {
        case 0x004:
            V6M_INFO("P: LPC_SYSCON->PRESETCTRL << %08x", d);
            break;
        case 0x008:
            V6M_INFO("P: LPC_SYSCON->SYSPLLCTRL << %08x", d);
            break;
        case 0x040:
            V6M_INFO("P: LPC_SYSCON->SYSPLLCLKSEL << %08x", d);
            break;
        case 0x044:
            V6M_INFO("P: LPC_SYSCON->SYSPLLCLKUEN << %08x", d);
            break;
        case 0x070:
            V6M_INFO("P: LPC_SYSCON->MAINCLKSEL << %08x", d);
            break;
        case 0x074:
            V6M_INFO("P: LPC_SYSCON->MAINCLKUEN << %08x", d);
            break;
        case 0x078:
            V6M_INFO("P: LPC_SYSCON->SYSAHBCLKDIV << %08x", d);
            break;
        case 0x080:
            V6M_INFO("P: LPC_SYSCON->SYSAHBCLKCTRL << %08x", d);
            break;
        case 0x094:
            V6M_INFO("P: LPC_SYSCON->UARTCLKDIV << %08x", d);
            break;
        case 0x238:
            V6M_INFO("P: LPC_SYSCON->PDRUNCFG << %08x", d);
            break;
        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) {
        case 0x004:
            V6M_INFO("P: LPC_SYSCON->PRESETCTRL >> %08x", a, d);
            break;
        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;
         case 0x080:
            V6M_INFO("P: LPC_SYSCON->SYSAHBCLKCTRL >> %08x", a, d);
            break;
        case 0x238:
            V6M_INFO("P: LPC_SYSCON->PDRUNCFG >> %08x", d);
            break;
        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) {
                    i2c_size = 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 < i2c_size) {
                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;
        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:
                    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));

}