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-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)); }