auto V30MZ::modRM() -> void {
  auto data = fetch();
  modrm.mem = data.bits(0,2);
  modrm.reg = data.bits(3,5);
  modrm.mod = data.bits(6,7);

  if(modrm.mod == 0 && modrm.mem == 6) {
    modrm.segment = segment(r.ds);
    modrm.address = fetch(Word);
  } else {
    switch(modrm.mem) {
    case 0: modrm.segment = segment(r.ds); modrm.address = r.bx + r.si; break;
    case 1: modrm.segment = segment(r.ds); modrm.address = r.bx + r.di; break;
    case 2: modrm.segment = segment(r.ss); modrm.address = r.bp + r.si; break;
    case 3: modrm.segment = segment(r.ss); modrm.address = r.bp + r.di; break;
    case 4: modrm.segment = segment(r.ds); modrm.address = r.si; break;
    case 5: modrm.segment = segment(r.ds); modrm.address = r.di; break;
    case 6: modrm.segment = segment(r.ss); modrm.address = r.bp; break;
    case 7: modrm.segment = segment(r.ds); modrm.address = r.bx; break;
    }
    if(modrm.mod == 1) modrm.address += (int8)fetch(Byte);
    if(modrm.mod == 2) modrm.address += (int16)fetch(Word);
  }
}

//

auto V30MZ::getMem(Size size, uint offset) -> uint16 {
  if(modrm.mod != 3) return read(size, modrm.segment, modrm.address + offset);
  if(size == Byte) return *r.b[modrm.mem];
  if(size == Word) return *r.w[modrm.mem];
  unreachable;
}

auto V30MZ::setMem(Size size, uint16 data) -> void {
  if(modrm.mod != 3) return write(size, modrm.segment, modrm.address, data);
  if(size == Byte) *r.b[modrm.mem] = data;
  if(size == Word) *r.w[modrm.mem] = data;
}

//

auto V30MZ::getReg(Size size) -> uint16 {
  if(size == Byte) return *r.b[modrm.reg];
  if(size == Word) return *r.w[modrm.reg];
  unreachable;
}

auto V30MZ::setReg(Size size, uint16 data) -> void {
  if(size == Byte) *r.b[modrm.reg] = data;
  if(size == Word) *r.w[modrm.reg] = data;
}

//

auto V30MZ::getSeg() -> uint16 {
  return *r.s[modrm.reg];
}

auto V30MZ::setSeg(uint16 data) -> void {
  *r.s[modrm.reg] = data;
}
