--- /dev/null
+SOURCES += \
+ memory_conf.cpp
+
+HEADERS += \
+ memory_conf.h
--- /dev/null
+#include "asic14.h"
+
+namespace SA1100 {
+
+ ASIC14::ASIC14() {
+ init_register();
+ }
+
+ void ASIC14::reset() {
+ m_CTRL0 = 0;
+ m_KBD_PADR = 0;
+ m_CTRL_STATUS = 0;
+ m_POWER = 0;
+ m_STATUS = 0;
+ m_STATUS4 = 0;
+ m_CONTRAST = 0;
+ m_BRIGHTNESS = 0;
+ m_IRQ_STATUS = 0;
+ m_IRQ_MASK = 0xffff;
+ m_STATUS3 = 0;
+ m_KBD_SCAN = 0;
+ m_IRQ_EDGE = 0;
+ m_SPI_DATA = 0;
+ m_SPI_FN = 0;
+ }
+
+ void ASIC14::run() {}
+
+ uint16_t ASIC14::get_data(uint32_t const address) const {
+ switch (address) {
+ case CTRL0:
+ printf("ASIC14 read register CTRL0: %04x\n", m_CTRL0);
+ return m_CTRL0;
+ case KBD_PADR:
+ printf("ASIC14 read register KBD_PADR: %04x\n", m_KBD_PADR);
+ return m_KBD_PADR;
+ case CTRL_STATUS:
+ printf("ASIC14 read register CTRL_STATUS: %04x\n", m_CTRL_STATUS);
+ return m_CTRL_STATUS;
+ case POWER:
+ printf("ASIC14 read register POWER: %04x\n", m_POWER);
+ return m_POWER;
+ case STATUS4:
+ printf("ASIC14 read register STATUS4: %04x\n", m_STATUS4);
+ return m_STATUS4;
+ case CONTRAST:
+ printf("ASIC14 read register CONTRAST: %04x\n", m_CONTRAST);
+ return m_CONTRAST;
+ case BRIGHTNESS:
+ printf("ASIC14 read register BRIGHTNESS: %04x\n", m_BRIGHTNESS);
+ return m_BRIGHTNESS;
+ case IRQ_STATUS:
+ printf("ASIC14 read register IRQ_STATUS: %04x\n", m_IRQ_STATUS);
+ return m_IRQ_STATUS;
+ case IRQ_MASK:
+ printf("ASIC14 read register IRQ_MASK: %04x\n", m_IRQ_MASK);
+ return m_IRQ_MASK;
+ case STATUS3:
+ printf("ASIC14 read register STATUS3: %04x\n", m_STATUS3);
+ return m_STATUS3;
+ case KBD_SCAN:
+ printf("ASIC14 read register KBD_SCAN: %04x\n", m_KBD_SCAN);
+ return m_KBD_SCAN;
+ case IRQ_EDGE:
+ printf("ASIC14 read register IRQ_EDGE: %04x\n", m_IRQ_EDGE);
+ return m_IRQ_EDGE;
+ case STATUS6:
+ printf("ASIC14 read register STATUS6: %04x\n", m_STATUS6);
+ return m_STATUS6 | 2;
+ case SPI_DATA:
+ printf("ASIC14 read register SPI_DATA: %04x\n", m_SPI_DATA);
+ return m_SPI_DATA;
+ case SPI_FN:
+ printf("ASIC14 read register SPI_FN: %04x\n", m_SPI_FN);
+ return m_SPI_FN;
+ default:
+ printf("Unknown ASIC14 register requested %08x\n", address);
+ return 0;
+ }
+ }
+
+ void ASIC14::put_data(uint32_t const address, uint16_t const value) {
+ switch (address) {
+ case CTRL0:
+ printf("ASIC14 write %04x to register CTRL0\n", value);
+ m_CTRL0 = value;
+ break;
+ case KBD_PADR:
+ printf("ASIC14 write %04x to register KBD_PADR\n", value);
+ m_KBD_PADR = value;
+ break;
+ case CTRL_STATUS:
+ printf("ASIC14 write %04x to register CTRL_STATUS\n", value);
+ m_CTRL_STATUS = value;
+ break;
+ case POWER:
+ printf("ASIC14 write %04x to register POWER\n", value);
+ m_POWER = value;
+ break;
+ case STATUS4:
+ printf("ASIC14 write %04x to register STATUS4\n", value);
+ m_STATUS4 &= ~value;
+ break;
+ case CONTRAST:
+ printf("ASIC14 write %04x to register CONTRAST\n", value);
+ m_CONTRAST = value;
+ break;
+ case BRIGHTNESS:
+ printf("ASIC14 write %04x to register BRIGHTNESS\n", value);
+ m_BRIGHTNESS = value;
+ break;
+ case IRQ_STATUS:
+ printf("ASIC14 write %04x to register IRQ_STATUS\n", value);
+ m_IRQ_STATUS = value;
+ break;
+ case IRQ_MASK:
+ printf("ASIC14 write %04x to register IRQ_MASK\n", value);
+ m_IRQ_MASK = value;
+ break;
+ case STATUS3:
+ printf("ASIC14 write %04x to register STATUS3\n", value);
+ m_STATUS3 &= ~value;
+ break;
+ case KBD_SCAN:
+ printf("ASIC14 write %04x to register KBD_SCAN\n", value);
+ m_KBD_SCAN = value;
+ break;
+ case IRQ_EDGE:
+ printf("ASIC14 write %04x to register IRQ_EDGE\n", value);
+ m_IRQ_EDGE = value;
+ break;
+ case STATUS6:
+ printf("ASIC14 write %04x to register STATUS6\n", value);
+ // Clear interrupts on STATUS6 according to the bit mask provided
+ m_STATUS6 &= ~value;
+ break;
+ case SPI_DATA:
+ printf("ASIC14 write %04x to register SPI_DATA\n", value);
+ m_SPI_DATA = value;
+ break;
+ case SPI_FN:
+ printf("ASIC14 write %04x to register SPI_FN\n", value);
+ m_SPI_FN = value;
+ break;
+ default:
+ printf("ASIC14 write %04x to unknown register %08x\n", value, address);
+ break;
+ }
+ return;
+ }
+
+} // namespace SA1100
--- /dev/null
+#ifndef ASIC14_H
+#define ASIC14_H
+
+#include <stdint.h>
+
+#include "gpio_controller.h"
+#include "lcd_controller.h"
+#include "os_timer.h"
+#include "serial_3.h"
+#include "uart.h"
+
+// An implementation of ASIC14 from the Psion netBook.
+// This is mapped into the 0x10000000 address space and
+// appears to handle power/battery status, CF/PCMCIA power,
+// two timers, LCD brightness/contrast and their associated
+// interrupts.
+
+namespace SA1100 {
+
+class ASIC14 {
+ public:
+ enum IRQMaskEnum
+ {
+ IRQ_TIMER0 = (1<<0),
+ IRQ_TIMER1 = (1<<1),
+ IRQ_Rx = (1<<2),
+ IRQ_Tx = (1<<3),
+ IRQ_E2PROM = (1<<4),
+ IRQ_Rx_OVERRUN = (1<<5),
+ IRQ_E2PROM_ERR = (1<<6),
+ IRQ_ADC = (1<<7),
+ IRQ_PCMCIA = (1<<9),
+ // Bit 8?
+ IRQ_CFCARD = (1<<10),
+ // Bits 11 and 12 are expansion interrupts?
+ IRQ_CFCARD_CHANGE = (1<<13),
+ IRQ_PCMCIA_CHANGE = (1<<14),
+ IRQ_PEN = (1<<15)
+ };
+ typedef enum IRQMaskEnum IRQMaskEnum;
+
+ private:
+ enum
+ {
+ CTRL0 = 0x10000000,
+ KBD_PADR = 0x10000004,
+ CTRL_STATUS = 0x10000006,
+ POWER = 0x10000008,
+ STATUS = 0x1000000a,
+ STATUS4 = 0x10000012,
+ CONTRAST = 0x10000016,
+ BRIGHTNESS = 0x10000018,
+ IRQ_STATUS = 0x1000002a,
+ IRQ_MASK = 0x1000002c,
+ STATUS3 = 0x1000002e,
+ KBD_SCAN = 0x10000030,
+ IRQ_EDGE = 0x10000032,
+ STATUS6 = 0x10000040,
+ SPI_DATA = 0x10000048,
+ SPI_FN = 0x1000004c
+ };
+
+ uint16_t m_CTRL0;
+ uint16_t m_KBD_PADR;
+ uint16_t m_CTRL_STATUS;
+ uint16_t m_POWER;
+ uint16_t m_STATUS;
+ uint16_t m_STATUS4;
+ uint16_t m_CONTRAST;
+ uint16_t m_BRIGHTNESS;
+ uint16_t m_IRQ_STATUS;
+ uint16_t m_IRQ_MASK;
+ uint16_t m_STATUS3;
+ uint16_t m_KBD_SCAN;
+ uint16_t m_IRQ_EDGE;
+ uint16_t m_STATUS6;
+ uint16_t m_SPI_DATA;
+ uint16_t m_SPI_FN;
+
+ void init_register() {
+ m_CTRL0 = 0;
+ m_KBD_PADR = 0;
+ m_CTRL_STATUS = 0;
+ m_POWER = 0;
+ m_STATUS = 0;
+ m_STATUS4 = 0;
+ m_CONTRAST = 0;
+ m_BRIGHTNESS = 0;
+ m_IRQ_STATUS = 0;
+ m_IRQ_MASK = 0;
+ m_STATUS3 = 0;
+ m_KBD_SCAN = 0;
+ m_IRQ_EDGE = 0;
+ m_SPI_DATA = 0;
+ m_SPI_FN = 0;
+ }
+
+ public:
+ ASIC14();
+
+ void run();
+ void reset();
+
+ uint16_t get_data(uint32_t const address) const;
+
+ void put_data(uint32_t const address, uint16_t const value);
+};
+
+} // namespace SA1100
+
+#endif // ASIC14_H
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "gpio_controller.h"
+
+namespace SA1100 {
+ void GPIOController::reset() {
+ m_GPLR &= 0xFFFFFFF;
+ m_GEDR &= 0xFFFFFFF;
+ m_GPDR = 0;
+ m_GAFR = 0;
+
+ release_action_button();
+
+ m_GPLR_backup = m_GPLR;
+ }
+
+ uint32_t GPIOController::get_data(uint32_t const address) const {
+ switch (address) {
+ case GPLR:
+ return m_GPLR;
+ case GPDR:
+ return m_GPDR;
+ case GPSR:
+ case GPCR:
+ // :SA-1110 Developer's Manual: p.77: Wei 2004-Jun-05:
+ //
+ // GPSR & GPCR are write-only registers.
+ return 0;
+ case GRER:
+ return m_GRER;
+ case GFER:
+ return m_GFER;
+ case GEDR:
+ return m_GEDR;
+ case GAFR:
+ return m_GAFR;
+ default:
+ return 0;
+ }
+ }
+
+ void GPIOController::put_data(uint32_t const address, uint32_t const value) {
+ switch (address) {
+ case GPLR:
+ // :SA-1110 Developer's Manual: p.75: Wei 2004-Jun-05:
+ //
+ // GPLR is a read-only register.
+ break;
+ case GPDR:
+ // :SA-1110 Developer's Manual: p.233: Wei 2004-Jun-06:
+ //
+ // In active mode, GPIO pins 2..9 are also used.
+ // Note that the user must configure GPIO pins 2..9 as outputs (for 16-bit/pixel mode)
+ // by setting the appropriate bits within the GPIO pin direction register (GPDR)
+ // and GPIO alternate function register (GAFR).
+ //
+ // :NOTE: Wei 2004-Jun-06:
+ //
+ // ARMware supports only TFT (active) mode now.
+ //assert(LDD_BITS == (value & LDD_BITS));
+
+ // :SA-1110 Developer's Manual: p.76: Wei 2004-Jun-05:
+ //
+ // The upper 4 bits are always 0.
+ m_GPDR = (value & 0xFFFFFFF);
+ break;
+
+ case GPSR:
+ {
+ // Determine what pins are configured as output and we want to set it value now.
+ uint32_t const temp = (m_GPDR & (value & 0xFFFFFFF));
+ uint32_t const new_GPLR = m_GPLR | temp;
+ uint32_t const diff = m_GPLR ^ new_GPLR;
+
+ // Update GEDR
+ m_GEDR |= (m_GRER & (new_GPLR & diff));
+
+ // Update GPLR
+ m_GPLR = new_GPLR;
+ }
+ break;
+
+ case GPCR:
+ {
+ // Determine what pins are configured as output and we want to clear it value now.
+ uint32_t const temp = (m_GPDR & (value & 0xFFFFFFF));
+
+ // Update GEDR
+ m_GEDR |= (m_GFER & (m_GPLR & temp));
+
+ // Update GPLR
+
+ // :SA-1110 Developer's Manual: p.77: Wei 2004-Jul-1:
+ //
+ // To clear an output pin, a one is written to the corresponding bit within the GPCR.
+ m_GPLR &= ~temp;
+ }
+ break;
+
+ case GRER:
+ m_GRER = (value & 0xFFFFFFF);
+ break;
+
+ case GFER:
+ m_GFER = (value & 0xFFFFFFF);
+ break;
+
+ case GEDR:
+ // :SA-1110 Developer's Manual: p.79: Wei 2004-Jun-05:
+ //
+ // GEDR status bits are cleared by writing a one to them.
+ // Writing a zero to a GEDR status bit has no effect.
+ m_GEDR &= ~(value & 0xFFFFFFF);
+ break;
+
+ case GAFR:
+ // :SA-1110 Developer's Manual: p.233: Wei 2004-Jun-06:
+ //
+ // In active mode, GPIO pins 2..9 are also used.
+ // Note that the user must configure GPIO pins 2..9 as outputs (for 16-bit/pixel mode)
+ // by setting the appropriate bits within the GPIO pin direction register (GPDR)
+ // and GPIO alternate function register (GAFR).
+ //
+ // :NOTE: Wei 2004-Jun-06:
+ //
+ // ARMware supports only TFT (active) mode now.
+
+ // :SA-1110 Developer's Manual: p.80: Wei 2004-Jun-06:
+ //
+ // A bit set in this register indicates that the corresponding GPIO pin
+ // is to be used for its alternate function.
+ //assert(LDD_BITS == (value & LDD_BITS));
+
+ m_GAFR = (value & 0xFFFFFFF);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+} // namespace SA1100
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef GPIO_CONTROLLER_H
+#define GPIO_CONTROLLER_H
+#include <stdio.h>
+#include <stdint.h>
+
+namespace SA1100
+{
+
+class GPIOController {
+ private:
+
+ // Register location
+
+ enum {
+ GPLR = 0x90040000,
+ GPDR = 0x90040004,
+ GPSR = 0x90040008,
+ GPCR = 0x9004000C,
+ GRER = 0x90040010,
+ GFER = 0x90040014,
+ GEDR = 0x90040018,
+ GAFR = 0x9004001C
+ };
+
+ // Normal function
+
+ enum {
+ GAFR_ACTION_BUTTON = (1 << 18)
+ };
+
+ // Alternative function
+
+ enum {
+ LDD_8 = (1 << 2),
+ LDD_9 = (1 << 3),
+ LDD_10 = (1 << 4),
+ LDD_11 = (1 << 5),
+ LDD_12 = (1 << 6),
+ LDD_13 = (1 << 7),
+ LDD_14 = (1 << 8),
+ LDD_15 = (1 << 9),
+
+ LDD_BITS = (LDD_8 | LDD_9 | LDD_10 | LDD_11 | LDD_12 | LDD_13 | LDD_14 | LDD_15)
+ };
+
+ // Attribute
+
+ uint32_t m_GPLR; // GPIO pin-level register
+ uint32_t m_GPDR; // GPIO pin direction register
+ uint32_t m_GPSR; // GPIO pin output set register
+ uint32_t m_GPCR; // GPIO pin output clear register
+ uint32_t m_GRER; // GPIO rising-edge detect register
+ uint32_t m_GFER; // GPIO falling-edge detect register
+ uint32_t m_GEDR; // GPIO edge detect status register
+ uint32_t m_GAFR; // GPIO alternate function register
+
+ uint32_t m_GPLR_backup;
+
+ // Operation
+
+ void init_register() {
+ m_GPLR = 0;
+ m_GPDR = 0;
+ m_GPSR = 0;
+ m_GPCR = 0;
+ m_GRER = 0;
+ m_GFER = 0;
+ m_GEDR = 0;
+ m_GAFR = 0;
+ }
+
+ public:
+
+ // Life cycle
+
+ GPIOController() {
+ init_register();
+ }
+
+ // Operation
+
+ inline void run() {
+ uint32_t const temp = m_GPLR ^ m_GPLR_backup;
+
+ if (temp != 0) {
+ m_GEDR |= (m_GRER & (m_GPLR & temp));
+ m_GEDR |= (m_GFER & (m_GPLR_backup & temp));
+
+ m_GPLR_backup = m_GPLR;
+ }
+ }
+
+ void reset();
+
+ inline uint32_t get_interrupt_status() const { return m_GEDR; }
+
+ // :NOTE: Wei 2004-Jan-11:
+ //
+ // if bit 18 of GPLR == 0: action button is pressed.
+ // if bit 18 of GPLR == 1: action button is released.
+ inline void press_action_button() {
+ // :SA-1110 Developer's Manual: p.80: Wei 2004-Jul-1:
+ //
+ // A zero in GAFR indicates that the corresponding GPIO pin is to be used for its normal GPIO function.
+ if (0 == (m_GAFR & GAFR_ACTION_BUTTON))
+ {
+ m_GPLR &= ~GAFR_ACTION_BUTTON;
+ }
+ }
+ inline void flip_gpio() {
+ if (m_GPLR & 0x400) {
+ m_GPLR &= ~0x400;
+ } else {
+ m_GPLR |= 0x400;
+ }
+ }
+
+ inline void release_action_button() {
+ if (0 == (m_GAFR & GAFR_ACTION_BUTTON))
+ {
+ m_GPLR |= GAFR_ACTION_BUTTON;
+ }
+ }
+
+ uint32_t get_data(uint32_t const address) const;
+
+ void put_data(uint32_t const address, uint32_t const value);
+};
+
+} // namespace SA1100
+
+#endif // GPIO_CONTROLLER_H
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "interrupt_controller.h"
+
+namespace SA1100 {
+
+ IntController::IntController(LCDController* const lcdController,
+ OsTimer* const osTimer,
+ GPIOController* const gpioController,
+ Serial3* const serial3)
+ : mOsTimer(osTimer),
+ mLCDController(lcdController),
+ mGPIOController(gpioController),
+ mSerial3(serial3) {
+ init_register();
+ }
+
+ //============================== Operation ==================================
+
+ void IntController::reset() {
+ m_ICIP = 0;
+
+ // :NOTE: Wei 2004-Apr-25:
+ //
+ // Although the SA-1110 Developer's Manual doesn't specify whether ICFP will be
+ // initialized to 0 when reset. However, SA-1110 Developer's Manual does specify
+ // ICIP will be initialized to 0 when reset.
+ // Thus I _assume_ this is a bug in the SA-1110 Developer's Manual, and will do
+ // the initialization by my self.
+
+ // :NOTE: Wei 2004-Jul-20;
+ //
+ // It is really a bug.
+ // According to the Intel-StrongARM SA-1110 Microprocessor Specification Update
+ // (December 2001), p.37:
+ //
+ // Changed the reset values for the Interrupt Controller IRQ and FIQ Pending
+ // Registers (ICIP and ICFP) from undefined to 0.
+ m_ICFP = 0;
+
+ m_ICCR = 0;
+ //m_ICMR = ~0;
+
+ // :NOTE: Wei 2004-Jun-06:
+ //
+ // Althought there is no words in SA-1110 Developer's manual says that
+ // ICPR will be set to 0 when reset.
+ // However, I think it should set to 0 when reset to indicate that no
+ // pending interrupt exist.
+ m_ICPR = 0;
+ }
+
+ void IntController::run() {
+ // check GPIO interrupt
+
+ {
+ uint32_t const gpio_status = mGPIOController->get_interrupt_status();
+
+ if (gpio_status != 0)
+ {
+ m_ICPR &= ~GPIO_0_10_EDGE_BIT_MASK;
+ m_ICPR |= (gpio_status & GPIO_0_10_EDGE_BIT_MASK);
+
+ if ((gpio_status & ~GPIO_0_10_EDGE_BIT_MASK) != 0)
+ {
+ m_ICPR |= GPIO_11_27_EDGE_BIT_MASK;
+ }
+ else
+ {
+ m_ICPR &= ~GPIO_11_27_EDGE_BIT_MASK;
+ }
+ }
+ }
+
+ // check OS timer
+
+ {
+ uint32_t const os_timer_status = mOsTimer->get_interrupt_status();
+
+ switch (os_timer_status) {
+ case 0: // 0000
+ {
+ m_ICPR &= ~(OS_TIMER_0_BIT_MASK |
+ OS_TIMER_1_BIT_MASK |
+ OS_TIMER_2_BIT_MASK |
+ OS_TIMER_3_BIT_MASK);
+ }
+ break;
+
+ case OsTimer::OSMR0_MASK: // 0001
+ {
+ m_ICPR |= OS_TIMER_0_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_1_BIT_MASK |
+ OS_TIMER_2_BIT_MASK |
+ OS_TIMER_3_BIT_MASK);
+ }
+ break;
+
+ case OsTimer::OSMR1_MASK: // 0010
+ {
+ m_ICPR |= OS_TIMER_1_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_0_BIT_MASK |
+ OS_TIMER_2_BIT_MASK |
+ OS_TIMER_3_BIT_MASK);
+ }
+ break;
+
+ case (OsTimer::OSMR0_MASK |
+ OsTimer::OSMR1_MASK): // 0011
+ {
+ m_ICPR |= OS_TIMER_0_BIT_MASK;
+ m_ICPR |= OS_TIMER_1_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_2_BIT_MASK |
+ OS_TIMER_3_BIT_MASK);
+ }
+ break;
+
+ case OsTimer::OSMR2_MASK: // 0100
+ {
+ m_ICPR |= OS_TIMER_2_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_0_BIT_MASK |
+ OS_TIMER_1_BIT_MASK |
+ OS_TIMER_3_BIT_MASK);
+ }
+ break;
+
+ case (OsTimer::OSMR0_MASK |
+ OsTimer::OSMR2_MASK): // 0101
+ {
+ m_ICPR |= OS_TIMER_0_BIT_MASK;
+ m_ICPR |= OS_TIMER_2_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_1_BIT_MASK |
+ OS_TIMER_3_BIT_MASK);
+ }
+ break;
+
+ case (OsTimer::OSMR1_MASK |
+ OsTimer::OSMR2_MASK): // 0110
+ {
+ m_ICPR |= OS_TIMER_1_BIT_MASK;
+ m_ICPR |= OS_TIMER_2_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_0_BIT_MASK |
+ OS_TIMER_3_BIT_MASK);
+ }
+ break;
+
+ case (OsTimer::OSMR0_MASK |
+ OsTimer::OSMR1_MASK |
+ OsTimer::OSMR2_MASK): // 0111
+ {
+ m_ICPR |= OS_TIMER_0_BIT_MASK;
+ m_ICPR |= OS_TIMER_1_BIT_MASK;
+ m_ICPR |= OS_TIMER_2_BIT_MASK;
+
+ m_ICPR &= ~OS_TIMER_3_BIT_MASK;
+ }
+ break;
+
+ case OsTimer::OSMR3_MASK: // 1000
+ {
+ m_ICPR |= OS_TIMER_3_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_0_BIT_MASK |
+ OS_TIMER_1_BIT_MASK |
+ OS_TIMER_2_BIT_MASK);
+ }
+ break;
+
+ case (OsTimer::OSMR0_MASK |
+ OsTimer::OSMR3_MASK): // 1001
+ {
+ m_ICPR |= OS_TIMER_0_BIT_MASK;
+ m_ICPR |= OS_TIMER_3_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_1_BIT_MASK |
+ OS_TIMER_2_BIT_MASK);
+ }
+ break;
+
+ case (OsTimer::OSMR1_MASK |
+ OsTimer::OSMR3_MASK): // 1010
+ {
+ m_ICPR |= OS_TIMER_1_BIT_MASK;
+ m_ICPR |= OS_TIMER_3_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_0_BIT_MASK |
+ OS_TIMER_2_BIT_MASK);
+ }
+ break;
+
+ case (OsTimer::OSMR0_MASK |
+ OsTimer::OSMR1_MASK |
+ OsTimer::OSMR3_MASK): // 1011
+ {
+ m_ICPR |= OS_TIMER_0_BIT_MASK;
+ m_ICPR |= OS_TIMER_1_BIT_MASK;
+ m_ICPR |= OS_TIMER_3_BIT_MASK;
+
+ m_ICPR &= ~OS_TIMER_2_BIT_MASK;
+ }
+ break;
+
+ case (OsTimer::OSMR2_MASK |
+ OsTimer::OSMR3_MASK): // 1100
+ {
+ m_ICPR |= OS_TIMER_2_BIT_MASK;
+ m_ICPR |= OS_TIMER_3_BIT_MASK;
+
+ m_ICPR &= ~(OS_TIMER_0_BIT_MASK |
+ OS_TIMER_1_BIT_MASK);
+ }
+ break;
+
+ case (OsTimer::OSMR0_MASK |
+ OsTimer::OSMR2_MASK |
+ OsTimer::OSMR3_MASK): // 1101
+ {
+ m_ICPR |= OS_TIMER_0_BIT_MASK;
+ m_ICPR |= OS_TIMER_2_BIT_MASK;
+ m_ICPR |= OS_TIMER_3_BIT_MASK;
+
+ m_ICPR &= ~OS_TIMER_1_BIT_MASK;
+ }
+ break;
+
+ case (OsTimer::OSMR1_MASK |
+ OsTimer::OSMR2_MASK |
+ OsTimer::OSMR3_MASK): // 1110
+ {
+ m_ICPR |= OS_TIMER_1_BIT_MASK;
+ m_ICPR |= OS_TIMER_2_BIT_MASK;
+ m_ICPR |= OS_TIMER_3_BIT_MASK;
+
+ m_ICPR &= ~OS_TIMER_0_BIT_MASK;
+ }
+ break;
+
+ case (OsTimer::OSMR0_MASK |
+ OsTimer::OSMR1_MASK |
+ OsTimer::OSMR2_MASK |
+ OsTimer::OSMR3_MASK): // 1111
+ {
+ m_ICPR |= (OS_TIMER_0_BIT_MASK |
+ OS_TIMER_1_BIT_MASK |
+ OS_TIMER_2_BIT_MASK |
+ OS_TIMER_3_BIT_MASK);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // check RTC
+
+ // {
+ // uint32_t const rtc_status = mp_rtc->get_interrupt_status();
+
+ // switch (rtc_status)
+ // {
+ // case 0:
+ // m_ICPR &= ~(RTC_ALARM_BIT_MASK | RTC_HZ_BIT_MASK);
+ // break;
+
+ // case RTC::STATUS_AL_BIT:
+ // m_ICPR |= RTC_ALARM_BIT_MASK;
+ // m_ICPR &= ~RTC_HZ_BIT_MASK;
+ // break;
+
+ // case RTC::STATUS_HZ_BIT:
+ // m_ICPR |= RTC_HZ_BIT_MASK;
+ // m_ICPR &= ~RTC_ALARM_BIT_MASK;
+ // break;
+
+ // case (RTC::STATUS_AL_BIT | RTC::STATUS_HZ_BIT):
+ // m_ICPR |= (RTC_ALARM_BIT_MASK | RTC_HZ_BIT_MASK);
+ // break;
+
+ // default:
+ // assert(!"Should not reach here.");
+ // break;
+ // }
+ // }
+
+ // check LCD controller
+
+ {
+ uint32_t const lcd_status = mLCDController->get_interrupt_status();
+
+ if (0 == lcd_status)
+ {
+ m_ICPR &= ~LCD_SERVICE_BIT_MASK;
+ }
+ else
+ {
+ if ((lcd_status & ~(LCDController::LCSR_BAU | LCDController::LCSR_LDD)) != 0)
+ {
+ m_ICPR |= LCD_SERVICE_BIT_MASK;
+ }
+ else
+ {
+ switch (lcd_status & (LCDController::LCSR_BAU | LCDController::LCSR_LDD))
+ {
+ case 0:
+ // If we go here, means (lcd_status == 0), however, (lcd_status == 0) should
+ // go to the upper 'if' block, thus if we go here, it is a bug.
+ break;
+
+ case LCDController::LCSR_BAU:
+ {
+ uint32_t const ctrl_0 = mLCDController->get_ctrl_reg_0();
+
+ if (0 == (ctrl_0 & LCDController::LCCR0_BAM))
+ {
+ // Enable BAU
+ m_ICPR |= LCD_SERVICE_BIT_MASK;
+ }
+ else
+ {
+ m_ICPR &= ~LCD_SERVICE_BIT_MASK;
+ }
+ }
+ break;
+
+ case LCDController::LCSR_LDD:
+ {
+ uint32_t const ctrl_0 = mLCDController->get_ctrl_reg_0();
+
+ if (0 == (ctrl_0 & LCDController::LCCR0_LDM))
+ {
+ // Enable LDD
+ m_ICPR |= LCD_SERVICE_BIT_MASK;
+ }
+ else
+ {
+ m_ICPR &= ~LCD_SERVICE_BIT_MASK;
+ }
+ }
+ break;
+
+ case (LCDController::LCSR_BAU | LCDController::LCSR_LDD):
+ {
+ uint32_t const ctrl_0 = mLCDController->get_ctrl_reg_0();
+
+ switch (ctrl_0 & (LCDController::LCCR0_BAM | LCDController::LCCR0_LDM))
+ {
+ case 0:
+ case LCDController::LCCR0_BAM:
+ case LCDController::LCCR0_LDM:
+ // Enable BAU
+ m_ICPR |= LCD_SERVICE_BIT_MASK;
+ break;
+
+ case (LCDController::LCCR0_BAM | LCDController::LCCR0_LDM):
+ m_ICPR &= ~LCD_SERVICE_BIT_MASK;
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Check UART in the serial port 1, 2 & 3
+ // check_UART_interrupt(mp_serial_1->get_UART());
+ // check_UART_interrupt(mp_serial_2->get_UART());
+ check_UART_interrupt(mSerial3->get_UART());
+
+ // Determine IRQ & FIQ
+
+ if (m_ICPR != 0)
+ {
+ uint32_t const temp = m_ICPR & m_ICMR;
+
+ m_ICIP = temp & (~m_ICLR);
+ m_ICFP = temp & m_ICLR;
+
+ // if (true == mp_core->is_in_idle_mode())
+ // {
+ // // We have at least one interrupt.
+ // if (0 == (m_ICCR & ICCR_DIM_BITMASK))
+ // {
+ // // :SA-1110 Developer's Manual: p.89: Wei 2004-May-09:
+ // //
+ // // All enabled interrupts will bring the SA-1110 out of idle mode.
+ // mp_core->exit_idle_mode();
+ // }
+ // else
+ // {
+ // if (temp != 0)
+ // {
+ // // :SA-1110 Developer's Manual: p.89: Wei 2004-May-09:
+ // //
+ // // Only enabled and unmasked (as defined in the ICMR) will bring
+ // // the SA-1110 out of idle mode.
+ // mp_core->exit_idle_mode();
+ // }
+ // }
+ // }
+ } else {
+ // Optimize the condition of no pending interrupt.
+
+ // m_ICPR == 0: We have no pending interrupt.
+ m_ICIP = 0;
+ m_ICFP = 0;
+ }
+ }
+
+ uint32_t IntController::get_data(uint32_t const address) const {
+ switch (address) {
+ case ICIP: return m_ICIP;
+ case ICMR: return m_ICMR;
+ case ICLR: return m_ICLR;
+ case ICCR: return m_ICCR;
+ case ICFP: return m_ICFP;
+ case ICPR: return m_ICPR;
+
+ default:
+ return 0;
+ }
+ }
+
+ void IntController::put_data(uint32_t const address, uint32_t const value) {
+ switch (address)
+ {
+ case ICIP:
+ // :SA-1110 Developer's Manual: Wei 2003-Dec-09:
+ //
+ // ICIP is a read-only register
+ break;
+
+ case ICMR:
+ m_ICMR = value;
+ break;
+
+ case ICLR:
+ m_ICLR = value;
+ break;
+
+ case ICCR:
+ // :SA-1110 Developer's Manual: p.89: Wei 2004-May-09:
+ //
+ // bits[31:1] are reserved.
+ m_ICCR = (value & 0x1);
+ break;
+
+ case ICFP:
+ // :SA-1110 Developer's Manual: Wei 2003-Dec-09:
+ //
+ // ICFP is a read-only register
+ break;
+
+ case ICPR:
+ // :SA-1110 Developer's Manual: Wei 2003-Dec-09:
+ //
+ // ICPR is a read-only register
+ break;
+
+ default:
+ break;
+ }
+ }
+
+
+ void IntController::check_UART_interrupt(Uart const &uart) {
+ uint32_t const UART_status = uart.get_interrupt_status();
+
+ if (0 == UART_status)
+ {
+ m_ICPR &= ~SERIAL_3_BIT_MASK;
+ }
+ else
+ {
+ uint32_t const ctrl_3 = uart.get_ctrl_reg_3();
+
+ switch (ctrl_3 & (Uart::UTCR3_TIE |
+ Uart::UTCR3_RIE))
+ {
+ case 0:
+ break;
+
+ case Uart::UTCR3_TIE:
+ if ((UART_status & Uart::UTSR0_TFS) != 0)
+ {
+ m_ICPR |= SERIAL_3_BIT_MASK;
+ }
+ else
+ {
+ m_ICPR &= ~SERIAL_3_BIT_MASK;
+ }
+ break;
+
+ case Uart::UTCR3_RIE:
+ if ((UART_status & (Uart::UTSR0_RFS |
+ Uart::UTSR0_RID)) != 0)
+ {
+ m_ICPR |= SERIAL_3_BIT_MASK;
+ }
+ else
+ {
+ m_ICPR &= ~SERIAL_3_BIT_MASK;
+ }
+ break;
+
+ case (Uart::UTCR3_TIE | Uart::UTCR3_RIE):
+ if ((UART_status & (Uart::UTSR0_TFS |
+ Uart::UTSR0_RFS |
+ Uart::UTSR0_RID)) != 0)
+ {
+ m_ICPR |= SERIAL_3_BIT_MASK;
+ }
+ else
+ {
+ m_ICPR &= ~SERIAL_3_BIT_MASK;
+ }
+ break;
+ }
+ }
+ }
+
+} // namespace SA1100
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INTERRUPT_CONTROLLER_H
+#define INTERRUPT_CONTROLLER_H
+
+#include <stdint.h>
+
+#include "gpio_controller.h"
+#include "lcd_controller.h"
+#include "os_timer.h"
+#include "serial_3.h"
+#include "uart.h"
+
+namespace SA1100 {
+
+class IntController {
+ public:
+
+ // Interrupt Bit Mask
+
+ enum IntCtrlBitMaskEnum
+ {
+ GPIO_0_EDGE_BIT_MASK = (1 << 0),
+ GPIO_1_EDGE_BIT_MASK = (1 << 1),
+ GPIO_2_EDGE_BIT_MASK = (1 << 2),
+ GPIO_3_EDGE_BIT_MASK = (1 << 3),
+ GPIO_4_EDGE_BIT_MASK = (1 << 4),
+ GPIO_5_EDGE_BIT_MASK = (1 << 5),
+ GPIO_6_EDGE_BIT_MASK = (1 << 6),
+ GPIO_7_EDGE_BIT_MASK = (1 << 7),
+ GPIO_8_EDGE_BIT_MASK = (1 << 8),
+ GPIO_9_EDGE_BIT_MASK = (1 << 9),
+ GPIO_10_EDGE_BIT_MASK = (1 << 10),
+
+ GPIO_0_10_EDGE_BIT_MASK = (GPIO_0_EDGE_BIT_MASK |
+ GPIO_1_EDGE_BIT_MASK |
+ GPIO_2_EDGE_BIT_MASK |
+ GPIO_3_EDGE_BIT_MASK |
+ GPIO_4_EDGE_BIT_MASK |
+ GPIO_5_EDGE_BIT_MASK |
+ GPIO_6_EDGE_BIT_MASK |
+ GPIO_7_EDGE_BIT_MASK |
+ GPIO_8_EDGE_BIT_MASK |
+ GPIO_9_EDGE_BIT_MASK |
+ GPIO_10_EDGE_BIT_MASK),
+
+ GPIO_11_27_EDGE_BIT_MASK = (1 << 11),
+
+ LCD_SERVICE_BIT_MASK = (1 << 12),
+
+ SERIAL_1_BIT_MASK = (1 << 15),
+ SERIAL_2_BIT_MASK = (1 << 16),
+ SERIAL_3_BIT_MASK = (1 << 17),
+
+ OS_TIMER_0_BIT_MASK = (1 << 26),
+ OS_TIMER_1_BIT_MASK = (1 << 27),
+ OS_TIMER_2_BIT_MASK = (1 << 28),
+ OS_TIMER_3_BIT_MASK = (1 << 29),
+
+ RTC_HZ_BIT_MASK = (1 << 30),
+ RTC_ALARM_BIT_MASK = (1 << 31)
+ };
+ typedef enum IntCtrlBitMaskEnum IntCtrlBitMaskEnum;
+
+ private:
+
+ // Attribute
+ OsTimer* const mOsTimer;
+ LCDController* const mLCDController;
+ GPIOController* const mGPIOController;
+ Serial3* const mSerial3;
+
+ // Register location
+
+ enum
+ {
+ ICIP = 0x90050000,
+ ICMR = 0x90050004,
+ ICLR = 0x90050008,
+ ICCR = 0x9005000C,
+ ICFP = 0x90050010,
+ ICPR = 0x90050020
+ };
+
+ // Register
+
+ uint32_t m_ICIP;
+ uint32_t m_ICMR;
+ uint32_t m_ICLR;
+ uint32_t m_ICCR;
+ uint32_t m_ICFP;
+ uint32_t m_ICPR;
+
+ enum
+ {
+ ICCR_DIM_BITMASK = 0x1
+ };
+
+ // Operation
+
+ void
+ init_register()
+ {
+ m_ICIP = 0;
+ m_ICMR = 0;
+ m_ICLR = 0;
+ m_ICCR = 0;
+ m_ICFP = 0;
+ m_ICPR = 0;
+ }
+
+ void check_UART_interrupt(Uart const &uart);
+
+ public:
+
+ // Life cycle
+
+ IntController(LCDController* const lcdController,
+ OsTimer* const osTimer,
+ GPIOController* const gpioController,
+ Serial3* const serial3);
+
+ // Operation
+
+ void run();
+ void reset();
+
+ uint32_t get_data(uint32_t const address) const;
+
+ void put_data(uint32_t const address, uint32_t const value);
+
+ inline bool have_pending_irq() const {
+ return (0 == m_ICIP) ? false : true;
+ }
+
+ inline bool have_pending_fiq() const {
+ return (0 == m_ICFP) ? false : true;
+ }
+};
+
+} // namespace SA1100
+
+#endif // INTERRUPT_CONTROLLER_H
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <iostream>
+
+#include "lcd_controller.h"
+
+namespace SA1100 {
+
+LCDController::LCDController() {
+ init_register();
+}
+
+void LCDController::reset() {
+ m_LCCR0 = 0;
+ m_LCCR1 = 0;
+ m_LCCR2 = 0;
+ m_LCCR3 = 0;
+ m_LCSR = 0;
+ mEnabled = false;
+}
+
+uint32_t LCDController::get_data32(uint32_t const address) const {
+ std::cout << "LCD: get value at " << std::hex << address << std::endl;
+
+ switch (address) {
+ case LCCR0: return m_LCCR0;
+ case LCCR1: return m_LCCR1;
+ case LCCR2: return m_LCCR2;
+ case LCCR3: return m_LCCR3;
+ case DBAR1: return m_DBAR1;
+ case DCAR1: return m_DCAR1;
+ case DBAR2: return m_DBAR2;
+ case DCAR2: return m_DCAR2;
+ case LCSR: return m_LCSR;
+
+ default:
+ return 0;
+ }
+}
+
+void LCDController::put_data32(uint32_t const address, uint32_t const value)
+ {
+ switch (address) {
+ case LCCR0:
+ {
+ std::cout << "LCD: LCCR0: " << std::hex << value << std::endl;
+
+ uint32_t const diff = (m_LCCR0 ^ value);
+
+ if ((diff & LCCR0_LEN) != 0)
+ {
+ if (0 == (value & LCCR0_LEN))
+ {
+ std::cout << "LCD: disable lcd" << std::endl;
+ mEnabled = false;
+ m_LCSR |= LCSR_LDD;
+
+ // mp_machine_screen->disable_drawing();
+ // mp_memory->disable_drawing();
+ }
+ else
+ {
+ std::cout << "LCD: enable lcd" << std::endl;
+ mEnabled = true;
+
+ // :NOTE: Wei 2004-Jun-06:
+ //
+ // ARMware supports only TFT (active) mode now.
+ // assert(LCCR0_PAS == (value & LCCR0_PAS));
+
+ // :SA-1110 Developer's Manual: Wei 2003-Dec-08:
+ //
+ // Value in DBAR1(or 2) is transferred to DCAR1(or 2) when LCD is first enabled (LEN = 0->1).
+ m_DCAR1 = m_DBAR1;
+ m_DCAR2 = m_DBAR2;
+
+ // :SA-1110 Developer's Manual: p.249: Wei 2004-Jan-15:
+ //
+ // The base address update status (BAU) is a read/write status bit
+ // that is set after the contents of the DMA base address register 1
+ // are transferred to the DMA current Address register 1.
+ m_LCSR |= LCSR_BAU;
+
+ // mp_machine_screen->enable_drawing();
+ // mp_memory->enable_drawing();
+ }
+ }
+
+ if ((diff & LCCR0_SDS) != 0) {
+ // No support for dual panels, ignore
+ }
+
+ m_LCCR0 = (value & (0xFFFFF ^ (1 << 6)));
+ }
+ break;
+
+ case LCCR1:
+ std::cout << "LCD: LCCR1: " << std::hex << value << std::endl;
+
+ // :SA-1110 Developer's Manual: Wei 2004-Jan-13:
+ //
+ // Note that the bottom four bits of PPL are not implemented and
+ // therefore are not writable. Reads of these bits return zeros
+ // because the LCD controller only supports displays that are a
+ // multiple of 16 pixels wide.
+ m_LCCR1 = (value & 0xFFFFFFF0);
+ break;
+
+ case LCCR2:
+ std::cout << "LCD: LCCR2: " << std::hex << value << std::endl;
+
+ m_LCCR2 = value;
+ break;
+
+ case LCCR3:
+ std::cout << "LCD: LCCR3: " << std::hex << value << std::endl;
+
+ m_LCCR3 = (value & 0xFFFFFF);
+ break;
+
+ case DBAR1:
+ std::cout << "LCD: DBAR1: " << std::hex << value << std::endl;
+
+ // :SA-1110 Developer's Manual: p.245: Wei 2003-Dec-08:
+ //
+ // Addresses programmed in the base address register must be aligned
+ // on quadword boundaries;
+ // the least significant four bits (DBAR1[3:0]) must always be written with zeros.
+ // assert(0 == (value & 0xF));
+
+ // :NOTE: Wei 2004-Jan-15:
+ //
+ // If we want to change the frame buffer address,
+ // we are likely need to update the whole screen.
+ if (m_DBAR1 != value)
+ {
+ m_DBAR1 = value;
+ // mp_machine_screen->set_frame_buffer_addr_1(m_DBAR1);
+ // mp_machine_screen->template update_panel<MachineScreen::PANEL_1>();
+ // mp_memory->set_frame_buffer_addr_1(m_DBAR1);
+ }
+ break;
+
+ case DBAR2:
+ std::cout << "LCD: DBAR2: " << std::hex << value << std::endl;
+
+ // :SA-1110 Developer's Manual: p.245: Wei 2003-Dec-08:
+ //
+ // Addresses programmed in the base address register must be aligned
+ // on quadword boundaries;
+ // the least significant four bits (DBAR1[3:0]) must always be written with zeros.
+ // assert(0 == (value & 0xF));
+
+ if (m_DBAR2 != value)
+ {
+ m_DBAR2 = value;
+
+ // mp_machine_screen->set_frame_buffer_addr_2(m_DBAR2);
+ // mp_machine_screen->template update_panel<MachineScreen::PANEL_2>();
+
+ // mp_memory->set_frame_buffer_addr_2(m_DBAR2);
+ }
+ break;
+
+ case DCAR1:
+ case DCAR2:
+ // :SA-1110 Developer's Manual: p.247: Wei 2004-Jun-06:
+ // :SA-1110 Developer's Manual: p.248: Wei 2004-Jun-06:
+ //
+ // These are read-only registers.
+ // assert(!"Should not reach here.");
+ break;
+
+ case LCSR:
+ std::cout << "LCD: LCSR: " << std::hex << value << std::endl;
+
+ // :SA-1110 Developer's Manual: p.248: Wei 2004-Jun-06:
+ //
+ // Status bits are referred to as 'sticky' (once set by hardware,
+ // they must be cleared by software). Writing a 1 to a sticky status bit clears it;
+ // writing a zero has no effect.
+ // Read-only flags are set and cleared by hardware; writes have no effect.
+
+ m_LCSR &= ~(m_LCSR & (value & LCSR_READ_WRITE_BITMASK));
+ break;
+
+ default:
+ // assert(!"Should not reach here.");
+ break;
+ }
+ }
+} // namespace SA1100
\ No newline at end of file
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef LCD_CONTROLLER_H
+#define LCD_CONTROLLER_H
+
+#include <stdint.h>
+
+namespace SA1100 {
+
+class LCDController {
+public:
+ enum {
+ LCCR0_LEN = (1 << 0), // LCD controller enable
+ LCCR0_CMS = (1 << 1), // Color/monochrome select.
+ LCCR0_SDS = (1 << 2), // Single-/dual-panel display select.
+ LCCR0_LDM = (1 << 3), // LCD disable done mask
+ LCCR0_BAM = (1 << 4), // Base address update interrupt mask
+ LCCR0_ERM = (1 << 5), // Error mask.
+ LCCR0_PAS = (1 << 7), // Passive/active display select
+ LCCR0_BLE = (1 << 8), // Big/little endian select.
+ LCCR0_DPD = (1 << 9), // Double-pixel data pin mode.
+ LCCR0_VCS = ((1 << 10) | (1 << 11)), // Vertical slant line correction.
+ LCCR0_PDD = ((1 << 12) | (1 << 13) |
+ (1 << 14) | (1 << 15) |
+ (1 << 16) | (1 << 17) |
+ (1 << 18) | (1 << 19)) // Palette DMA request delay.
+ };
+
+ enum {
+ LCSR_LDD = (1 << 0), // LCD disable done status.
+ LCSR_BAU = (1 << 1), // Base address update flag (read-only, maskable interrupt)
+ LCSR_BER = (1 << 2), // Bus error status.
+ LCSR_ABC = (1 << 3), // AC bias count status.
+
+ // :NOTE: Wei 2004-Jun-06:
+ //
+ // I think in ARMware, we shouldn't raise the following bits.
+ // As a result, no interrupts should be raised because of the following bits.
+
+ LCSR_IOL = (1 << 4), // Input FIFO overrun lower panel status.
+ LCSR_IUL = (1 << 5), // Input FIFO underrun lower panel status.
+ LCSR_IOU = (1 << 6), // Input FIFO overrun upper panel status.
+ LCSR_IUU = (1 << 7), // Input FIFO underrun upper panel status.
+ LCSR_OOL = (1 << 8), // Output FIFO overrun lower panel status.
+ LCSR_OUL = (1 << 9), // Output FIFO underrun lower panel status.
+ LCSR_OOU = (1 << 10), // Output FIFO overrun upper panel status.
+ LCSR_OUU = (1 << 11), // Output FIFO underrun upper panel status.
+
+ // :NOTE: Wei 2004-Jun-30:
+ //
+ // Althought page 249 in the Intel SA-1110 Developer's Manual says that BAU flag is read-only,
+ // however, in the same page (p.249), it says that BAU flag can be cleared when it is written
+ // to a 1.
+ // After searching google, I find a post related this:
+ //
+ // �H��̡Gbratfi_t@my-deja.com (bratfi_t@my-deja.com)
+ // �D���GRe: BAU flag on SA1100
+ // ���W�׾¡Gcomp.sys.arm
+ // ����G1999/08/31
+ //
+ // ...
+ // According to the manual, the BAU flag is read-only, but it can be cleared like a status bit!
+ // ...
+ //
+ // Thus I include BAU in the following constant.
+ LCSR_READ_WRITE_BITMASK = (LCSR_LDD |
+ LCSR_BAU |
+ LCSR_BER |
+ LCSR_ABC |
+ LCSR_IOL |
+ LCSR_IUL |
+ LCSR_IOU |
+ LCSR_IUU |
+ LCSR_OOL |
+ // LCSR_OUL |
+ LCSR_OOU |
+ LCSR_OUU)
+ };
+
+ enum
+ {
+ LCCR0 = 0xB0100000,
+ LCSR = 0xB0100004,
+ DBAR1 = 0xB0100010,
+ DCAR1 = 0xB0100014,
+ DBAR2 = 0xB0100018,
+ DCAR2 = 0xB010001C,
+ LCCR1 = 0xB0100020,
+ LCCR2 = 0xB0100024,
+ LCCR3 = 0xB0100028
+ };
+
+private:
+ // Operation
+
+ uint32_t CalculateFrameBufferEndAddress();
+
+ bool mEnabled;
+
+ // Register location
+
+
+ // Register
+
+ uint32_t m_LCCR0; // LCD controller control register 0
+ uint32_t m_LCSR; // LCD controller status register 1
+ uint32_t m_DBAR1; // DMA channel 1 base address register
+ uint32_t m_DCAR1; // DMA channel 1 current address register
+ uint32_t m_DBAR2; // DMA channel 2 base address register
+ uint32_t m_DCAR2; // DMA channel 2 current address register
+ uint32_t m_LCCR1; // LCD controller control register 1
+ uint32_t m_LCCR2; // LCD controller control register 2
+ uint32_t m_LCCR3; // LCD controller control register 3
+
+ // Operation
+
+ void init_register() {
+ m_LCCR0 = 0;
+ m_LCSR = 0;
+ m_DBAR1 = 0;
+ m_DCAR1 = 0;
+ m_DBAR2 = 0;
+ m_DCAR2 = 0;
+ m_LCCR1 = 0;
+ m_LCCR2 = 0;
+ m_LCCR3 = 0;
+ }
+
+public:
+
+ LCDController();
+ void reset();
+
+ bool isLCDEnabled() { return mEnabled; }
+
+ unsigned int getWidth() { return (m_LCCR1 & 0x3FF) + 16; }
+ unsigned int getHeight() { return (m_LCCR2 & 0x3FF) + 1; }
+
+ inline void finish_one_frame() {
+ // assert(LCCR0_LEN == (m_LCCR0 & LCCR0_LEN));
+ m_DCAR1 = m_DBAR1;
+ m_DCAR2 = m_DBAR2;
+
+ // :SA-1110 Developer's Manual: Wei 2003-Dec-08:
+ //
+ // Value in DBAR1(or 2) is transferred to DCAR1(or 2) when LCD is first enabled (LEN = 0->1)
+ // and when the current address pointer value equals the end-of-frame buffer.
+
+ // :NOTE: Wei 2004-Jan-15:
+ //
+ // Althought I don't update the m_DCAR1(or 2) when (m_DBAR1 == m_DCAR1) here,
+ // however, they are actually transfered in the real SA-1110,
+ // thus the following LCSR_BAU setting operation are always performed.
+
+ // :SA-1110 Developer's Manual: p.249: Wei 2004-Jan-15:
+ //
+ // The base address update status (BAU) is a read/write status bit
+ // that is set after the contents of the DMA base address register 1
+ // are transferred to the DMA current Address register 1
+ m_LCSR |= LCSR_BAU;
+ }
+
+ inline uint32_t get_interrupt_status() const {
+ return m_LCSR;
+ }
+
+ inline uint32_t get_ctrl_reg_0() const {
+ return m_LCCR0;
+ }
+
+ uint32_t get_data32(uint32_t const address) const;
+ void put_data32(uint32_t const address, uint32_t const value);
+};
+
+} // namespace SA1100
+
+#endif // LCD_CONTROLLER_H
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "os_timer.h"
+
+namespace SA1100 {
+
+ OsTimer::OsTimer()
+ {
+ init_register();
+ }
+
+ //============================== Operation ==================================
+
+ void
+ OsTimer::reset()
+ {
+ // :SA-1110 Developer's Manual: Wei 2004-Apr-24:
+ //
+ // WME (Watchdog Match Enable) bit is set by writing a one to it.
+ // It can only be cleared by one of the reset functions (hardware reset,
+ // software reset) and by entering sleep mode.
+ // A watchdog reset also clears the watchdog enable bit.
+ m_OWER = 0;
+ m_has_enabled_watchdog_timer = false;
+
+ // :SA-1110 Developer's Manual: p.97: Wei 2004-Apr-24:
+ //
+ // the value of bits 0 ~ 3 of OSSR register are unknown at reset.
+ m_OSSR &= 0xF;
+
+ m_OIER = 0;
+ }
+
+ void OsTimer::tick() {
+ // :SA-1110 Developer's Manual: p.96: Wei 2004-Apr-24:
+ //
+ // OSMR[0..3] are compared against the OSCR following every rising
+ // edge of the 3.6864-MHz clock.
+ switch (m_OIER & 0xF)
+ {
+ case 0:
+ break;
+
+ default:
+ compare_and_set_status(m_OIER & 0xF);
+ }
+
+ // :SA-1110 Developer's Manual: p.96: Wei 2004-Apr-24:
+ //
+ // The OS timer count register is a 32-bit counter that increments
+ // on rising edges of the 3.6864-MHz clock.
+
+ // :NOTE: Wei 2004-Apr-25:
+ //
+ // According to the Linux Kernel source about the setup_timer() routine,
+ // I think the increment of OSCR register should be put after the
+ // comparation between OSCR & OSMR.
+ ++m_OSCR;
+ }
+
+ uint32_t OsTimer::get_data(uint32_t const address) const {
+ switch (address)
+ {
+ case OSMR0:
+ return m_OSMR[0];
+
+ case OSMR1:
+ return m_OSMR[1];
+
+ case OSMR2:
+ return m_OSMR[2];
+
+ case OSMR3:
+ return m_OSMR[3];
+
+ case OSCR:
+ return m_OSCR;
+
+ case OSSR:
+ return m_OSSR;
+
+ case OWER:
+ return m_OWER;
+
+ case OIER:
+ return m_OIER;
+
+ default:
+ return 0;
+ }
+ }
+
+ void OsTimer::put_data(uint32_t const address, uint32_t const value) {
+ switch (address)
+ {
+ case OSMR0:
+ m_OSMR[0] = value;
+ break;
+
+ case OSMR1:
+ m_OSMR[1] = value;
+ break;
+
+ case OSMR2:
+ m_OSMR[2] = value;
+ break;
+
+ case OSMR3:
+ m_OSMR[3] = value;
+ break;
+
+ case OSCR:
+ m_OSCR = value;
+ break;
+
+ case OSSR:
+ // :SA-1110 Developer's Manual: p.97: Wei 2004-Apr-24:
+ //
+ // bits 0 ~ 3 of OSSR register are cleared by writing a one to the
+ // proper bit position. Writing zeros to this register has no effect.
+ // All reserved bits read as zeros and are unaffected by writes;
+ switch (value & 0xF) {
+ case 0x0: // 0000
+ break;
+ default:
+ m_OSSR &= ~(value & 0xF);
+ break;
+ }
+ break;
+
+ case OWER:
+ // :SA-1110 Developer's Manual: p.96: Wei 2004-Apr-24:
+ //
+ // WME (Watchdog Match Enable) bit is set by writing a one to it.
+ // It can only be cleared by one of the reset functions (hardware reset,
+ // software reset) and by entering sleep mode.
+ // A watchdog reset also clears the watchdog enable bit.
+ if (false == m_has_enabled_watchdog_timer)
+ {
+ if (WME_BITMASK == (value & WME_BITMASK))
+ {
+ // :SA-1110 Developer's Manual: p.98: Wei 2004-Apr-25:
+ //
+ // The user must clear OSSR:M3 before setting up a watchdog reset.
+ //assert(0 == (m_OSSR & OSMRTraits<OSMR3>::BITMASK));
+
+ m_OWER |= WME_BITMASK;
+ m_has_enabled_watchdog_timer = true;
+ }
+ }
+ break;
+
+ case OIER:
+ // :NOTE: Wei 2004-Apr-24:
+ //
+ // According to OSSR register: All reserved bits read as zeros and are unaffected by writes
+ // I think OIER is the same with OSSR.
+ m_OIER = (value & 0xF);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+} // namespace SA1100
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef OS_TIMER_H
+#define OS_TIMER_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+namespace SA1100 {
+
+class OsTimer {
+ private:
+
+ static uint32_t const WME_BITMASK = 0x1; // Watchdog Match Enable bit mask
+
+ bool m_has_enabled_watchdog_timer;
+
+ uint32_t m_OSMR[4]; // OS timer match register 0 ~ 3
+ uint32_t m_OSCR; // OS timer counter register
+ uint32_t m_OSSR; // OS timer status register
+ uint32_t m_OWER; // OS timer watchdog enable register
+ uint32_t m_OIER; // OS timer interrupt enable register
+
+ void init_register() {
+ for (uint32_t i = 0; i < 4; ++i)
+ {
+ m_OSMR[i] = 0;
+ }
+
+ m_OSCR = 0;
+ m_OSSR = 0;
+ m_OWER = 0;
+ m_OIER = 0;
+ }
+
+ inline void compare_and_set_status(uint32_t osmrs) {
+ if (osmrs & OSMR0_MASK) {
+ if (m_OSCR == m_OSMR[0]) {
+ m_OSSR |= OSMR0_MASK;
+ }
+ }
+ if (osmrs & OSMR1_MASK) {
+ if (m_OSCR == m_OSMR[1]) {
+ m_OSSR |= OSMR1_MASK;
+ }
+ }
+ if (osmrs & OSMR2_MASK) {
+ if (m_OSCR == m_OSMR[2]) {
+ m_OSSR |= OSMR2_MASK;
+ }
+ }
+ if (osmrs & OSMR3_MASK) {
+ if (m_has_enabled_watchdog_timer) {
+ // TODO: implement watchdog
+ } else {
+ if (m_OSCR == m_OSMR[3]) {
+ printf("OSMR3 triggered\n");
+ m_OSSR |= OSMR3_MASK;
+ }
+ }
+ }
+ }
+
+ public:
+ enum {
+ OSMR0 = 0x90000000,
+ OSMR1 = 0x90000004,
+ OSMR2 = 0x90000008,
+ OSMR3 = 0x9000000C,
+ OSCR = 0x90000010,
+ OSSR = 0x90000014,
+ OWER = 0x90000018,
+ OIER = 0x9000001C
+ };
+
+ enum {
+ OSMR0_MASK = (1 << 0),
+ OSMR1_MASK = (1 << 1),
+ OSMR2_MASK = (1 << 2),
+ OSMR3_MASK = (1 << 3)
+ };
+
+ OsTimer();
+
+ void reset();
+ void tick();
+
+ inline uint32_t get_interrupt_status() const {
+ return m_OSSR;
+ }
+
+ uint32_t get_data(uint32_t const address) const;
+ void put_data(uint32_t const address, uint32_t const value);
+};
+
+} // namespace SA1100
+
+#endif // OS_TIMER_H
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "power_manager.h"
+
+namespace SA1100 {
+
+void PowerManager::reset() {
+ mPMCR = 0;
+ mPCFR = 0;
+ mPPCR = 0;
+ mPWER = 3;
+ mPSSR = 0;
+
+ // :NOTE: Wei 2003-Dec-11:
+ //
+ // I assume all of the bits which have unknown values when reset have value 0.
+ mPGSR = 0;
+
+ // :NOTE: Wei 2004-Jan-16:
+ //
+ // Because ARMware is not a real machine, thus I should set OOK bit in the
+ // POSR register after reset immediately.
+ mPOSR = POSR_OOK;
+}
+
+uint32_t PowerManager::get_data(uint32_t const address) const {
+ switch (address) {
+ case PMCR: return mPMCR;
+ case PSSR: return mPSSR;
+ case PSPR: return mPSPR;
+ case PWER: return mPWER;
+ case PCFR: return mPCFR;
+ case PPCR: return mPPCR;
+ case PGSR: return mPGSR;
+ case POSR: return mPOSR;
+
+ default:
+ return 0;
+ }
+}
+
+void PowerManager::put_data(uint32_t const address, uint32_t const value)
+{
+ switch (address) {
+ case PMCR: mPMCR = value; break;
+ case PSSR: mPSSR = value; break;
+ case PSPR: mPSPR = value; break;
+ case PWER: mPWER = value; break;
+ case PCFR: mPCFR = value; break;
+
+ case PPCR:
+ // :SA-1110 Developer's Manual: Wei 2004-Jan-11:
+ //
+ // The PPCR contains bits used to configure the core operating frequency generated by the PLL.
+ //
+ // :NOTE: Wei 2004-Jan-11:
+ //
+ // However, I enforce the core operating frequency as 206 MHz.
+ // Thus, this register is no use to me.
+ mPPCR = value;
+ break;
+
+ case PGSR: mPGSR = value; break;
+ case POSR: break;
+ default: break;
+ }
+}
+
+} // namespace SA1100
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef POWER_MANAGER_H
+#define POWER_MANAGER_H
+
+#include <stdint.h>
+
+namespace SA1100 {
+
+class PowerManager {
+ private:
+
+ enum {
+ PMCR = 0x90020000,
+ PSSR = 0x90020004,
+ PSPR = 0x90020008,
+ PWER = 0x9002000C,
+ PCFR = 0x90020010,
+ PPCR = 0x90020014,
+ PGSR = 0x90020018,
+ POSR = 0x9002001C
+ };
+
+ enum {
+ POSR_OOK = (1 << 0)
+ };
+
+ // Attribute
+
+ uint32_t mPMCR; // Power manager control register
+ uint32_t mPSSR; // Power manager sleep status register
+ uint32_t mPSPR; // Power manager scratch pad register
+ uint32_t mPWER; // Power manager wake-up enable register;
+ uint32_t mPCFR; // Power manager general configuration register
+ uint32_t mPPCR; // Power manager PLL configuration register
+ uint32_t mPGSR; // Power manager GPIO sleep state register
+ uint32_t mPOSR; // Power manager oscillator status register
+
+ // Operation
+
+ void init_register() {
+ mPMCR = 0;
+ mPSSR = 0;
+ mPSPR = 0;
+ mPWER = 0;
+ mPCFR = 0;
+ mPPCR = 0;
+ mPGSR = 0;
+ mPOSR = 0;
+ }
+
+ public:
+
+ PowerManager() {
+ init_register();
+ }
+
+ void reset();
+
+ uint32_t get_data(uint32_t const address) const;
+ void put_data(uint32_t const address, uint32_t const value);
+};
+
+} // namespace SA1100
+
+#endif // POWER_MANAGER_H
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "reset_controller.h"
+
+namespace SA1100
+{
+
+ uint32_t
+ ResetController::get_data(uint32_t const address) const
+ {
+ switch (address) {
+ case RSRR:
+ // :SA-1110 Developer's Manual: Wei 2003-Dec-11:
+ //
+ // RSRR is write-only.
+ return 0;
+
+ case RCSR:
+ return mRCSR;
+
+ default:
+ return 0;
+ }
+ }
+
+ void ResetController::put_data(uint32_t const address, uint32_t const value) {
+ switch (address) {
+ case RSRR: mRSRR = value; break;
+ case RCSR: mRCSR = value; break;
+ default: break;
+ }
+ }
+}
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef RESET_CONTROLLER_H
+#define RESET_CONTROLLER_H
+
+#include <stdint.h>
+
+namespace SA1100
+{
+
+class ResetController {
+ private:
+
+ enum {
+ RSRR = 0x90030000,
+ RCSR = 0x90030004
+ };
+
+ uint32_t mRSRR; // Reset controller software reset register
+ uint32_t mRCSR; // Reset controller status register
+
+ void init_register() {
+ mRSRR = 0;
+ mRCSR = 1;
+ }
+
+ public:
+
+ ResetController() {
+ init_register();
+ }
+
+ void reset() {
+ mRSRR = 0;
+ mRCSR = 2;
+ }
+
+ bool resetRequested() {
+ return mRSRR & 0xFFFFFFFF;
+ }
+
+ uint32_t get_data(uint32_t const address) const;
+
+ void put_data(uint32_t const address, uint32_t const value);
+ };
+
+}
+
+#endif // RESET_CONTROLLER_H
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// Serial port 3
+//
+
+#ifndef SERIAL_3_H
+#define SERIAL_3_H
+
+#include <stdint.h>
+
+#include "uart.h"
+
+namespace SA1100
+{
+class Serial3 {
+ private:
+
+ Uart m_UART;
+
+ public:
+ // Access
+
+ Uart const & get_UART() const { return m_UART; };
+
+ inline void reset() { m_UART.reset(); }
+
+ inline void run() { m_UART.run(); }
+
+ uint32_t get_data(uint32_t const address) {
+ return m_UART.get_data(address);
+ }
+
+ void put_data(uint32_t const address, uint32_t const value) {
+ m_UART.put_data(address, value);
+ }
+ };
+}
+
+#endif // SERIAL_3_H
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "uart.h"
+
+namespace SA1100
+{
+ inline void Uart::tx_data() {
+ // :NOTE: Wei 2004-Jun-10:
+ //
+ // Becuase of using fifo[0], fifo has to reside in a consecutive memory blocks.
+ // This is why I use std::vector rather than std::deque for m_tx_fifo.
+ // reinterpret_cast<SerialConsole *>(mp_output_device)->put_char_to_serial_console(m_tx_fifo);
+ }
+
+ inline void Uart::rx_data() {
+ // :TODO: Wei 2004-Jun-29:
+ //
+ // Receives data from serial console
+ // reinterpret_cast<SerialConsole *>(mp_output_device)->get_char_from_serial_console();
+ }
+
+ Uart::Uart() {
+ init_register();
+ }
+
+ void Uart::run() {
+ if ((m_UTCR3 & UTCR3_TXE) && (m_tx_fifo.size() != 0))
+ {
+ tx_data();
+
+ m_tx_fifo.clear();
+
+ m_UTSR0 |= UTSR0_TFS; // Enable Transmit FIFO service request
+ m_UTSR1 |= UTSR1_TNF; // Transmit FIFO not full
+ }
+
+ if (m_UTCR3 & UTCR3_RXE)
+ {
+ // :NOTE: Wei 2004-Jul-1:
+ //
+ // Try to get more data.
+ rx_data();
+
+ switch (m_rx_fifo.size())
+ {
+ case 0:
+ m_UTSR1 &= ~UTSR1_RNE;
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ // :SA-1110 Developer's Manual: p.338: Wei 2003-Jun-29:
+ //
+ // If receiver is enabled, receive FIFO not empty, 3 frame times elapsed without receiving data, request interrupt.
+ //
+ // :NOTE: Wei 2004-Jun-29:
+ //
+ // However, I don't see the reasone that I should implement a time-critical operation like this (3 frame times),
+ // thus, whenever the rx fifo isn't empty, ARMware will set the RID bit in UTSR0 up.
+ m_UTSR0 |= UTSR0_RID;
+
+ m_UTSR1 |= UTSR1_RNE;
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ default:
+ // :SA-1110 Developer's Manual: p.338: Wei 2003-Jun-29:
+ //
+ // Receive FIFO is one- to two-thirds full (contains 5, 6, 7, or 8 entries of data) or more,
+ // and receiver operation is enabled, DMA service request signalled,
+ // and interrupt request signalled if not masked (if RIE=1).
+ //
+ // :NOTE: Wei 2004-Jun-29:
+ //
+ // And I choice 8 elements as the delimiter.
+ m_UTSR0 |= (UTSR0_RFS | UTSR0_RID);
+
+ m_UTSR1 |= UTSR1_RNE;
+ break;
+ }
+ }
+ }
+
+ void Uart::reset()
+ {
+ // bit 7 sets 0 on reset.
+ m_UTCR0 &= ~(1 << 7);
+
+ // bit 4, 5, 6, 7 set 0 on reset.
+ m_UTCR1 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
+
+ // bit 0, 1, 6, 7 set 0 on reset.
+ m_UTCR3 &= ~((1 << 7) | (1 << 6) | (1 << 1) | (1 << 0));
+
+ // bit 0, 1, 5, 6, 7 set 0 on reset.
+ m_UTSR0 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 1) | (1 << 0));
+
+ // bit 0, 1, 5, 6, 7 set 0 on reset.
+ m_UTSR1 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 1) | (1 << 0));
+ }
+
+ uint32_t Uart::get_data(uint32_t const address)
+ {
+ switch (address)
+ {
+ case UTCR0:
+ return static_cast<uint32_t>(m_UTCR0);
+
+ case UTCR1:
+ return static_cast<uint32_t>(m_UTCR1);
+
+ case UTCR2:
+ return static_cast<uint32_t>(m_UTCR2);
+
+ case UTCR3:
+ return static_cast<uint32_t>(m_UTCR3);
+
+ case UTDR:
+ {
+ if (true == m_rx_fifo.empty())
+ {
+ assert(0 == (m_UTSR1 & UTSR1_RNE));
+ return static_cast<uint32_t>(0);
+ }
+ else
+ {
+ assert(UTSR1_RNE == (m_UTSR1 & UTSR1_RNE));
+ uint8_t const ch = m_rx_fifo.front();
+
+ m_rx_fifo.pop_front();
+
+ switch (m_rx_fifo.size())
+ {
+ case 0:
+ m_UTSR0 &= ~(UTSR0_RID | UTSR0_RFS);
+
+ m_UTSR1 &= ~UTSR1_RNE;
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ m_UTSR0 &= ~UTSR0_RFS;
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ default:
+ break;
+ }
+ return static_cast<uint32_t>(ch);
+ }
+ }
+
+ case UTSR0:
+ return static_cast<uint32_t>(m_UTSR0);
+
+ case UTSR1:
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 6, 7 are reserved.
+ //
+ // However, this is a read-only register, thus I don't have to do the mask operation.
+ return static_cast<uint32_t>(m_UTSR1);
+
+ default:
+ assert(!"Should not reach here.");
+ return 0;
+ }
+ }
+
+ void Uart::put_data(uint32_t const address, uint32_t const value) {
+ switch (address)
+ {
+ case UTCR0:
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 7 is reserved.
+ m_UTCR0 = static_cast<uint8_t>(value & ~(1 << 7));
+ break;
+
+ case UTCR1:
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 4, 5, 6, 7 are reserved.
+ m_UTCR1 = static_cast<uint8_t>(value & ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4)));
+ break;
+
+ case UTCR2:
+ m_UTCR2 = static_cast<uint8_t>(value);
+ break;
+
+ case UTCR3:
+ {
+ uint8_t const diff = (m_UTCR3 ^ value);
+
+ if ((diff & UTCR3_TXE) && (0 == (value & UTCR3_TXE)))
+ {
+ if (m_tx_fifo.size() != 0)
+ {
+ // :SA-1110 Developer's Manual: p.332: Wei 2003-Jun-29:
+ //
+ // If the TXE bit is cleared to zero, all entries within the transmit FIFO are reset.
+ m_tx_fifo.clear();
+
+ m_UTSR0 |= UTSR0_TFS; // Enable Transmit FIFO service request
+ m_UTSR1 |= UTSR1_TNF; // Transmit FIFO not full
+ }
+ }
+
+ if ((diff & UTCR3_RXE) && (0 == (value & UTCR3_RXE)))
+ {
+ // :SA-1110 Developer's Manual: p.332: Wei 2003-Jun-29:
+ //
+ // If the RXE bit is cleared to zero, all entries within the receive FIFO are reset
+ if (false == m_rx_fifo.empty())
+ {
+ m_rx_fifo.clear();
+
+ m_UTSR0 &= ~(UTSR0_RID | UTSR0_RFS);
+ m_UTSR1 &= ~UTSR1_RNE;
+ }
+ }
+
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 6, 7 are reserved.
+ m_UTCR3 = static_cast<uint8_t>(value & ~((1 << 7) | (1 << 6)));
+ }
+ break;
+
+ case UTDR:
+ switch (m_tx_fifo.size())
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ break;
+
+ case 4:
+ m_UTSR0 &= ~UTSR0_TFS; // disable 'Transmit FIFO service request'
+ break;
+
+ case 5:
+ case 6:
+ break;
+
+ case 7:
+ // :NOTE: Wei 2005-May-29:
+ //
+ // Because the ARMware has unlimited UART buffer,
+ // thus I will never rise down the TNF (Transmit FIFO Not Full) bit.
+ //
+ // m_UTSR1 &= ~(UTSR1_TNF);
+ break;
+
+ case 8:
+ default:
+ break;
+ }
+
+ m_tx_fifo.push_back(static_cast<uint8_t>(value & 0xFF));
+ break;
+
+ case UTSR0:
+ // :SA-1110 Developer's Manual: p.336: Wei 2003-Jun-07:
+ //
+ // Writing a one to a sticky status bit clears it; writing a zero has no effect.
+ // Read-only flags are set and cleared by hardware; writes have no effect.
+
+ // :NOTE: Wei 2004-Jan-03:
+ //
+ // Bit 6, 7 are reserved.
+ // bits 0, 1, 5 are read-only.
+ m_UTSR0 &= ~(value & UTSR0_READ_WRITE_BITS);
+ break;
+
+ case UTSR1:
+ // :NOTE: Wei 2004-Jan-01:
+ //
+ // read-only register.
+ assert(!"Should not reach here.");
+ return;
+
+ default:
+ assert(!"Should not reach here.");
+ break;
+ }
+ }
+}
--- /dev/null
+// ARMware - an ARM emulator
+// Copyright (C) <2007> Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef UART_H
+#define UART_H
+
+#include <cassert>
+#include <deque>
+#include <vector>
+
+#include <stdint.h>
+
+namespace SA1100
+{
+
+class Uart {
+ public:
+ enum
+ {
+ UTCR3_RXE = (1 << 0), // Receiver enable.
+ UTCR3_TXE = (1 << 1), // Transmitter enable.
+ UTCR3_BRK = (1 << 2), // Break.
+ UTCR3_RIE = (1 << 3), // Receive FIFO interrupt enable.
+ UTCR3_TIE = (1 << 4), // Transmit FIFO interrupt enable.
+ UTCR3_LBM = (1 << 5) // Loopback mode.
+ };
+
+ enum
+ {
+ UTSR0_TFS = (1 << 0), // Transmit FIFO service request
+ UTSR0_RFS = (1 << 1), // Receive FIFO service request
+ UTSR0_RID = (1 << 2), // Receiver idle.
+ UTSR0_RBB = (1 << 3), // Receiver begin of break.
+ UTSR0_REB = (1 << 4), // Receiver end of break.
+ UTSR0_EIF = (1 << 5), // Error in FIFO (read-only).
+
+ UTSR0_READ_WRITE_BITS = (UTSR0_RID | UTSR0_RBB | UTSR0_REB),
+ };
+
+ enum
+ {
+ UTSR1_TBY = (1 << 0), // Transmitter busy flag
+ UTSR1_RNE = (1 << 1), // Receive FIFO not empty
+ UTSR1_TNF = (1 << 2), // Transmit FIFO not full
+ UTSR1_PRE = (1 << 3), // Parity error
+ UTSR1_FRE = (1 << 4), // Framing error
+ UTSR1_ROR = (1 << 5) // Receive FIFO overrun
+ };
+
+ static uint32_t const PORT_NUMBER = 3;
+
+ enum
+ {
+ UTCR0 = 0x80050000,
+ UTCR1 = 0x80050004,
+ UTCR2 = 0x80050008,
+ UTCR3 = 0x8005000C,
+ UTDR = 0x80050014,
+ UTSR0 = 0x8005001C,
+ UTSR1 = 0x80050020
+ };
+
+ static uint32_t const RX_FIFO_SIZE = 12;
+ static uint32_t const TX_FIFO_SIZE = 8;
+
+ private:
+
+ // Attribute
+
+ uint8_t m_UTCR0; // UART control register 0
+ uint8_t m_UTCR1; // UART control register 1
+ uint8_t m_UTCR2; // UART control register 2
+ uint8_t m_UTCR3; // UART control register 3
+ uint8_t m_UTDR; // UART data register
+ uint8_t m_UTSR0; // UART status register 0
+ uint8_t m_UTSR1; // UART status register 1
+
+ // :NOTE: Wei 2005-May-29:
+ //
+ // SerialConsole needs m_tx_fifo be in a continus memory space,
+ // thus I use std::vector here.
+ std::vector<uint8_t> m_tx_fifo;
+ std::deque<uint8_t> m_rx_fifo;
+
+ // :NOTE: Wei 2004-Mar-22:
+ //
+ // For now, this mp_output_device is only used in Uart<Serial_3> to output to SerialConsole.
+ void *mp_output_device;
+
+ // Operation
+
+ void init_register() {
+ m_UTCR0 = 0;
+ m_UTCR1 = 0;
+ m_UTCR2 = 0;
+ m_UTCR3 = 0;
+ m_UTDR = 0;
+
+ m_UTSR0 = UTSR0_TFS; // Transmit FIFO service request
+ m_UTSR1 = UTSR1_TNF; // Transmit FIFO not full
+ }
+
+ void tx_data();
+ void rx_data();
+
+ public:
+ Uart();
+ void reset();
+
+ inline void register_output_device(void * const output_device) {
+ mp_output_device = output_device;
+ }
+
+ void run();
+
+ inline uint32_t get_interrupt_status() const {
+ return m_UTSR0;
+ }
+
+ inline uint32_t get_ctrl_reg_3() const {
+ return m_UTCR3;
+ }
+
+ // :SA-1110 Developer's Manual: Wei 2003-Dec-14:
+ //
+ // All registers in the Peripheral Control Module are accessed via
+ // the CPU must be performed using word reads and writes.
+ uint32_t get_data(uint32_t const address);
+
+ void put_data(uint32_t const address, uint32_t const value);
+
+ inline std::deque<uint8_t>& rx_fifo() {
+ return m_rx_fifo;
+ }
+};
+
+} // namespace SA1100
+
+#endif // UART_H