dev: Convert the x86 i8237 DMA controller to use RegBank.
authorGabe Black <gabe.black@gmail.com>
Tue, 27 Oct 2020 00:59:38 +0000 (17:59 -0700)
committerGabe Black <gabe.black@gmail.com>
Tue, 3 Nov 2020 02:04:49 +0000 (02:04 +0000)
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>
src/dev/x86/i8237.cc
src/dev/x86/i8237.hh

index 05d08c862fc1e1f7c0f4969ea1538e3f7bb97093..a7f641fe0668cbc68269e8b1020cfeb210222862 100644 (file)
 
 #include "dev/x86/i8237.hh"
 
+#include "base/cprintf.hh"
 #include "mem/packet.hh"
 #include "mem/packet_access.hh"
 
+namespace X86ISA
+{
+
+namespace
+{
+
+I8237::Register::ReadFunc
+readUnimpl(const std::string &label)
+{
+    return [label](I8237::Register &reg) -> uint8_t {
+        panic("Read from i8237 %s unimplemented.", label);
+    };
+}
+
+I8237::Register::WriteFunc
+writeUnimpl(const std::string &label)
+{
+    return [label](I8237::Register &reg, 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 &reg) -> 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 &reg, 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
-X86ISA::I8237::read(PacketPtr pkt)
+I8237::read(PacketPtr pkt)
 {
-    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);
-    }
+    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
index d5044d64837621f690f875e58ef3efd4772909b1..61544855b3896f4665971f87ae71a72c3abc9290 100644 (file)
 #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 &reg, 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;