mbed LPC1114 emulator pre-alpha version

Dependencies:   BaseV6M mbed F12RFileSystem F32RFileSystem ROMSLOT SDStorage

Fork of emu812 by Norimasa Okamoto

480
TOYOSHIKI TINY BASIC mbed Edition TTB_mbed_LPC1114.bin save as "LPC1114.IMG" .

EMU111x.cpp

Committer:
va009039
Date:
2016-04-09
Revision:
9:ef9a58221fbe
Parent:
4:6629544a482e

File content as of revision 9:ef9a58221fbe:

// EMU111x.cpp 2015/8/19
#include "mbed.h"
#include "EMU111x.h"
#define V6M_LOG_LEVEL 2
#include "v6m_log.h"

const int EMU111x_RAM_SIZE = (1024*4);
const int EMU111x_FLASH_SIZE = (1024*32);
const int EMU111x_ROM_SIZE = (1024*16);

const uint32_t EMU111x_FLASH_BASE = 0x00000000;
const uint32_t EMU111x_RAM_BASE =   0x10000000;
const uint32_t EMU111x_ROM_BASE =   0x1fff0000;
const uint32_t EMU111x_APB_BASE =   0x40000000;
const uint32_t EMU111x_AHB_BASE =   0x50000000;
const uint32_t EMU111x_SCS_BASE =   0xe000e000;

EMU111x_SYSCON::EMU111x_SYSCON() {
}

void EMU111x_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(0x000, SYSMEMREMAP);
        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, SSP0CLKDIV);
        c(0x098, UARTCLKDIV);
        c(0x238, PDRUNCFG);
        #undef c
        default:
            V6M_WARN("P: LPC_SYSCON %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU111x_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(0x000, SYSMEMREMAP);
        c(0x004, PRESETCTRL);
        case 0x00c:
            d = 0x01;
            V6M_INFO("P: LPC_SYSCON->SYSPLLSTAT >> %08x", a, d);
            break;
        case 0x044:
            d = 0x01;
            V6M_INFO("P: LPC_SYSCON->SYSPLLCLKUEN >> %08x", a, d);
            break;
        case 0x074:
            d = 0x01;
            V6M_INFO("P: LPC_SYSCON->MAINCLKUEN >> %08x", a, d);
            break;
        c(0x080, SYSAHBCLKCTRL);
        c(0x238, PDRUNCFG);
        #undef c
        default:
            V6M_WARN("P: LPC_SYSCON %08x >> %08x", a, d);
            break;
    }
    return d;
}

EMU111x_IOCON::EMU111x_IOCON() {
    PIO0_4 = 0xd0;
    PIO0_5 = 0xd0;
    PIO0_6 = 0xd0;
    PIO0_7 = 0xd0;
    PIO0_8 = 0xd0;
    PIO0_9 = 0xd0;
    R_PIO0_11 = 0xd0;
    SCK_LOC = 0x00;
}

void EMU111x_IOCON::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        #define c(V,PIN) case V: PIN = d; V6M_INFO("P: LPC_IOCON->%s << %08x", #PIN, d); break;
        c(0x30, PIO0_4);
        c(0x34, PIO0_5);
        c(0x4c, PIO0_6);
        c(0x50, PIO0_7);
        c(0x60, PIO0_8);
        c(0x64, PIO0_9);
        c(0x74, R_PIO0_11);
        c(0xa0, PIO1_5);
        c(0xa4, PIO1_6);
        c(0xa8, PIO1_7);
        c(0xb0, SCK_LOC);
        #undef c
        default: V6M_WARN("P: LPC_IOCON %08x << %08x", a, d); break;
    }
}

