mbed LPC812 emulator pre-alpha version
Dependencies: BaseV6M mbed F12RFileSystem F32RFileSystem ROMSLOT SDStorage
Example
TTB_mbed_LPC812.bin save as "LPC812.IMG" .
internal boot rom image(0x1fff0000-0x1fff1fff) save as "LPC812.ROM".
Tested programs
- TTB_mbed - TOYOSHIKI TINY BASIC mbed Edition
- mbed_blinky - LED1 blinky
EMU81x.cpp
- Committer:
- va009039
- Date:
- 2015-08-12
- Revision:
- 2:3f3637d7c2bc
- Parent:
- 1:913dfd59e25a
File content as of revision 2:3f3637d7c2bc:
// 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)); }