]> localhost Git - WindEmu.git/commitdiff
initial impl of sa-1100 core and associated peripherals for netbook/s7 emulation
authorGeorge Wright <gw@gwright.org.uk>
Tue, 3 Dec 2024 17:18:07 +0000 (09:18 -0800)
committerGeorge Wright <gw@gwright.org.uk>
Tue, 3 Dec 2024 17:18:07 +0000 (09:18 -0800)
18 files changed:
WindCore/sa1100/SA1100.pro [new file with mode: 0644]
WindCore/sa1100/asic14.cpp [new file with mode: 0644]
WindCore/sa1100/asic14.h [new file with mode: 0644]
WindCore/sa1100/gpio_controller.cpp [new file with mode: 0644]
WindCore/sa1100/gpio_controller.h [new file with mode: 0644]
WindCore/sa1100/interrupt_controller.cpp [new file with mode: 0644]
WindCore/sa1100/interrupt_controller.h [new file with mode: 0644]
WindCore/sa1100/lcd_controller.cpp [new file with mode: 0644]
WindCore/sa1100/lcd_controller.h [new file with mode: 0644]
WindCore/sa1100/os_timer.cpp [new file with mode: 0644]
WindCore/sa1100/os_timer.h [new file with mode: 0644]
WindCore/sa1100/power_manager.cpp [new file with mode: 0644]
WindCore/sa1100/power_manager.h [new file with mode: 0644]
WindCore/sa1100/reset_controller.cpp [new file with mode: 0644]
WindCore/sa1100/reset_controller.h [new file with mode: 0644]
WindCore/sa1100/serial_3.h [new file with mode: 0644]
WindCore/sa1100/uart.cpp [new file with mode: 0644]
WindCore/sa1100/uart.h [new file with mode: 0644]

diff --git a/WindCore/sa1100/SA1100.pro b/WindCore/sa1100/SA1100.pro
new file mode 100644 (file)
index 0000000..4f6782a
--- /dev/null
@@ -0,0 +1,5 @@
+SOURCES += \
+    memory_conf.cpp
+
+HEADERS += \
+    memory_conf.h
diff --git a/WindCore/sa1100/asic14.cpp b/WindCore/sa1100/asic14.cpp
new file mode 100644 (file)
index 0000000..75ee9e3
--- /dev/null
@@ -0,0 +1,152 @@
+#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
diff --git a/WindCore/sa1100/asic14.h b/WindCore/sa1100/asic14.h
new file mode 100644 (file)
index 0000000..98d7633
--- /dev/null
@@ -0,0 +1,111 @@
+#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
diff --git a/WindCore/sa1100/gpio_controller.cpp b/WindCore/sa1100/gpio_controller.cpp
new file mode 100644 (file)
index 0000000..d3c20ba
--- /dev/null
@@ -0,0 +1,157 @@
+// 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
diff --git a/WindCore/sa1100/gpio_controller.h b/WindCore/sa1100/gpio_controller.h
new file mode 100644 (file)
index 0000000..b2af1d1
--- /dev/null
@@ -0,0 +1,149 @@
+// 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
diff --git a/WindCore/sa1100/interrupt_controller.cpp b/WindCore/sa1100/interrupt_controller.cpp
new file mode 100644 (file)
index 0000000..3f6e433
--- /dev/null
@@ -0,0 +1,547 @@
+// 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
diff --git a/WindCore/sa1100/interrupt_controller.h b/WindCore/sa1100/interrupt_controller.h
new file mode 100644 (file)
index 0000000..ac4fe50
--- /dev/null
@@ -0,0 +1,158 @@
+// 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
diff --git a/WindCore/sa1100/lcd_controller.cpp b/WindCore/sa1100/lcd_controller.cpp
new file mode 100644 (file)
index 0000000..3981889
--- /dev/null
@@ -0,0 +1,207 @@
+// 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
diff --git a/WindCore/sa1100/lcd_controller.h b/WindCore/sa1100/lcd_controller.h
new file mode 100644 (file)
index 0000000..e8f0c0f
--- /dev/null
@@ -0,0 +1,192 @@
+// 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
diff --git a/WindCore/sa1100/os_timer.cpp b/WindCore/sa1100/os_timer.cpp
new file mode 100644 (file)
index 0000000..10bc5e5
--- /dev/null
@@ -0,0 +1,181 @@
+// 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
diff --git a/WindCore/sa1100/os_timer.h b/WindCore/sa1100/os_timer.h
new file mode 100644 (file)
index 0000000..3e10a6b
--- /dev/null
@@ -0,0 +1,113 @@
+// 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
diff --git a/WindCore/sa1100/power_manager.cpp b/WindCore/sa1100/power_manager.cpp
new file mode 100644 (file)
index 0000000..33a9e45
--- /dev/null
@@ -0,0 +1,84 @@
+// 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
diff --git a/WindCore/sa1100/power_manager.h b/WindCore/sa1100/power_manager.h
new file mode 100644 (file)
index 0000000..000e0ae
--- /dev/null
@@ -0,0 +1,81 @@
+// 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
diff --git a/WindCore/sa1100/reset_controller.cpp b/WindCore/sa1100/reset_controller.cpp
new file mode 100644 (file)
index 0000000..4e84aec
--- /dev/null
@@ -0,0 +1,48 @@
+// 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;
+    }
+  }
+}
diff --git a/WindCore/sa1100/reset_controller.h b/WindCore/sa1100/reset_controller.h
new file mode 100644 (file)
index 0000000..e4aed16
--- /dev/null
@@ -0,0 +1,64 @@
+// 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
diff --git a/WindCore/sa1100/serial_3.h b/WindCore/sa1100/serial_3.h
new file mode 100644 (file)
index 0000000..d25d5d1
--- /dev/null
@@ -0,0 +1,54 @@
+// 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
diff --git a/WindCore/sa1100/uart.cpp b/WindCore/sa1100/uart.cpp
new file mode 100644 (file)
index 0000000..66ab4b4
--- /dev/null
@@ -0,0 +1,322 @@
+// 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;
+    }
+  }
+}
diff --git a/WindCore/sa1100/uart.h b/WindCore/sa1100/uart.h
new file mode 100644 (file)
index 0000000..8a83cd8
--- /dev/null
@@ -0,0 +1,153 @@
+// 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