uint32_t EMU111x_IOCON::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a&0xff) {
        #define c(V,PIN) case V: d = PIN; V6M_INFO("P: LPC_IOCON->%s >> %08x", #PIN, d); break;
        c(0x30, PIO0_4);
        c(0x34, PIO0_5);
        c(0x4c, PIO0_6);
        c(0x50, PIO0_7);
        c(0x60, PIO0_8);
        c(0x64, PIO0_9);
        c(0x74, R_PIO0_11);
        c(0xa0, PIO1_5);
        c(0xa4, PIO1_6);
        c(0xa8, PIO1_7);
        c(0xb0, SCK_LOC);
        #undef c
        default: V6M_WARN("P: LPC_IOCON %08x >> %08x", a, d); break;
    }
    return d;
}

EMU111x_GPIO::EMU111x_GPIO(EMU111x& mcu_, int port_):mcu(mcu_),port(port_) {
    data = 0x00;
    dir = 0x00;
}

void EMU111x_GPIO::poke32(uint32_t a, uint32_t d) {
    switch(a&0xffff) {
        case 0x3ffc:
            data = d;
            for(int pin = 0; pin < 12; pin++) {
                uint32_t mask = 1UL<<pin;
                if (dir & mask) { // output
                    mcu.DigitalWrite_Callback(port, pin, (d&mask) ? 1 : 0);
                }
            }
            V6M_INFO("P: LPC_GPIO%d->DATA %08x << %08x", port, a, d);
            break;
        case 0x8000:
            dir = d;
            V6M_INFO("P: LPC_GPIO%d->DIR << %08x", port, d);
            break;
        default:
            V6M_WARN("P: LPC_GPIO%d %08x << %08x", port, a, d);
            break;
    }
}

static int pinpos(uint32_t data) {
    for(int pin = 0; pin < 12; pin++) {
        if (data & (1UL<<pin)) {
            return pin;
        }
    }
    return 0;
}

uint32_t EMU111x_GPIO::peek32(uint32_t a) {
    uint32_t d = 0x00;
    if ((a&0xffff) < 0x3ffc) {
        uint32_t mask = (a>>2)&0xfff;
        int pin = pinpos(mask);
        if (dir & mask) { // output
            d = data & mask;
        } else { // input
            if (mcu.DigitalRead_Callback(port, pin)) {
                d = mask;
            }
        }
        V6M_INFO("P: LPC_GPIO%d->MASKED_ACCESS[%03x] >> %08x", port, mask, d);
        return d;
    }
    switch(a&0xffff) {
        case 0x3ffc:
            d = data;
            V6M_INFO("P: LPC_GPIO%d->DATA >> %08x", port, d);
            break;
        case 0x8000:
            d = dir;
            V6M_INFO("P: LPC_GPIO%d->DIR >> %08x", port, d);
            break;
        default:
            V6M_WARN("P: LPC_GPIO%d %08x >> %08x", port, a, d);
            break;
    }
    return d;
}

EMU111x_TMR32B::EMU111x_TMR32B(int ch_):ch(ch_) {
    V6M_ASSERT(ch == 0 || ch == 1);
    tc = 0;
}

void EMU111x_TMR32B::clock_in(uint32_t n) {
    V6M_ASSERT(n != 0);
    tc += n;
}

void EMU111x_TMR32B::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        case 0x04:
            V6M_INFO("P: LPC_TMR32B->TCR << %08x", d);
            break;
        case 0x0c:
            V6M_INFO("P: LPC_TMR32B->PR << %08x", d);
            break;
        default:
            V6M_WARN("P: LPC_TMR32B %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU111x_TMR32B::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a&0xff) {
        case 0x08:
            d = tc;
            V6M_INFO("P: LPC_TMR32B%d->TC >> %u", ch, d);
            break;
        default:
            V6M_WARN("P: LPC_TMR32B%d %08x >> %02x", ch, a, d);
            break;
    }
    return d;
}

EMU111x_UART::EMU111x_UART(EMU111x& mcu_):mcu(mcu_) {
    LCR = 0x00;
}

