diff --git a/dev/tsunami_io.cc b/dev/tsunami_io.cc index 537e40a22..b6533dcba 100644 --- a/dev/tsunami_io.cc +++ b/dev/tsunami_io.cc @@ -1,9 +1,11 @@ /* $Id$ */ /* @file - * Tsunami DMA fake + * Tsunami I/O including PIC, PIT, RTC, DMA */ +#include + #include #include #include @@ -11,50 +13,43 @@ #include "base/trace.hh" #include "cpu/exec_context.hh" #include "dev/console.hh" -#include "dev/etherdev.hh" -#include "dev/scsi_ctrl.hh" #include "dev/tlaser_clock.hh" #include "dev/tsunami_io.hh" #include "dev/tsunamireg.h" #include "dev/tsunami.hh" #include "mem/functional_mem/memory_control.hh" #include "sim/builder.hh" -#include "sim/system.hh" using namespace std; + +#define UNIX_YEAR_OFFSET 52 + +//This will have to be dynamic if we want support usermode access of the RTC +#define RTC_RATE 1024 + +// Timer Event for Periodic interrupt of RTC TsunamiIO::RTCEvent::RTCEvent() : Event(&mainEventQueue) { - DPRINTF(Tsunami, "RTC Event Initilizing\n"); - rtc_uip = 0; - schedule(curTick + (curTick % ticksPerSecond)); + DPRINTF(MC146818, "RTC Event Initilizing\n"); + schedule(curTick + ticksPerSecond/RTC_RATE); } void TsunamiIO::RTCEvent::process() { - DPRINTF(Tsunami, "Timer Interrupt\n"); - if (rtc_uip == 0) { - rtc_uip = 1; //Signal a second has occured - schedule(curTick + (curTick % ticksPerSecond) - 10); - } - else - rtc_uip = 0; //Done signaling second has occured - schedule(curTick + (curTick % ticksPerSecond)); + DPRINTF(MC146818, "Timer Interrupt\n"); + schedule(curTick + ticksPerSecond/RTC_RATE); + //Actually interrupt the processor here } const char * TsunamiIO::RTCEvent::description() { - return "tsunami RTC changte second"; -} - -uint8_t -TsunamiIO::RTCEvent::rtc_uip_value() -{ - return rtc_uip; + return "tsunami RTC 1024Hz interrupt"; } +// Timer Event for PIT Timers TsunamiIO::ClockEvent::ClockEvent() : Event(&mainEventQueue) { @@ -76,7 +71,8 @@ void TsunamiIO::ClockEvent::Program(int count) { DPRINTF(Tsunami, "Timer set to curTick + %d\n", count); - interval = count * ticksPerSecond/1193180UL; // should be count * (cpufreq/pitfreq) + // should be count * (cpufreq/pitfreq) + interval = count * ticksPerSecond/1193180UL; schedule(curTick + interval); status = 0; } @@ -100,11 +96,22 @@ TsunamiIO::ClockEvent::Status() } -TsunamiIO::TsunamiIO(const string &name, /*Tsunami *t,*/ + + +TsunamiIO::TsunamiIO(const string &name, /*Tsunami *t,*/ time_t init_time, Addr addr, Addr mask, MemoryController *mmu) : MmapDevice(name, addr, mask, mmu)/*, tsunami(t) */ { timerData = 0; + set_time(init_time == 0 ? time(NULL) : init_time); + uip = 1; +} + +void +TsunamiIO::set_time(time_t t) +{ + gmtime_r(&t, &tm); + DPRINTFN("Real-time clock set to %s", asctime(&tm)); } Fault @@ -123,6 +130,47 @@ TsunamiIO::read(MemReqPtr req, uint8_t *data) case TSDEV_TMR_CTL: *(uint8_t*)data = timer2.Status(); return No_Fault; + case TSDEV_RTC_DATA: + switch(RTCAddress) { + case RTC_CONTROL_REGISTERA: + *(uint8_t*)data = uip << 7 | 0x26; + uip = !uip; + return No_Fault; + case RTC_CONTROL_REGISTERB: + // DM and 24/12 and UIE + *(uint8_t*)data = 0x46; + return No_Fault; + case RTC_CONTROL_REGISTERC: + // If we want to support RTC user access in linux + // This won't work, but for now it's fine + *(uint8_t*)data = 0x00; + return No_Fault; + case RTC_CONTROL_REGISTERD: + panic("RTC Control Register D not implemented"); + case RTC_SECOND: + *(uint8_t *)data = tm.tm_sec; + return No_Fault; + case RTC_MINUTE: + *(uint8_t *)data = tm.tm_min; + return No_Fault; + case RTC_HOUR: + *(uint8_t *)data = tm.tm_hour; + return No_Fault; + case RTC_DAY_OF_WEEK: + *(uint8_t *)data = tm.tm_wday; + return No_Fault; + case RTC_DAY_OF_MONTH: + *(uint8_t *)data = tm.tm_mday; + case RTC_MONTH: + *(uint8_t *)data = tm.tm_mon + 1; + return No_Fault; + case RTC_YEAR: + *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET; + return No_Fault; + default: + panic("Unknown RTC Address\n"); + } + default: panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); } @@ -177,13 +225,9 @@ TsunamiIO::write(MemReqPtr req, const uint8_t *data) case 0: timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1); break; - case 1: - timer1.ChangeMode((*(uint8_t*)data & 0xF) >> 1); - break; case 2: timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1); break; - case 3: default: panic("Read Back Command not implemented\n"); } @@ -212,6 +256,11 @@ TsunamiIO::write(MemReqPtr req, const uint8_t *data) timerData |= 0x1000; } return No_Fault; + case TSDEV_RTC_ADDR: + RTCAddress = *(uint8_t*)data; + return No_Fault; + case TSDEV_RTC_DATA: + panic("RTC Write not implmented (rtc.o won't work)\n"); default: panic("I/O Write - va%#x size %d\n", req->vaddr, req->size); } @@ -241,6 +290,7 @@ TsunamiIO::unserialize(Checkpoint *cp, const std::string §ion) BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) // SimObjectParam tsunami; + Param time; SimObjectParam mmu; Param addr; Param mask; @@ -250,6 +300,8 @@ END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) // INIT_PARAM(tsunami, "Tsunami"), + INIT_PARAM_DFLT(time, "System time to use " + "(0 for actual time, default is 1/1/06", ULL(1136073600)), INIT_PARAM(mmu, "Memory Controller"), INIT_PARAM(addr, "Device Address"), INIT_PARAM(mask, "Address Mask") @@ -258,7 +310,7 @@ END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) CREATE_SIM_OBJECT(TsunamiIO) { - return new TsunamiIO(getInstanceName(), /*tsunami,*/ addr, mask, mmu); + return new TsunamiIO(getInstanceName(), /*tsunami,*/ time, addr, mask, mmu); } REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) diff --git a/dev/tsunami_io.hh b/dev/tsunami_io.hh index 4e342523f..fe904605c 100644 --- a/dev/tsunami_io.hh +++ b/dev/tsunami_io.hh @@ -42,7 +42,13 @@ class TsunamiIO : public MmapDevice { - public: + private: + struct tm tm; + + // In Tsunami RTC only has two i/o ports + // one for data and one for address, so you + // write the address and then read/write the data + uint8_t RTCAddress; protected: @@ -66,33 +72,43 @@ class TsunamiIO : public MmapDevice class RTCEvent : public Event { - protected: - Tick interval; - uint8_t rtc_uip; - public: RTCEvent(); virtual void process(); virtual const char *description(); - uint8_t rtc_uip_value(); }; + uint8_t uip; + uint8_t mask1; uint8_t mask2; uint8_t mode1; uint8_t mode2; + /* This timer is initilized, but after I wrote the code + it doesn't seem to be used again, and best I can tell + it too is not connected to any interrupt port */ ClockEvent timer0; - ClockEvent timer1; + + /* This timer is used to control the speaker, which + we normally could care less about, however it is + also used to calculated the clockspeed and hense + bogomips which is kinda important to the scheduler + so we need to implemnt it although after boot I can't + imagine we would be playing with the PC speaker much */ ClockEvent timer2; + RTCEvent rtc; + uint32_t timerData; public: - TsunamiIO(const std::string &name, /*Tsunami *t,*/ + TsunamiIO(const std::string &name, /*Tsunami *t,*/ time_t init_time, Addr addr, Addr mask, MemoryController *mmu); + void set_time(time_t t); + virtual Fault read(MemReqPtr req, uint8_t *data); virtual Fault write(MemReqPtr req, const uint8_t *data); diff --git a/dev/tsunami_uart.cc b/dev/tsunami_uart.cc new file mode 100644 index 000000000..88f6a6f8a --- /dev/null +++ b/dev/tsunami_uart.cc @@ -0,0 +1,199 @@ +/* $Id$ */ + +/* @file + * Tsunami UART + */ + +/* + * Copyright (C) 1998 by the Board of Trustees + * of Leland Stanford Junior University. + * Copyright (C) 1998 Digital Equipment Corporation + * + * This file is part of the SimOS distribution. + * See LICENSE file for terms of the license. + * + */ + +#include +#include + +#include "base/inifile.hh" +#include "base/str.hh" // for to_number +#include "base/trace.hh" +#include "dev/console.hh" +#include "dev/tsunami_uart.hh" +#include "mem/functional_mem/memory_control.hh" +#include "sim/builder.hh" +#include "targetarch/ev5.hh" + +using namespace std; + +#define CONS_INT_TX 0x01 // interrupt enable / state bits +#define CONS_INT_RX 0x02 + +TsunamiUart::TsunamiUart(const string &name, SimConsole *c, + Addr addr, Addr mask, MemoryController *mmu) + : MmapDevice(name, addr, mask, mmu), + cons(c), status_store(0), next_char(-1) +{ +} + +Fault +TsunamiUart::read(MemReqPtr req, uint8_t *data) +{ + Addr daddr = req->paddr & addr_mask; + + switch (req->size) { + case sizeof(uint64_t): + *(uint64_t *)data = 0; + break; + case sizeof(uint32_t): + *(uint32_t *)data = 0; + break; + case sizeof(uint16_t): + *(uint16_t *)data = 0; + break; + case sizeof(uint8_t): + *(uint8_t *)data = 0; + break; + } + + switch (daddr) { + case 0xD: // Status Register + { + int status = cons->intStatus(); + if (next_char < 0) { + next_char = cons->in(); + if (next_char < 0) { + status &= ~CONS_INT_RX; + } + } else { + status |= CONS_INT_RX; + } + + if (status_store == 3) { + // RR3 stuff? Don't really understand it, btw + status_store = 0; + if (status & CONS_INT_TX) { + *data = (1 << 4); + return No_Fault; + } else if (status & CONS_INT_RX) { + *data = (1 << 5); + return No_Fault; + } else { + DPRINTF(TsunamiUart, "spurious read\n"); + return No_Fault; + } + } else { + int reg = (1 << 2); + if (status & CONS_INT_RX) + reg |= (1 << 0); + *data = reg; + return No_Fault; + } + break; + } + + case 0x8: // Data register (RX) + if (next_char < 0) + panic("Invalid character"); + + DPRINTF(TsunamiUart, "read data register \'%c\' %#02x\n", + isprint(next_char) ? next_char : ' ', next_char); + + *data = next_char; + next_char = -1; +// cons.next(); + return No_Fault; + } + + panic("%s: read daddr=%#x type=read *data=%#x\n", name(), daddr, *data); + + return No_Fault; +} + +Fault +TsunamiUart::write(MemReqPtr req, const uint8_t *data) +{ + Addr daddr = req->paddr & addr_mask; + switch (daddr) { + case 0xb: + status_store = *data; + switch (*data) { + case 0x03: // going to read RR3 + return No_Fault; + + case 0x28: // Ack of TX + { + if ((cons->intStatus() & CONS_INT_TX) == 0) + panic("Ack of transmit, though there was no interrupt"); + + cons->clearInt(CONS_INT_TX); + return No_Fault; + } + + case 0x00: + case 0x01: + case 0x12: + // going to write data??? + return No_Fault; + + default: + DPRINTF(TsunamiUart, "writing status register %#x \n", + *(uint64_t *)data); + return No_Fault; + } + + case 0x8: // Data register (TX) + cons->out(*(uint64_t *)data); + return No_Fault; + case 0x9: // DLM + DPRINTF(TsunamiUart, "writing to DLM/IER %#x\n", *(uint64_t*)data); + return No_Fault; + case 0xc: // MCR + DPRINTF(TsunamiUart, "writing to MCR %#x\n", *(uint64_t*)data); + return No_Fault; + + } + + return No_Fault; +} + +void +TsunamiUart::serialize(ostream &os) +{ + SERIALIZE_SCALAR(status_store); + SERIALIZE_SCALAR(next_char); +} + +void +TsunamiUart::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(status_store); + UNSERIALIZE_SCALAR(next_char); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart) + + SimObjectParam console; + SimObjectParam mmu; + Param addr; + Param mask; + +END_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiUart) + + INIT_PARAM(console, "The console"), + INIT_PARAM(mmu, "Memory Controller"), + INIT_PARAM(addr, "Device Address"), + INIT_PARAM(mask, "Address Mask") + +END_INIT_SIM_OBJECT_PARAMS(TsunamiUart) + +CREATE_SIM_OBJECT(TsunamiUart) +{ + return new TsunamiUart(getInstanceName(), console, addr, mask, mmu); +} + +REGISTER_SIM_OBJECT("TsunamiUart", TsunamiUart) diff --git a/dev/tsunami_uart.hh b/dev/tsunami_uart.hh new file mode 100644 index 000000000..a1bd7006d --- /dev/null +++ b/dev/tsunami_uart.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Tsunami UART + */ + +#ifndef __TSUNAMI_UART_HH__ +#define __TSUNAMI_UART_HH__ + +#include "mem/functional_mem/mmap_device.hh" + +class SimConsole; + +/* + * Tsunami UART + */ +class TsunamiUart : public MmapDevice +{ + protected: + SimConsole *cons; + int status_store; + int next_char; + + public: + TsunamiUart(const std::string &name, SimConsole *c, + Addr addr, Addr mask, MemoryController *mmu); + + Fault read(MemReqPtr req, uint8_t *data); + Fault write(MemReqPtr req, const uint8_t *data); + + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __TSUNAMI_UART_HH__ diff --git a/dev/tsunamireg.h b/dev/tsunamireg.h index f178974b9..7201edf94 100644 --- a/dev/tsunamireg.h +++ b/dev/tsunamireg.h @@ -78,4 +78,26 @@ #define TSDEV_TMR2_CTL 0x43 #define TSDEV_TMR2_DATA 0x42 #define TSDEV_TMR0_DATA 0x40 + +#define TSDEV_RTC_ADDR 0x70 +#define TSDEV_RTC_DATA 0x71 + +// RTC defines +#define RTC_SECOND 0 // second of minute [0..59] +#define RTC_SECOND_ALARM 1 // seconds to alarm +#define RTC_MINUTE 2 // minute of hour [0..59] +#define RTC_MINUTE_ALARM 3 // minutes to alarm +#define RTC_HOUR 4 // hour of day [0..23] +#define RTC_HOUR_ALARM 5 // hours to alarm +#define RTC_DAY_OF_WEEK 6 // day of week [1..7] +#define RTC_DAY_OF_MONTH 7 // day of month [1..31] +#define RTC_MONTH 8 // month of year [1..12] +#define RTC_YEAR 9 // year [00..99] +#define RTC_CONTROL_REGISTERA 10 // control register A +#define RTC_CONTROL_REGISTERB 11 // control register B +#define RTC_CONTROL_REGISTERC 12 // control register C +#define RTC_CONTROL_REGISTERD 13 // control register D +#define RTC_REGNUMBER_RTC_CR1 0x6A // control register 1 + + #endif // __TSUNAMIREG_H__ diff --git a/kern/linux/linux_system.cc b/kern/linux/linux_system.cc index fe655ad74..db67c5619 100644 --- a/kern/linux/linux_system.cc +++ b/kern/linux/linux_system.cc @@ -265,13 +265,13 @@ LinuxSystem::LinuxSystem(const string _name, const uint64_t _init_param, #endif //FS_MEASURE Addr addr = 0; - if (kernelSymtab->findAddress("enable_async_printf", addr)) { + if (kernelSymtab->findAddress("est_cycle_freq", addr)) { Addr paddr = vtophys(physmem, addr); - uint8_t *enable_async_printf = - physmem->dma_addr(paddr, sizeof(uint32_t)); + uint8_t *est_cycle_frequency = + physmem->dma_addr(paddr, sizeof(uint64_t)); - if (enable_async_printf) - *(uint32_t *)enable_async_printf = 0; + if (est_cycle_frequency) + *(uint64_t *)est_cycle_frequency = ticksPerSecond; } if (consoleSymtab->findAddress("env_booted_osflags", addr)) {