dev: Convert the x86 i8237 DMA controller to use RegBank.
This gets rid of the requirement to only modify one byte register at a time, and builds some structure around individual DMA channels. The one small feature of the i8237 that was implemented is still implemented, but now with a method of the i8237. Change-Id: Ibc2b2d75f2a3b860da3f28ae649c6f1a099bdf7d Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/36815 Reviewed-by: Matthew Poremba <matthew.poremba@amd.com> Maintainer: Gabe Black <gabe.black@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -28,110 +28,137 @@
|
||||
|
||||
#include "dev/x86/i8237.hh"
|
||||
|
||||
#include "base/cprintf.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
|
||||
Tick
|
||||
X86ISA::I8237::read(PacketPtr pkt)
|
||||
namespace X86ISA
|
||||
{
|
||||
assert(pkt->getSize() == 1);
|
||||
Addr offset = pkt->getAddr() - pioAddr;
|
||||
switch (offset) {
|
||||
case 0x0:
|
||||
panic("Read from i8237 channel 0 current address unimplemented.\n");
|
||||
case 0x1:
|
||||
panic("Read from i8237 channel 0 remaining "
|
||||
"word count unimplemented.\n");
|
||||
case 0x2:
|
||||
panic("Read from i8237 channel 1 current address unimplemented.\n");
|
||||
case 0x3:
|
||||
panic("Read from i8237 channel 1 remaining "
|
||||
"word count unimplemented.\n");
|
||||
case 0x4:
|
||||
panic("Read from i8237 channel 2 current address unimplemented.\n");
|
||||
case 0x5:
|
||||
panic("Read from i8237 channel 2 remaining "
|
||||
"word count unimplemented.\n");
|
||||
case 0x6:
|
||||
panic("Read from i8237 channel 3 current address unimplemented.\n");
|
||||
case 0x7:
|
||||
panic("Read from i8237 channel 3 remaining "
|
||||
"word count unimplemented.\n");
|
||||
case 0x8:
|
||||
panic("Read from i8237 status register unimplemented.\n");
|
||||
default:
|
||||
panic("Read from undefined i8237 register %d.\n", offset);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
I8237::Register::ReadFunc
|
||||
readUnimpl(const std::string &label)
|
||||
{
|
||||
return [label](I8237::Register ®) -> uint8_t {
|
||||
panic("Read from i8237 %s unimplemented.", label);
|
||||
};
|
||||
}
|
||||
|
||||
I8237::Register::WriteFunc
|
||||
writeUnimpl(const std::string &label)
|
||||
{
|
||||
return [label](I8237::Register ®, const uint8_t &value) {
|
||||
panic("Write to i8237 %s unimplemented.", label);
|
||||
};
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
I8237::Channel::ChannelAddrReg::ChannelAddrReg(Channel &channel) :
|
||||
Register(csprintf("channel %d current address", channel.number))
|
||||
{
|
||||
reader(readUnimpl(name()));
|
||||
writer(writeUnimpl(name()));
|
||||
}
|
||||
|
||||
I8237::Channel::ChannelRemainingReg::ChannelRemainingReg(Channel &channel) :
|
||||
Register(csprintf("channel %d remaining word count", channel.number))
|
||||
{
|
||||
reader(readUnimpl(name()));
|
||||
writer(writeUnimpl(name()));
|
||||
}
|
||||
|
||||
I8237::WriteOnlyReg::WriteOnlyReg(const std::string &new_name, Addr offset) :
|
||||
Register(new_name)
|
||||
{
|
||||
reader([offset](I8237::Register ®) -> uint8_t {
|
||||
panic("Illegal read from i8237 register %d.", offset);
|
||||
});
|
||||
}
|
||||
|
||||
I8237::I8237(const Params &p) : BasicPioDevice(p, 16), latency(p.pio_latency),
|
||||
regs("registers", pioAddr), channels{{{0}, {1}, {2}, {3}}},
|
||||
statusCommandReg("status/command"),
|
||||
requestReg("request", 0x9),
|
||||
setMaskBitReg("set mask bit", 0xa),
|
||||
modeReg("mode", 0xb),
|
||||
clearFlipFlopReg("clear flip-flop", 0xc),
|
||||
temporaryMasterClearReg("temporary/maskter clear"),
|
||||
clearMaskReg("clear mask", 0xe),
|
||||
writeMaskReg("write mask", 0xf)
|
||||
{
|
||||
// Add the channel address and remaining registers.
|
||||
for (auto &channel: channels)
|
||||
regs.addRegisters({ channel.addrReg, channel.remainingReg });
|
||||
|
||||
// Add the other registers individually.
|
||||
regs.addRegisters({
|
||||
statusCommandReg.
|
||||
reader(readUnimpl("status register")).
|
||||
writer(writeUnimpl("command register")),
|
||||
|
||||
requestReg.
|
||||
writer(writeUnimpl("request register")),
|
||||
|
||||
setMaskBitReg.
|
||||
writer(this, &I8237::setMaskBit),
|
||||
|
||||
modeReg.
|
||||
writer(writeUnimpl("mode register")),
|
||||
|
||||
clearFlipFlopReg.
|
||||
writer(writeUnimpl("clear LSB/MSB flip-flop register")),
|
||||
|
||||
temporaryMasterClearReg.
|
||||
reader(readUnimpl("temporary register")).
|
||||
writer(writeUnimpl("master clear register")),
|
||||
|
||||
clearMaskReg.
|
||||
writer(writeUnimpl("clear mask register")),
|
||||
|
||||
writeMaskReg.
|
||||
writer(writeUnimpl("write all mask register bits"))
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
I8237::setMaskBit(Register ®, const uint8_t &command)
|
||||
{
|
||||
uint8_t select = bits(command, 1, 0);
|
||||
uint8_t bitVal = bits(command, 2);
|
||||
if (!bitVal)
|
||||
panic("Turning on i8237 channels unimplemented.");
|
||||
replaceBits(maskReg, select, bitVal);
|
||||
}
|
||||
|
||||
Tick
|
||||
I8237::read(PacketPtr pkt)
|
||||
{
|
||||
regs.read(pkt->getAddr(), pkt->getPtr<void>(), pkt->getSize());
|
||||
pkt->makeAtomicResponse();
|
||||
return latency;
|
||||
}
|
||||
|
||||
Tick
|
||||
X86ISA::I8237::write(PacketPtr pkt)
|
||||
I8237::write(PacketPtr pkt)
|
||||
{
|
||||
assert(pkt->getSize() == 1);
|
||||
Addr offset = pkt->getAddr() - pioAddr;
|
||||
switch (offset) {
|
||||
case 0x0:
|
||||
panic("Write to i8237 channel 0 starting address unimplemented.\n");
|
||||
case 0x1:
|
||||
panic("Write to i8237 channel 0 starting "
|
||||
"word count unimplemented.\n");
|
||||
case 0x2:
|
||||
panic("Write to i8237 channel 1 starting address unimplemented.\n");
|
||||
case 0x3:
|
||||
panic("Write to i8237 channel 1 starting "
|
||||
"word count unimplemented.\n");
|
||||
case 0x4:
|
||||
panic("Write to i8237 channel 2 starting address unimplemented.\n");
|
||||
case 0x5:
|
||||
panic("Write to i8237 channel 2 starting "
|
||||
"word count unimplemented.\n");
|
||||
case 0x6:
|
||||
panic("Write to i8237 channel 3 starting address unimplemented.\n");
|
||||
case 0x7:
|
||||
panic("Write to i8237 channel 3 starting "
|
||||
"word count unimplemented.\n");
|
||||
case 0x8:
|
||||
panic("Write to i8237 command register unimplemented.\n");
|
||||
case 0x9:
|
||||
panic("Write to i8237 request register unimplemented.\n");
|
||||
case 0xa:
|
||||
{
|
||||
uint8_t command = pkt->getLE<uint8_t>();
|
||||
uint8_t select = bits(command, 1, 0);
|
||||
uint8_t bitVal = bits(command, 2);
|
||||
if (!bitVal)
|
||||
panic("Turning on i8237 channels unimplemented.\n");
|
||||
replaceBits(maskReg, select, bitVal);
|
||||
}
|
||||
break;
|
||||
case 0xb:
|
||||
panic("Write to i8237 mode register unimplemented.\n");
|
||||
case 0xc:
|
||||
panic("Write to i8237 clear LSB/MSB flip-flop "
|
||||
"register unimplemented.\n");
|
||||
case 0xd:
|
||||
panic("Write to i8237 master clear/reset register unimplemented.\n");
|
||||
case 0xe:
|
||||
panic("Write to i8237 clear mask register unimplemented.\n");
|
||||
case 0xf:
|
||||
panic("Write to i8237 write all mask register bits unimplemented.\n");
|
||||
default:
|
||||
panic("Write to undefined i8237 register.\n");
|
||||
}
|
||||
regs.write(pkt->getAddr(), pkt->getPtr<void>(), pkt->getSize());
|
||||
pkt->makeAtomicResponse();
|
||||
return latency;
|
||||
}
|
||||
|
||||
void
|
||||
X86ISA::I8237::serialize(CheckpointOut &cp) const
|
||||
I8237::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
SERIALIZE_SCALAR(maskReg);
|
||||
}
|
||||
|
||||
void
|
||||
X86ISA::I8237::unserialize(CheckpointIn &cp)
|
||||
I8237::unserialize(CheckpointIn &cp)
|
||||
{
|
||||
UNSERIALIZE_SCALAR(maskReg);
|
||||
}
|
||||
|
||||
} // namespace X86ISA
|
||||
|
||||
@@ -29,7 +29,10 @@
|
||||
#ifndef __DEV_X86_I8237_HH__
|
||||
#define __DEV_X86_I8237_HH__
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "dev/io_device.hh"
|
||||
#include "dev/reg_bank.hh"
|
||||
#include "params/I8237.hh"
|
||||
|
||||
namespace X86ISA
|
||||
@@ -37,10 +40,57 @@ namespace X86ISA
|
||||
|
||||
class I8237 : public BasicPioDevice
|
||||
{
|
||||
public:
|
||||
using Register = RegisterBankLE::Register8;
|
||||
|
||||
protected:
|
||||
Tick latency;
|
||||
uint8_t maskReg = 0;
|
||||
|
||||
RegisterBankLE regs;
|
||||
|
||||
struct Channel
|
||||
{
|
||||
class ChannelAddrReg : public Register
|
||||
{
|
||||
public:
|
||||
ChannelAddrReg(Channel &);
|
||||
};
|
||||
|
||||
class ChannelRemainingReg : public Register
|
||||
{
|
||||
public:
|
||||
ChannelRemainingReg(Channel &);
|
||||
};
|
||||
|
||||
int number;
|
||||
|
||||
ChannelAddrReg addrReg;
|
||||
ChannelRemainingReg remainingReg;
|
||||
|
||||
Channel(int _num) : number(_num), addrReg(*this), remainingReg(*this)
|
||||
{}
|
||||
};
|
||||
|
||||
class WriteOnlyReg : public Register
|
||||
{
|
||||
public:
|
||||
WriteOnlyReg(const std::string &new_name, Addr offset);
|
||||
};
|
||||
|
||||
std::array<Channel, 4> channels;
|
||||
|
||||
Register statusCommandReg;
|
||||
WriteOnlyReg requestReg;
|
||||
WriteOnlyReg setMaskBitReg;
|
||||
WriteOnlyReg modeReg;
|
||||
WriteOnlyReg clearFlipFlopReg;
|
||||
Register temporaryMasterClearReg;
|
||||
WriteOnlyReg clearMaskReg;
|
||||
WriteOnlyReg writeMaskReg;
|
||||
|
||||
void setMaskBit(Register ®, const uint8_t &command);
|
||||
|
||||
public:
|
||||
typedef I8237Params Params;
|
||||
|
||||
@@ -50,7 +100,7 @@ class I8237 : public BasicPioDevice
|
||||
return dynamic_cast<const Params &>(_params);
|
||||
}
|
||||
|
||||
I8237(const Params &p) : BasicPioDevice(p, 16), latency(p.pio_latency) {}
|
||||
I8237(const Params &p);
|
||||
|
||||
Tick read(PacketPtr pkt) override;
|
||||
Tick write(PacketPtr pkt) override;
|
||||
|
||||
Reference in New Issue
Block a user