void EMU111x_UART::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        case 0x00:
            if (LCR & 0x80) { // DLAB=1
                V6M_INFO("P: LPC_UART->DLL << %08x", d);
            } else { // DLAB=0
                mcu.SerialPutc_Callback(0, d);
                V6M_INFO("P: LPC_UART->THR << %08x", d);
            }
            break;
        case 0x04:
            V6M_INFO("P: LPC_UART->IER << %08x", d);
            break;
        case 0x08:
            V6M_INFO("P: LPC_UART->FCR << %08x", d);
            break;
        case 0x0c:
            LCR = d;
            V6M_INFO("P: LPC_UART->LCR << %08x", d);
            break;
        case 0x28:
            FDR = d;
            V6M_INFO("P: LPC_UART->FDR << %08x", d);
            break;
        default:
            V6M_WARN("P: LPC_UART %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU111x_UART::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a&0xff) {
        case 0x00:
            if (LCR & 0x80) { // DLAB=1
                V6M_INFO("P: LPC_UART->DLL >> %08x", d);
            } else {
                d = mcu.SerialGetc_Callback(0);
                V6M_INFO("P: LPC_UART->RBR >> %08x", d);
            }
            break;
        case 0x0c:
            d = LCR;
            V6M_INFO("P: LPC_UART->LCR >> %08x", d);
            break;
        case 0x14:
            d = 0x20;
            if (mcu.SerialReadable_Callback(0)) {
                d |= 0x01;
            }
            V6M_INFO("P: LPC_UART->LSR >> %08x", d);
            break;
        default:
            V6M_WARN("P: LPC_UART %08x >> %08x", a, d);
            break;
    }
    return d;
}

EMU111x_I2C::EMU111x_I2C(EMU111x& mcu_):mcu(mcu_) {
    con = 0;
    stat = 0xf8;
}

void EMU111x_I2C::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        case 0x00: // CONSET
            if (d == 0x40) {
                con = 0x40;
            } else if (d == 0x24) { // start
                con = 0x48;
                stat = 0x10;
            } else if (d == 0x10) { // stop
                if ((i2c_addr&0x01) == 0x00) {
                    mcu.I2CWrite_Callback(i2c_addr, i2c_data, i2c_pos);
                }
            } else {
                V6M_ASSERT(0);
            }
            V6M_INFO("P: LPC_I2C->CONSET << %08x", d);
            break;
        case 0x08: // DAT
            if (stat == 0x10) { // start
                i2c_addr = d & 0xff;
                i2c_pos = 0;
                if (i2c_addr & 0x01) {
                    mcu.I2CRead_Callback(i2c_addr, i2c_data, sizeof(i2c_data));
                    stat = 0x40;
                    i2c_pos = 0;
                } else {
                    stat = 0x18;
                }
            } else {
                if (i2c_pos < sizeof(i2c_data)) {
                    i2c_data[i2c_pos++] = d & 0xff;
                }
                stat = 0x18;
            }
            V6M_INFO("P: LPC_I2C->DAT << %08x", d);
            break;
        case 0x10:
            V6M_INFO("P: LPC_I2C->SCLH << %08x", d);
            break;
        case 0x14:
            V6M_INFO("P: LPC_I2C->SCLL << %08x", d);
            break;
        case 0x18:
            V6M_INFO("P: LPC_I2C->CONCLR << %08x", d);
            break;
        default:
            V6M_WARN("P: LPC_I2C %08x << %08x", a, d);
            break;
    }
}

uint32_t EMU111x_I2C::peek32(uint32_t a) {
    uint32_t d = 0x00000000;
    switch(a&0xff) {
        case 0x00:
            d = con;
            V6M_INFO("P: LPC_I2C->CON >> %08x", d);
            break;
        case 0x04:
            d = stat;
            V6M_INFO("P: LPC_I2C->STAT >> %08x", d);
            break;
        case 0x08:
            if (i2c_pos < sizeof(i2c_data)) {
                d = i2c_data[i2c_pos++];
            }
            if (i2c_pos < sizeof(i2c_data)) {
                stat = 0x50;
            } else {
                stat = 0x58;
            }
            V6M_INFO("P: LPC_I2C->DAT >> %08x", d);
            break;
        default:
            V6M_WARN("P: LPC_I2C %08x >> %08x", a, d);
            break;
    }
    return d;
}

