int func = (daddr >> 8) & 0x7;
int reg = daddr & 0xFF;
- union {
- uint8_t byte_value;
- uint16_t half_value;
- uint32_t word_value;
- };
+ uint32_t word_value = 0;
if (devices[device][func] == NULL)
panic("Attempting to write to config space on non-existant device\n");
else {
switch (req->size) {
case sizeof(uint8_t):
- byte_value = *(uint8_t*)data;
+ word_value = *(uint8_t*)data;
break;
case sizeof(uint16_t):
- half_value = *(uint16_t*)data;
+ word_value = *(uint16_t*)data;
break;
case sizeof(uint32_t):
word_value = *(uint32_t*)data;
void
PciDev::ReadConfig(int offset, int size, uint8_t *data)
{
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ };
+
if (offset >= PCI_DEVICE_SPECIFIC)
panic("Device specific PCI config space not implemented!\n");
- switch(size) {
- case sizeof(uint32_t):
- memcpy(data, &config.data[offset], sizeof(uint32_t));
- *(uint32_t*)data = htoa(*(uint32_t*)data);
+ dword = 0;
- DPRINTF(PCIDEV,
- "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
- params()->deviceNum, params()->functionNum, offset, size,
- *(uint32_t*)data);
+ switch(size) {
+ case sizeof(uint8_t):
+ memcpy(&byte, &config.data[offset], size);
+ *data = byte;
break;
-
case sizeof(uint16_t):
- memcpy(data, &config.data[offset], sizeof(uint16_t));
- *(uint16_t*)data = htoa(*(uint16_t*)data);
-
- DPRINTF(PCIDEV,
- "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
- params()->deviceNum, params()->functionNum, offset, size,
- *(uint16_t*)data);
+ memcpy(&byte, &config.data[offset], size);
+ *(uint16_t*)data = htoa(word);
break;
-
- case sizeof(uint8_t):
- memcpy(data, &config.data[offset], sizeof(uint8_t));
- DPRINTF(PCIDEV,
- "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
- params()->deviceNum, params()->functionNum, offset, size,
- *data);
+ case sizeof(uint32_t):
+ memcpy(&byte, &config.data[offset], size);
+ *(uint32_t*)data = htoa(dword);
break;
-
default:
panic("Invalid PCI configuration read size!\n");
}
+
+ DPRINTF(PCIDEV,
+ "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
+ params()->deviceNum, params()->functionNum, offset, size,
+ htoa(dword));
}
void
uint32_t barnum;
- union {
- uint8_t byte_value;
- uint16_t half_value;
- uint32_t word_value;
- };
- word_value = data;
-
DPRINTF(PCIDEV,
"write device: %#x function: %#x reg: %#x size: %d data: %#x\n",
params()->deviceNum, params()->functionNum, offset, size,
- word_value);
+ data);
barnum = (offset - PCI0_BASE_ADDR0) >> 2;
switch (size) {
case sizeof(uint8_t): // 1-byte access
+ uint8_t byte_value = data;
switch (offset) {
case PCI0_INTERRUPT_LINE:
case PCI_CACHE_LINE_SIZE:
break;
case sizeof(uint16_t): // 2-byte access
+ uint16_t half_value = data;
switch (offset) {
case PCI_COMMAND:
case PCI_STATUS:
}
break;
- case sizeof(uint16_t)+1: // 3-byte access
- panic("invalid access size");
-
case sizeof(uint32_t): // 4-byte access
+ uint32_t word_value = data;
switch (offset) {
case PCI0_BASE_ADDR0:
case PCI0_BASE_ADDR1:
// This is I/O Space, bottom two bits are read only
if (htoa(config.data[offset]) & 0x1) {
*(uint32_t *)&config.data[offset] = htoa(
- ~(BARSize[barnum] - 1) |
+ (~(BARSize[barnum] - 1) & ~0x3) |
(htoa(config.data[offset]) & 0x3));
} else {
// This is memory space, bottom four bits are read only
*(uint32_t *)&config.data[offset] = htoa(
- ~(BARSize[barnum] - 1) |
+ (~(BARSize[barnum] - 1) & ~0xF) |
(htoa(config.data[offset]) & 0xF));
}
} else {
htoa((word_value & ~0x3) |
(htoa(config.data[offset]) & 0x3));
- if (word_value != 0x1) {
+ if (word_value &= ~0x1) {
Addr base_addr = (word_value & ~0x1) + TSUNAMI_PCI0_IO;
Addr base_size = BARSize[barnum];
DPRINTF(PCIDEV, "Writing to a read only register");
}
break;
+
+ default:
+ panic("invalid access size");
}
}
#define RTC_DOM 0x07
#define RTC_MON 0x08
#define RTC_YEAR 0x09
+
#define RTC_CNTRL_REGA 0x0A
+#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */
+#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */
+#define RTCA_UIP 0x80 /* 1 = date and time update in progress */
+
#define RTC_CNTRL_REGB 0x0B
+#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */
+#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
+#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */
+#define RTCB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */
+#define RTCB_UPDT_IE 0x10 /* 1 = enable update-ended interrupt */
+#define RTCB_ALRM_IE 0x20 /* 1 = enable alarm interrupt */
+#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */
+#define RTCB_NO_UPDT 0x80 /* stop clock updates */
+
#define RTC_CNTRL_REGC 0x0C
#define RTC_CNTRL_REGD 0x0D
#define UNIX_YEAR_OFFSET 52
-struct tm TsunamiIO::tm = { 0 };
-
// Timer Event for Periodic interrupt of RTC
TsunamiIO::RTCEvent::RTCEvent(Tsunami* t, Tick i)
: Event(&mainEventQueue), tsunami(t), interval(i)
{
DPRINTF(MC146818, "RTC Event Initilizing\n");
- intr_count = 0;
schedule(curTick + interval);
}
schedule(curTick + interval);
//Actually interrupt the processor here
tsunami->cchip->postRTC();
-
- if (intr_count == 1023)
- tm.tm_sec = (tm.tm_sec + 1) % 60;
-
- intr_count = (intr_count + 1) % 1024;
-
}
const char *
reschedule(time);
}
+void
+TsunamiIO::RTCEvent::scheduleIntr()
+{
+ schedule(curTick + interval);
+}
// Timer Event for PIT Timers
TsunamiIO::ClockEvent::ClockEvent()
DPRINTF(Tsunami, "Timer Interrupt\n");
if (mode == 0)
status = 0x20; // set bit that linux is looking for
- else
- schedule(curTick + interval);
-
- current_count--; //decrement count
+ else if (mode == 2)
+ schedule(curTick + current_count*interval);
}
void
DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n",
req->vaddr, req->size, req->vaddr & 0xfff);
- Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) + 0x20;
+ Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
switch(req->size) {
case TSDEV_RTC_DATA:
switch(RTCAddress) {
case RTC_CNTRL_REGA:
- *(uint8_t*)data = uip << 7 | 0x26;
+ *(uint8_t*)data = uip << 7 | RTCA_32768HZ | RTCA_1024HZ;
uip = !uip;
return No_Fault;
case RTC_CNTRL_REGB:
// DM and 24/12 and UIE
- *(uint8_t*)data = 0x46;
+ *(uint8_t*)data = RTCB_PRDC_IE | RTCB_BIN | RTCB_24HR;
return No_Fault;
case RTC_CNTRL_REGC:
// If we want to support RTC user access in linux
return No_Fault;
case RTC_CNTRL_REGD:
panic("RTC Control Register D not implemented");
+ case RTC_SEC_ALRM:
+ case RTC_MIN_ALRM:
+ case RTC_HR_ALRM:
+ // RTC alarm functionality is not currently implemented
+ *(uint8_t *)data = 0x00;
+ return No_Fault;
case RTC_SEC:
*(uint8_t *)data = tm.tm_sec;
return No_Fault;
*(uint8_t *)data = tm.tm_hour;
return No_Fault;
case RTC_DOW:
- *(uint8_t *)data = tm.tm_wday;
+ *(uint8_t *)data = tm.tm_wday + 1;
return No_Fault;
case RTC_DOM:
- *(uint8_t *)data = tm.tm_mday;
+ *(uint8_t *)data = tm.tm_mday + 1;
return No_Fault;
case RTC_MON:
*(uint8_t *)data = tm.tm_mon + 1;
return No_Fault;
case RTC_YEAR:
- *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
+ *(uint8_t *)data = tm.tm_year;
return No_Fault;
default:
panic("Unknown RTC Address\n");
DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
req->vaddr, req->size, req->vaddr & 0xfff, dt64);
- Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) + 0x20;
+ Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
switch(req->size) {
case sizeof(uint8_t):
switch(*(uint8_t*)data >> 6) {
case 0:
timer0.LatchCount();
- break;
+ return No_Fault;
case 2:
timer2.LatchCount();
- break;
+ return No_Fault;
default:
panic("Read Back Command not implemented\n");
}
/* two writes before we actually start the Timer
so I set a flag in the timerData */
if(timerData & 0x1000) {
- timerData &= 0x1000;
+ timerData &= ~0x1000;
timerData += *(uint8_t*)data << 8;
timer0.Program(timerData);
+ timerData = 0;
} else {
timerData = *(uint8_t*)data;
timerData |= 0x1000;
case TSDEV_RTC_DATA:
switch(RTCAddress) {
case RTC_CNTRL_REGA:
+ if (*data != (RTCA_32768HZ | RTCA_1024HZ))
+ panic("Unimplemented RTC register A value write!\n");
return No_Fault;
case RTC_CNTRL_REGB:
+ if ((*data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
+ panic("Write to RTC reg B bits that are not implemented!\n");
+
+ if (*data & RTCB_PRDC_IE) {
+ if (!rtc.scheduled())
+ rtc.scheduleIntr();
+ } else {
+ if (rtc.scheduled())
+ rtc.deschedule();
+ }
return No_Fault;
case RTC_CNTRL_REGC:
+ panic("Write to RTC reg C not implemented!\n");
return No_Fault;
case RTC_CNTRL_REGD:
+ panic("Write to RTC reg D not implemented!\n");
return No_Fault;
case RTC_SEC:
tm.tm_sec = *(uint8_t *)data;
tm.tm_mday = *(uint8_t *)data;
return No_Fault;
case RTC_MON:
- tm.tm_mon = *(uint8_t *)data - 1;
+ tm.tm_mon = *(uint8_t *)data;
return No_Fault;
case RTC_YEAR:
- tm.tm_year = *(uint8_t *)data + UNIX_YEAR_OFFSET;
+ tm.tm_year = *(uint8_t *)data;
return No_Fault;
//panic("RTC Write not implmented (rtc.o won't work)\n");
}
/** The size of mappad from the above address */
static const Addr size = 0xff;
- static struct tm tm;
+ struct tm tm;
/**
* In Tsunami RTC only has two i/o ports one for data and one for
Tsunami* tsunami;
Tick interval;
- /** Count of the number of RTC interrupts that have occured */
- uint32_t intr_count;
-
public:
/**
* RTC Event initializes the RTC event by scheduling an event
RTCEvent(Tsunami* t, Tick i);
/**
- * Interrupth the processor and reschedule the event.
+ * Interrupt the processor and reschedule the event.
*/
virtual void process();
* @param section The section name of this object
*/
virtual void unserialize(Checkpoint *cp, const std::string §ion);
+
+ void scheduleIntr();
};
/** uip UpdateInProgess says that the rtc is updating, but we just fake it
* This variable contains a flag as to how many writes have happened, and
* the time so far.
*/
- uint32_t timerData;
+ uint16_t timerData;
public:
/**
break;
case 0x2: // Intr Identification Register (IIR)
DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
- if (status)
- *(uint8_t*)data = 0;
+ status &= ~TX_INT;
+ if (status & RX_INT)
+ *(uint8_t*)data = IIR_RXID;
else
- *(uint8_t*)data = 1;
+ *(uint8_t*)data = IIR_NOPEND;
break;
case 0x3: // Line Control Register (LCR)
*(uint8_t*)data = LCR;
#include "dev/io_device.hh"
#include "dev/uart.hh"
+#define IIR_NOPEND 0x1
+#define IIR_RXID 0x4
+
class SimConsole;
class Platform;
skipCalibrateClocks = new FreebsdSkipCalibrateClocksEvent(&pcEventQueue, "calibrate_clocks");
if (kernelSymtab->findAddress("calibrate_clocks", addr))
skipCalibrateClocks->schedule(addr + sizeof(MachInst) * 2);
-
}
class FreebsdSystem : public System
{
private:
-
SkipFuncEvent *skipDelayEvent;
-
FreebsdSkipCalibrateClocksEvent *skipCalibrateClocks;
public:
pci_func = Param.Int("PCI function code")
configdata = Param.PciConfigData(Parent.any, "PCI Config data")
configspace = Param.PciConfigAll(Parent.any, "PCI Configspace")
+
+class PciFake(PciDevice):
+ type = 'PciFake'