2005-06-05 07:22:21 +02:00
|
|
|
/*
|
2005-06-05 11:16:00 +02:00
|
|
|
* Copyright (c) 2005 The Regents of The University of Michigan
|
2005-06-05 07:22:21 +02:00
|
|
|
* 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.
|
2006-06-01 01:26:56 +02:00
|
|
|
*
|
|
|
|
* Authors: Ali Saidi
|
2005-06-05 07:22:21 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/** @file
|
|
|
|
* Implements a 8250 UART
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "base/inifile.hh"
|
|
|
|
#include "base/str.hh" // for to_number
|
|
|
|
#include "base/trace.hh"
|
2009-09-23 17:34:21 +02:00
|
|
|
#include "config/the_isa.hh"
|
2011-04-15 19:44:32 +02:00
|
|
|
#include "debug/Uart.hh"
|
2005-06-05 07:22:21 +02:00
|
|
|
#include "dev/platform.hh"
|
2008-06-18 05:29:06 +02:00
|
|
|
#include "dev/terminal.hh"
|
|
|
|
#include "dev/uart8250.hh"
|
2006-10-20 08:38:45 +02:00
|
|
|
#include "mem/packet.hh"
|
|
|
|
#include "mem/packet_access.hh"
|
2005-06-05 07:22:21 +02:00
|
|
|
|
|
|
|
using namespace std;
|
Changes to untemplate StaticInst and StaticInstPtr, change the isa to a namespace instead of a class, an improvement to the architecture specific header file selection system, and fixed up a few include paths.
arch/alpha/alpha_linux_process.cc:
Added using directive for AlphaISA namespace
arch/alpha/alpha_memory.hh:
arch/alpha/isa/branch.isa:
cpu/pc_event.hh:
Added typedefs for Addr
arch/alpha/alpha_tru64_process.cc:
arch/alpha/arguments.cc:
Added using directive for AlphaISA
arch/alpha/ev5.hh:
Added an include of arch/alpha/isa_traits.hh, and a using directive for the AlphaISA namespace.
arch/alpha/faults.hh:
Added a typedef for the Addr type, and changed the formatting of the faults slightly.
arch/alpha/isa/main.isa:
Untemplatized StaticInst, added a using for namespace AlphaISA to show up in decoder.cc and the exec.ccs, relocated makeNop to decoder.hh
arch/alpha/isa/mem.isa:
Untemplatized StaticInst and StaticInstPtr
arch/alpha/isa/pal.isa:
cpu/base_dyn_inst.cc:
Untemplatized StaticInstPtr
arch/alpha/isa_traits.hh:
Changed variables to be externs instead of static since they are part of a namespace and not a class.
arch/alpha/stacktrace.cc:
Untemplatized StaticInstPtr, and added a using directive for AlphaISA.
arch/alpha/stacktrace.hh:
Added some typedefs for Addr and MachInst, and untemplatized StaticInstPtr
arch/alpha/vtophys.cc:
Added a using directive for AlphaISA
arch/alpha/vtophys.hh:
Added the AlphaISA namespace specifier where needed
arch/isa_parser.py:
Changed the placement of the definition of the decodeInst function to be outside the namespaceInst namespace.
base/loader/object_file.hh:
cpu/o3/bpred_unit.hh:
Added a typedef for Addr
base/loader/symtab.hh:
Added a typedef for Addr, and added a TheISA to Addr in another typedef
base/remote_gdb.cc:
Added a using namespace TheISA, and untemplatized StaticInstPtr
base/remote_gdb.hh:
Added typedefs for Addr and MachInst
cpu/base.cc:
Added TheISA specifier to some variables exported from the isa.
cpu/base.hh:
Added a typedef for Addr, and TheISA to some variables from the ISA
cpu/base_dyn_inst.hh:
Untemplatized StaticInstPtr, and added TheISA specifier to some variables from the ISA.
cpu/exec_context.hh:
Added some typedefs for types from the isa, and added TheISA specifier to some variables from the isa
cpu/exetrace.hh:
Added typedefs for some types from the ISA, and untemplatized StaticInstPtr
cpu/memtest/memtest.cc:
cpu/o3/btb.cc:
dev/baddev.cc:
dev/ide_ctrl.cc:
dev/ide_disk.cc:
dev/isa_fake.cc:
dev/ns_gige.cc:
dev/pciconfigall.cc:
dev/platform.cc:
dev/sinic.cc:
dev/uart8250.cc:
kern/freebsd/freebsd_system.cc:
kern/linux/linux_system.cc:
kern/system_events.cc:
kern/tru64/dump_mbuf.cc:
kern/tru64/tru64_events.cc:
sim/process.cc:
sim/pseudo_inst.cc:
sim/system.cc:
Added using namespace TheISA
cpu/memtest/memtest.hh:
cpu/trace/opt_cpu.hh:
cpu/trace/reader/itx_reader.hh:
dev/ide_disk.hh:
dev/pcidev.hh:
dev/platform.hh:
dev/tsunami.hh:
sim/system.hh:
sim/vptr.hh:
Added typedef for Addr
cpu/o3/2bit_local_pred.hh:
Changed the include to use arch/isa_traits.hh instead of arch/alpha/isa_traits.hh. Added typedef for Addr
cpu/o3/alpha_cpu.hh:
Added typedefs for Addr and IntReg
cpu/o3/alpha_cpu_impl.hh:
Added this-> to setNextPC to fix a problem since it didn't depend on template parameters any more. Removed "typename" where it was no longer needed.
cpu/o3/alpha_dyn_inst.hh:
Cleaned up some typedefs, and untemplatized StaticInst
cpu/o3/alpha_dyn_inst_impl.hh:
untemplatized StaticInstPtr
cpu/o3/alpha_impl.hh:
Fixed up a typedef of MachInst
cpu/o3/bpred_unit_impl.hh:
Added a using TheISA::MachInst to a function
cpu/o3/btb.hh:
Changed an include from arch/alpha/isa_traits.hh to arch/isa_traits.hh, and added a typedef for Addr
cpu/o3/commit.hh:
Removed a typedef of Impl::ISA as ISA, since TheISA takes care of this now.
cpu/o3/cpu.cc:
Cleaned up namespace issues
cpu/o3/cpu.hh:
Cleaned up namespace usage
cpu/o3/decode.hh:
Removed typedef of ISA, and changed it to TheISA
cpu/o3/fetch.hh:
Fized up typedefs, and changed ISA to TheISA
cpu/o3/free_list.hh:
Changed include of arch/alpha/isa_traits.hh to arch/isa_traits.hh
cpu/o3/iew.hh:
Removed typedef of ISA
cpu/o3/iew_impl.hh:
Added TheISA namespace specifier to MachInst
cpu/o3/ras.hh:
Changed include from arch/alpha/isa_traits.hh to arch/isa_traits.hh, and added a typedef for Addr.
cpu/o3/regfile.hh:
Changed ISA to TheISA, and added some typedefs for Addr, IntReg, FloatReg, and MiscRegFile
cpu/o3/rename.hh:
Changed ISA to TheISA, and added a typedef for RegIndex
cpu/o3/rename_map.hh:
Added an include for arch/isa_traits.hh, and a typedef for RegIndex
cpu/o3/rob.hh:
Added a typedef for RegIndex
cpu/o3/store_set.hh:
cpu/o3/tournament_pred.hh:
Changed an include of arch/alpha/isa_traits.hh to arch/isa_traits.hh, and added a typedef of Addr
cpu/ozone/cpu.hh:
Changed ISA into TheISA, and untemplatized StaticInst
cpu/pc_event.cc:
Added namespace specifier TheISA to Addr types
cpu/profile.hh:
kern/kernel_stats.hh:
Added typedef for Addr, and untemplatized StaticInstPtr
cpu/simple/cpu.cc:
Changed using directive from LittleEndianGuest to AlphaISA, which will contain both namespaces. Added TheISA where needed, and untemplatized StaticInst
cpu/simple/cpu.hh:
Added a typedef for MachInst, and untemplatized StaticInst
cpu/static_inst.cc:
Untemplatized StaticInst
cpu/static_inst.hh:
Untemplatized StaticInst by using the TheISA namespace
dev/alpha_console.cc:
Added using namespace AlphaISA
dev/simple_disk.hh:
Added typedef for Addr and fixed up some formatting
dev/sinicreg.hh:
Added TheISA namespace specifier where needed
dev/tsunami.cc:
dev/tsunami_io.cc:
dev/tsunami_pchip.cc:
Added using namespace TheISA. It might be better for it to be AlphaISA
dev/tsunami_cchip.cc:
Added typedef for TheISA. It might be better for it to be AlphaISA
kern/linux/aligned.hh:
sim/pseudo_inst.hh:
Added TheISA namespace specifier to Addr
kern/linux/linux_threadinfo.hh:
Added typedef for Addr, and TheISA namespace specifier to StackPointerReg
kern/tru64/mbuf.hh:
Added TheISA to Addr type in structs
sim/process.hh:
Added typedefs of Addr, RegFile, and MachInst
sim/syscall_emul.cc:
Added using namespace TheISA, and a cast of VMPageSize to the int type
sim/syscall_emul.hh:
Added typecast for Addr, and TheISA namespace specifier for where needed
--HG--
extra : convert_revision : 91d4f6ca33a73b21c1f1771d74bfdea3b80eff45
2006-02-19 08:34:37 +01:00
|
|
|
using namespace TheISA;
|
2005-06-05 07:22:21 +02:00
|
|
|
|
|
|
|
Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit)
|
2008-10-09 13:58:24 +02:00
|
|
|
: uart(u)
|
2005-06-05 07:22:21 +02:00
|
|
|
{
|
|
|
|
DPRINTF(Uart, "UART Interrupt Event Initilizing\n");
|
|
|
|
intrBit = bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
2008-02-06 22:32:40 +01:00
|
|
|
Uart8250::IntrEvent::description() const
|
2005-06-05 07:22:21 +02:00
|
|
|
{
|
2007-07-01 02:45:58 +02:00
|
|
|
return "uart interrupt delay";
|
2005-06-05 07:22:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Uart8250::IntrEvent::process()
|
|
|
|
{
|
|
|
|
if (intrBit & uart->IER) {
|
|
|
|
DPRINTF(Uart, "UART InterEvent, interrupting\n");
|
|
|
|
uart->platform->postConsoleInt();
|
|
|
|
uart->status |= intrBit;
|
2011-01-08 06:50:29 +01:00
|
|
|
uart->lastTxInt = curTick();
|
2005-06-05 07:22:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
DPRINTF(Uart, "UART InterEvent, not interrupting\n");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The linux serial driver (8250.c about line 1182) loops reading from
|
|
|
|
* the device until the device reports it has no more data to
|
|
|
|
* read. After a maximum of 255 iterations the code prints "serial8250
|
|
|
|
* too much work for irq X," and breaks out of the loop. Since the
|
|
|
|
* simulated system is so much slower than the actual system, if a
|
|
|
|
* user is typing on the keyboard it is very easy for them to provide
|
|
|
|
* input at a fast enough rate to not allow the loop to exit and thus
|
|
|
|
* the error to be printed. This magic number provides a delay between
|
|
|
|
* the time the UART receives a character to send to the simulated
|
|
|
|
* system and the time it actually notifies the system it has a
|
|
|
|
* character to send to alleviate this problem. --Ali
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
Uart8250::IntrEvent::scheduleIntr()
|
|
|
|
{
|
2010-04-16 01:24:12 +02:00
|
|
|
static const Tick interval = 225 * SimClock::Int::ns;
|
2005-06-05 07:22:21 +02:00
|
|
|
DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit,
|
2011-01-08 06:50:29 +01:00
|
|
|
curTick() + interval);
|
2005-06-05 07:22:21 +02:00
|
|
|
if (!scheduled())
|
2011-01-08 06:50:29 +01:00
|
|
|
uart->schedule(this, curTick() + interval);
|
2005-06-05 07:22:21 +02:00
|
|
|
else
|
2011-01-08 06:50:29 +01:00
|
|
|
uart->reschedule(this, curTick() + interval);
|
2005-06-05 07:22:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-24 06:51:38 +02:00
|
|
|
Uart8250::Uart8250(const Params *p)
|
2013-07-12 04:57:04 +02:00
|
|
|
: Uart(p, 8), IER(0), DLAB(0), LCR(0), MCR(0), lastTxInt(0),
|
2007-05-01 18:32:30 +02:00
|
|
|
txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT)
|
2005-06-05 07:22:21 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-04-06 20:57:51 +02:00
|
|
|
Tick
|
2006-10-20 09:10:12 +02:00
|
|
|
Uart8250::read(PacketPtr pkt)
|
2005-06-05 07:22:21 +02:00
|
|
|
{
|
2006-05-26 20:17:33 +02:00
|
|
|
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
|
|
|
|
assert(pkt->getSize() == 1);
|
2006-04-06 20:57:51 +02:00
|
|
|
|
2006-05-26 20:17:33 +02:00
|
|
|
Addr daddr = pkt->getAddr() - pioAddr;
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->allocate();
|
2006-04-06 20:57:51 +02:00
|
|
|
|
2005-06-05 07:22:21 +02:00
|
|
|
DPRINTF(Uart, " read register %#x\n", daddr);
|
|
|
|
|
|
|
|
switch (daddr) {
|
|
|
|
case 0x0:
|
|
|
|
if (!(LCR & 0x80)) { // read byte
|
2008-06-18 05:29:06 +02:00
|
|
|
if (term->dataAvailable())
|
|
|
|
pkt->set(term->in());
|
2005-06-05 07:22:21 +02:00
|
|
|
else {
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->set((uint8_t)0);
|
2005-06-05 07:22:21 +02:00
|
|
|
// A limited amount of these are ok.
|
|
|
|
DPRINTF(Uart, "empty read of RX register\n");
|
|
|
|
}
|
|
|
|
status &= ~RX_INT;
|
|
|
|
platform->clearConsoleInt();
|
|
|
|
|
2008-06-18 05:29:06 +02:00
|
|
|
if (term->dataAvailable() && (IER & UART_IER_RDI))
|
2005-06-05 07:22:21 +02:00
|
|
|
rxIntrEvent.scheduleIntr();
|
|
|
|
} else { // dll divisor latch
|
|
|
|
;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x1:
|
|
|
|
if (!(LCR & 0x80)) { // Intr Enable Register(IER)
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->set(IER);
|
2005-06-05 07:22:21 +02:00
|
|
|
} else { // DLM divisor latch MSB
|
|
|
|
;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x2: // Intr Identification Register (IIR)
|
|
|
|
DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
|
2005-08-15 22:59:58 +02:00
|
|
|
|
2005-08-16 21:44:57 +02:00
|
|
|
if (status & RX_INT) /* Rx data interrupt has a higher priority */
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->set(IIR_RXID);
|
2007-04-30 19:13:03 +02:00
|
|
|
else if (status & TX_INT) {
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->set(IIR_TXID);
|
2007-04-30 19:13:03 +02:00
|
|
|
//Tx interrupts are cleared on IIR reads
|
|
|
|
status &= ~TX_INT;
|
|
|
|
} else
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->set(IIR_NOPEND);
|
2005-08-16 21:44:57 +02:00
|
|
|
|
2005-06-05 07:22:21 +02:00
|
|
|
break;
|
|
|
|
case 0x3: // Line Control Register (LCR)
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->set(LCR);
|
2005-06-05 07:22:21 +02:00
|
|
|
break;
|
|
|
|
case 0x4: // Modem Control Register (MCR)
|
2010-10-09 21:41:31 +02:00
|
|
|
pkt->set(MCR);
|
2005-06-05 07:22:21 +02:00
|
|
|
break;
|
|
|
|
case 0x5: // Line Status Register (LSR)
|
|
|
|
uint8_t lsr;
|
|
|
|
lsr = 0;
|
|
|
|
// check if there are any bytes to be read
|
2008-06-18 05:29:06 +02:00
|
|
|
if (term->dataAvailable())
|
2005-06-05 07:22:21 +02:00
|
|
|
lsr = UART_LSR_DR;
|
|
|
|
lsr |= UART_LSR_TEMT | UART_LSR_THRE;
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->set(lsr);
|
2005-06-05 07:22:21 +02:00
|
|
|
break;
|
|
|
|
case 0x6: // Modem Status Register (MSR)
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->set((uint8_t)0);
|
2005-06-05 07:22:21 +02:00
|
|
|
break;
|
|
|
|
case 0x7: // Scratch Register (SCR)
|
2006-05-19 04:32:21 +02:00
|
|
|
pkt->set((uint8_t)0); // doesn't exist with at 8250.
|
2005-06-05 07:22:21 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
panic("Tried to access a UART port that doesn't exist\n");
|
|
|
|
break;
|
|
|
|
}
|
2006-04-12 23:46:25 +02:00
|
|
|
/* uint32_t d32 = *data;
|
|
|
|
DPRINTF(Uart, "Register read to register %#x returned %#x\n", daddr, d32);
|
|
|
|
*/
|
2007-06-30 19:16:18 +02:00
|
|
|
pkt->makeAtomicResponse();
|
2006-04-06 20:57:51 +02:00
|
|
|
return pioDelay;
|
2005-06-05 07:22:21 +02:00
|
|
|
}
|
|
|
|
|
2006-04-06 20:57:51 +02:00
|
|
|
Tick
|
2006-10-20 09:10:12 +02:00
|
|
|
Uart8250::write(PacketPtr pkt)
|
2005-06-05 07:22:21 +02:00
|
|
|
{
|
|
|
|
|
2006-05-26 20:17:33 +02:00
|
|
|
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
|
|
|
|
assert(pkt->getSize() == 1);
|
2006-04-06 20:57:51 +02:00
|
|
|
|
2006-05-26 20:17:33 +02:00
|
|
|
Addr daddr = pkt->getAddr() - pioAddr;
|
2006-04-06 20:57:51 +02:00
|
|
|
|
2006-05-19 04:32:21 +02:00
|
|
|
DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt->get<uint8_t>());
|
2005-06-05 07:22:21 +02:00
|
|
|
|
|
|
|
switch (daddr) {
|
|
|
|
case 0x0:
|
|
|
|
if (!(LCR & 0x80)) { // write byte
|
2008-06-18 05:29:06 +02:00
|
|
|
term->out(pkt->get<uint8_t>());
|
2005-06-05 07:22:21 +02:00
|
|
|
platform->clearConsoleInt();
|
|
|
|
status &= ~TX_INT;
|
|
|
|
if (UART_IER_THRI & IER)
|
|
|
|
txIntrEvent.scheduleIntr();
|
|
|
|
} else { // dll divisor latch
|
|
|
|
;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x1:
|
|
|
|
if (!(LCR & 0x80)) { // Intr Enable Register(IER)
|
2006-05-19 04:32:21 +02:00
|
|
|
IER = pkt->get<uint8_t>();
|
2005-06-05 07:22:21 +02:00
|
|
|
if (UART_IER_THRI & IER)
|
|
|
|
{
|
|
|
|
DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n");
|
2011-01-08 06:50:29 +01:00
|
|
|
if (curTick() - lastTxInt > 225 * SimClock::Int::ns) {
|
2007-04-30 19:13:03 +02:00
|
|
|
DPRINTF(Uart, "-- Interrupting Immediately... %d,%d\n",
|
2011-01-08 06:50:29 +01:00
|
|
|
curTick(), lastTxInt);
|
2007-04-30 19:13:03 +02:00
|
|
|
txIntrEvent.process();
|
|
|
|
} else {
|
|
|
|
DPRINTF(Uart, "-- Delaying interrupt... %d,%d\n",
|
2011-01-08 06:50:29 +01:00
|
|
|
curTick(), lastTxInt);
|
2007-04-30 19:13:03 +02:00
|
|
|
txIntrEvent.scheduleIntr();
|
|
|
|
}
|
2005-06-05 07:22:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
|
|
|
|
if (txIntrEvent.scheduled())
|
2008-10-09 13:58:24 +02:00
|
|
|
deschedule(txIntrEvent);
|
2005-06-05 07:22:21 +02:00
|
|
|
if (status & TX_INT)
|
|
|
|
platform->clearConsoleInt();
|
|
|
|
status &= ~TX_INT;
|
|
|
|
}
|
|
|
|
|
2008-06-18 05:29:06 +02:00
|
|
|
if ((UART_IER_RDI & IER) && term->dataAvailable()) {
|
2005-06-05 07:22:21 +02:00
|
|
|
DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n");
|
|
|
|
rxIntrEvent.scheduleIntr();
|
|
|
|
} else {
|
|
|
|
DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
|
|
|
|
if (rxIntrEvent.scheduled())
|
2008-10-09 13:58:24 +02:00
|
|
|
deschedule(rxIntrEvent);
|
2005-06-05 07:22:21 +02:00
|
|
|
if (status & RX_INT)
|
|
|
|
platform->clearConsoleInt();
|
|
|
|
status &= ~RX_INT;
|
|
|
|
}
|
|
|
|
} else { // DLM divisor latch MSB
|
|
|
|
;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x2: // FIFO Control Register (FCR)
|
|
|
|
break;
|
|
|
|
case 0x3: // Line Control Register (LCR)
|
2006-05-19 04:32:21 +02:00
|
|
|
LCR = pkt->get<uint8_t>();
|
2005-06-05 07:22:21 +02:00
|
|
|
break;
|
|
|
|
case 0x4: // Modem Control Register (MCR)
|
2006-05-19 04:32:21 +02:00
|
|
|
if (pkt->get<uint8_t>() == (UART_MCR_LOOP | 0x0A))
|
2005-06-05 07:22:21 +02:00
|
|
|
MCR = 0x9A;
|
|
|
|
break;
|
|
|
|
case 0x7: // Scratch Register (SCR)
|
|
|
|
// We are emulating a 8250 so we don't have a scratch reg
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
panic("Tried to access a UART port that doesn't exist\n");
|
|
|
|
break;
|
|
|
|
}
|
2007-06-30 19:16:18 +02:00
|
|
|
pkt->makeAtomicResponse();
|
2006-04-06 20:57:51 +02:00
|
|
|
return pioDelay;
|
2005-06-05 07:22:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Uart8250::dataAvailable()
|
|
|
|
{
|
|
|
|
// if the kernel wants an interrupt when we have data
|
|
|
|
if (IER & UART_IER_RDI)
|
|
|
|
{
|
|
|
|
platform->postConsoleInt();
|
|
|
|
status |= RX_INT;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-01-17 19:55:09 +01:00
|
|
|
AddrRangeList
|
2012-07-09 18:35:34 +02:00
|
|
|
Uart8250::getAddrRanges() const
|
2006-04-06 20:57:51 +02:00
|
|
|
{
|
2012-01-17 19:55:09 +01:00
|
|
|
AddrRangeList ranges;
|
|
|
|
ranges.push_back(RangeSize(pioAddr, pioSize));
|
|
|
|
return ranges;
|
2006-04-06 20:57:51 +02:00
|
|
|
}
|
|
|
|
|
2005-06-05 07:22:21 +02:00
|
|
|
void
|
|
|
|
Uart8250::serialize(ostream &os)
|
|
|
|
{
|
|
|
|
SERIALIZE_SCALAR(status);
|
|
|
|
SERIALIZE_SCALAR(IER);
|
|
|
|
SERIALIZE_SCALAR(DLAB);
|
|
|
|
SERIALIZE_SCALAR(LCR);
|
|
|
|
SERIALIZE_SCALAR(MCR);
|
|
|
|
Tick rxintrwhen;
|
|
|
|
if (rxIntrEvent.scheduled())
|
|
|
|
rxintrwhen = rxIntrEvent.when();
|
|
|
|
else
|
|
|
|
rxintrwhen = 0;
|
|
|
|
Tick txintrwhen;
|
|
|
|
if (txIntrEvent.scheduled())
|
|
|
|
txintrwhen = txIntrEvent.when();
|
|
|
|
else
|
|
|
|
txintrwhen = 0;
|
|
|
|
SERIALIZE_SCALAR(rxintrwhen);
|
|
|
|
SERIALIZE_SCALAR(txintrwhen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Uart8250::unserialize(Checkpoint *cp, const std::string §ion)
|
|
|
|
{
|
|
|
|
UNSERIALIZE_SCALAR(status);
|
|
|
|
UNSERIALIZE_SCALAR(IER);
|
|
|
|
UNSERIALIZE_SCALAR(DLAB);
|
|
|
|
UNSERIALIZE_SCALAR(LCR);
|
|
|
|
UNSERIALIZE_SCALAR(MCR);
|
|
|
|
Tick rxintrwhen;
|
|
|
|
Tick txintrwhen;
|
|
|
|
UNSERIALIZE_SCALAR(rxintrwhen);
|
|
|
|
UNSERIALIZE_SCALAR(txintrwhen);
|
|
|
|
if (rxintrwhen != 0)
|
2008-10-09 13:58:24 +02:00
|
|
|
schedule(rxIntrEvent, rxintrwhen);
|
2005-06-05 07:22:21 +02:00
|
|
|
if (txintrwhen != 0)
|
2008-10-09 13:58:24 +02:00
|
|
|
schedule(txIntrEvent, txintrwhen);
|
2005-06-05 07:22:21 +02:00
|
|
|
}
|
|
|
|
|
2007-07-24 06:51:38 +02:00
|
|
|
Uart8250 *
|
|
|
|
Uart8250Params::create()
|
2005-06-05 07:22:21 +02:00
|
|
|
{
|
2007-07-24 06:51:38 +02:00
|
|
|
return new Uart8250(this);
|
2005-06-05 07:22:21 +02:00
|
|
|
}
|