EMU111x_SPI::EMU111x_SPI(EMU111x& mcu_, int ch_):mcu(mcu_),ch(ch_) {
    cr0 = 0;
    cr1 = 0;
}

void EMU111x_SPI::poke32(uint32_t a, uint32_t d) {
    switch(a&0xff) {
        case 0x00:
            cr0 = d;
            V6M_INFO("P: LPC_SPI%d->CR0 << %08x", ch, d);
            break;
        case 0x04:
            cr1 = d;
            V6M_INFO("P: LPC_SPI%d->CR1 << %08x", ch, d);
            break;
        case 0x08:
            dr = mcu.SPIWrite_Callback(ch, d);
            V6M_INFO("P: LPC_SPI%d->DR << %08x", ch, d);
            break;
        case 0x10:
            V6M_INFO("P: LPC_SPI%d->CPSR << %08x", ch, d);
            break;
        default:
            V6M_WARN("P: LPC_SPI%d %08x << %08x", ch, a, d);
            break;
    }
}

uint32_t EMU111x_SPI::peek32(uint32_t a) {
    uint32_t d = 0;
    switch(a&0xff) {
        case 0x00:
            d = cr0;
            V6M_INFO("P: LPC_SPI%d->CR0 >> %08x", ch, d);
            break;
        case 0x04:
            d = cr1;
            V6M_INFO("P: LPC_SPI%d->CR1 >> %08x", ch, d);
            break;
        case 0x08:
            d = dr;
            V6M_INFO("P: LPC_SPI%d->DR >> %08x", ch, d);
            break;
        case 0x0c:
            d = 0x06;
            V6M_INFO("P: LPC_SPI%d->SR >> %08x", ch, d);
            break;
        default:
            V6M_WARN("P: LPC_SPI%d %08x >> %08x", ch, a, d);
            break;
    }
    return d;
}

void EMU111x_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;
    }
}

EMU111x::EMU111x():tmr32b1(1),_uart(*this),_i2c(*this),_spi0(*this,0),_spi1(*this,1),gpio0(*this,0),gpio1(*this,1) {
    flash = NULL;
    rom = NULL;
    ram = new uint8_t[EMU111x_RAM_SIZE];
}

void EMU111x::poke32(uint32_t a, uint32_t d) {
    switch(a>>24) {
        case EMU111x_RAM_BASE>>24:
            V6M_ASSERT(a < (EMU111x_RAM_BASE+EMU111x_RAM_SIZE));
            ram[a - EMU111x_RAM_BASE] = d;
            ram[a - EMU111x_RAM_BASE + 1] = d>>8;
            ram[a - EMU111x_RAM_BASE + 2] = d>>16;
            ram[a - EMU111x_RAM_BASE + 3] = d>>24;
            V6M_INFO("W: %08x << %08x", a, d);
            break;
        case EMU111x_APB_BASE>>24:
            switch((a>>12)&0xff) {
                case 0x00: _i2c.poke32(a, d); break;
                case 0x08: _uart.poke32(a, d); break;
                case 0x18: tmr32b1.poke32(a, d); break;
                case 0x40: _spi0.poke32(a, d); break;
                case 0x44: iocon.poke32(a, d); break;
                case 0x48: syscon.poke32(a, d); break;
                case 0x58: _spi1.poke32(a, d); break;
                default:
                    V6M_WARN("P: %08x << %08x", a, d);
                    break;
            }
            break;
        case EMU111x_AHB_BASE>>24:
            switch((a>>16)&0xff) {
                case 0: gpio0.poke32(a, d); break;
                case 1: gpio1.poke32(a, d); break;
                default:
                    V6M_ERROR("P: %08x << %08x", a, d);
                    break;
            }
            break;
        case EMU111x_FLASH_BASE>>24:
        case EMU111x_ROM_BASE>>24:
            V6M_ERROR("P: %08x << %08x", a, d);
            V6M_ASSERT(0);
            break;
        case EMU111x_SCS_BASE>>24:
            switch(a&0xffffff) {
                case 0x00e100:
                    nvic.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 EMU111x::peek32(uint32_t a) {
    uint32_t d = 0x00;
    switch(a>>24) {
        case EMU111x_RAM_BASE>>24:
            V6M_ASSERT(a < (EMU111x_RAM_BASE+EMU111x_RAM_SIZE));
            d = ram[a - EMU111x_RAM_BASE];
            d |= ram[a - EMU111x_RAM_BASE + 1]<<8;
            d |= ram[a - EMU111x_RAM_BASE + 2]<<16;
            d |= ram[a - EMU111x_RAM_BASE + 3]<<24;
            V6M_INFO("R: %08x >> %08x", a, d);
            break;
        case EMU111x_FLASH_BASE>>24:
            V6M_ASSERT(a < (EMU111x_FLASH_BASE+EMU111x_FLASH_SIZE));
            d = flash[a - EMU111x_FLASH_BASE];
            d |= flash[a - EMU111x_FLASH_BASE + 1]<<8;
            d |= flash[a - EMU111x_FLASH_BASE + 2]<<16;
            d |= flash[a - EMU111x_FLASH_BASE + 3]<<24;
            break;
        case EMU111x_ROM_BASE>>24:
            V6M_ERROR("P: %08x << %08x", a, d);
            V6M_ASSERT(0);
            break;
        case EMU111x_APB_BASE>>24:
            switch((a>>12)&0xff) {
                case 0x00: d = _i2c.peek32(a); break;
                case 0x08: d = _uart.peek32(a); break;
                case 0x18: d = tmr32b1.peek32(a); break;
                case 0x40: d = _spi0.peek32(a); break;
                case 0x44: d = iocon.peek32(a); break;
                case 0x48: d = syscon.peek32(a); break;
                case 0x58: d = _spi1.peek32(a); break;
                default:
                    V6M_WARN("P: %08x >> %08x", a, d);
                    break;
            }
            break;
        case EMU111x_AHB_BASE>>24:
            switch((a>>16)&0xff) {
                case 0: d = gpio0.peek32(a); break;
                case 1: d = gpio1.peek32(a); break;
                default:
                    V6M_ERROR("P: %08x >> %08x", a, d);
                    break;
            }
            break;
        default:
            V6M_WARN("P: %08x >> %08x", a, d);
            break;
    }
    return d;
}

void EMU111x::poke8(uint32_t a, uint8_t d) {
    switch(a>>24) {
        case EMU111x_RAM_BASE>>24:
            V6M_ASSERT(a < (EMU111x_RAM_BASE+EMU111x_RAM_SIZE));
            ram[a - EMU111x_RAM_BASE] = d;
            V6M_INFO("W: %08x << %02x", a, d);
            break;
        default:
            V6M_ERROR("P: %08x << %02x", a, d);
            //V6M_ASSERT(0);
            break;
    }
}

uint8_t EMU111x::peek8(uint32_t a) {
    uint8_t d = 0x00;
    switch(a>>24) {
        case EMU111x_RAM_BASE>>24:
            V6M_ASSERT(a < (EMU111x_RAM_BASE+EMU111x_RAM_SIZE));
            d = ram[a - EMU111x_RAM_BASE];
            V6M_INFO("R: %08x >> %02x", a, d);
            break;
        case EMU111x_FLASH_BASE>>24:
            V6M_ASSERT(a < (EMU111x_FLASH_BASE+EMU111x_FLASH_SIZE));
            d = flash[a - EMU111x_FLASH_BASE];
            break;
        case EMU111x_ROM_BASE>>24:
            V6M_ASSERT(a < (EMU111x_ROM_BASE+EMU111x_ROM_SIZE));
            d = flash[a - EMU111x_ROM_BASE];
            break;
        default:
            V6M_WARN("R: %08x >> %02x", a, d);
            //V6M_ASSERT(0);
            break;
    }
    return d;
}

void EMU111x::clock_in(uint32_t n) {
    tmr32b1.clock_in(n);
}

void EMU111x::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));
}