mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2025-11-26 12:17:43 +00:00
More style changes
This commit is contained in:
@@ -4,10 +4,6 @@
|
|||||||
|
|
||||||
namespace EightBit
|
namespace EightBit
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
public class IntelHexFile(string path)
|
public class IntelHexFile(string path)
|
||||||
{
|
{
|
||||||
private readonly string _path = path;
|
private readonly string _path = path;
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
|
|
||||||
namespace EightBit
|
namespace EightBit
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
public abstract class Memory
|
public abstract class Memory
|
||||||
{
|
{
|
||||||
public abstract int Size
|
public abstract int Size
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
|
|
||||||
namespace EightBit
|
namespace EightBit
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
public class Rom(int size = 0) : Memory
|
public class Rom(int size = 0) : Memory
|
||||||
{
|
{
|
||||||
private byte[] _bytes = new byte[size];
|
private byte[] _bytes = new byte[size];
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
namespace EightBit
|
namespace EightBit
|
||||||
{
|
{
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
public class UnusedMemory(int size, byte unchanging) : Memory
|
public class UnusedMemory(int size, byte unchanging) : Memory
|
||||||
{
|
{
|
||||||
private readonly int _size = size;
|
private readonly int _size = size;
|
||||||
@@ -13,14 +11,14 @@ namespace EightBit
|
|||||||
|
|
||||||
public override int Size => _size;
|
public override int Size => _size;
|
||||||
|
|
||||||
public override int Load(FileStream file, int writeOffset = 0, int readOffset = 0, int limit = -1) => throw new System.NotImplementedException();
|
public override int Load(FileStream file, int writeOffset = 0, int readOffset = 0, int limit = -1) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override int Load(string path, int writeOffset = 0, int readOffset = 0, int limit = -1) => throw new System.NotImplementedException();
|
public override int Load(string path, int writeOffset = 0, int readOffset = 0, int limit = -1) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override int Load(byte[] from, int writeOffset = 0, int readOffset = 0, int limit = -1) => throw new System.NotImplementedException();
|
public override int Load(byte[] from, int writeOffset = 0, int readOffset = 0, int limit = -1) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override byte Peek(ushort address) => _unchanging;
|
public override byte Peek(ushort address) => _unchanging;
|
||||||
|
|
||||||
protected override void Poke(ushort address, byte value) => throw new System.NotImplementedException();
|
protected override void Poke(ushort address, byte value) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace M6502.Symbols
|
namespace M6502.Symbols
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ namespace EightBit
|
|||||||
|
|
||||||
public class Disassembler(Bus bus)
|
public class Disassembler(Bus bus)
|
||||||
{
|
{
|
||||||
private bool prefixCB = false;
|
private bool _prefixCB = false;
|
||||||
private bool prefixDD = false;
|
private bool _prefixDD = false;
|
||||||
private bool prefixED = false;
|
private bool _prefixED = false;
|
||||||
private bool prefixFD = false;
|
private bool _prefixFD = false;
|
||||||
|
|
||||||
public Bus Bus { get; } = bus;
|
public Bus Bus { get; } = bus;
|
||||||
|
|
||||||
@@ -71,8 +71,8 @@ namespace EightBit
|
|||||||
public string Disassemble(Z80 cpu)
|
public string Disassemble(Z80 cpu)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(cpu);
|
ArgumentNullException.ThrowIfNull(cpu);
|
||||||
this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
|
_prefixCB = _prefixDD = _prefixED = _prefixFD = false;
|
||||||
return this.Disassemble(cpu, cpu.PC.Word);
|
return Disassemble(cpu, cpu.PC.Word);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string CC(int flag) => flag switch
|
private static string CC(int flag) => flag switch
|
||||||
@@ -85,7 +85,7 @@ namespace EightBit
|
|||||||
5 => "PE",
|
5 => "PE",
|
||||||
6 => "P",
|
6 => "P",
|
||||||
7 => "M",
|
7 => "M",
|
||||||
_ => throw new System.ArgumentOutOfRangeException(nameof(flag)),
|
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static string ALU(int which) => which switch
|
private static string ALU(int which) => which switch
|
||||||
@@ -98,12 +98,12 @@ namespace EightBit
|
|||||||
5 => "XOR",
|
5 => "XOR",
|
||||||
6 => "OR",
|
6 => "OR",
|
||||||
7 => "CP",
|
7 => "CP",
|
||||||
_ => throw new System.ArgumentOutOfRangeException(nameof(which)),
|
_ => throw new ArgumentOutOfRangeException(nameof(which)),
|
||||||
};
|
};
|
||||||
|
|
||||||
private string Disassemble(Z80 cpu, ushort pc)
|
private string Disassemble(Z80 cpu, ushort pc)
|
||||||
{
|
{
|
||||||
var opCode = this.Bus.Peek(pc);
|
var opCode = Bus.Peek(pc);
|
||||||
|
|
||||||
var decoded = cpu.GetDecodedOpCode(opCode);
|
var decoded = cpu.GetDecodedOpCode(opCode);
|
||||||
|
|
||||||
@@ -114,37 +114,37 @@ namespace EightBit
|
|||||||
var p = decoded.P;
|
var p = decoded.P;
|
||||||
var q = decoded.Q;
|
var q = decoded.Q;
|
||||||
|
|
||||||
var immediate = this.Bus.Peek((ushort)(pc + 1));
|
var immediate = Bus.Peek((ushort)(pc + 1));
|
||||||
var absolute = cpu.PeekWord((ushort)(pc + 1)).Word;
|
var absolute = cpu.PeekWord((ushort)(pc + 1)).Word;
|
||||||
var displacement = (sbyte)immediate;
|
var displacement = (sbyte)immediate;
|
||||||
var relative = pc + displacement + 2;
|
var relative = pc + displacement + 2;
|
||||||
var indexedImmediate = this.Bus.Peek((ushort)(pc + 1));
|
var indexedImmediate = Bus.Peek((ushort)(pc + 1));
|
||||||
|
|
||||||
var dumpCount = 0;
|
var dumpCount = 0;
|
||||||
|
|
||||||
var output = $"{opCode:x2}";
|
var output = $"{opCode:x2}";
|
||||||
|
|
||||||
var specification = string.Empty;
|
var specification = string.Empty;
|
||||||
if (this.prefixCB)
|
if (_prefixCB)
|
||||||
{
|
{
|
||||||
output += this.DisassembleCB(ref specification, x, y, z);
|
output += DisassembleCB(ref specification, x, y, z);
|
||||||
}
|
}
|
||||||
else if (this.prefixED)
|
else if (_prefixED)
|
||||||
{
|
{
|
||||||
output += this.DisassembleED(ref specification, ref dumpCount, x, y, z, p, q);
|
output += DisassembleED(ref specification, ref dumpCount, x, y, z, p, q);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
output += this.DisassembleOther(cpu, pc, ref specification, ref dumpCount, x, y, z, p, q);
|
output += DisassembleOther(cpu, pc, ref specification, ref dumpCount, x, y, z, p, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < dumpCount; ++i)
|
for (var i = 0; i < dumpCount; ++i)
|
||||||
{
|
{
|
||||||
output += $"{this.Bus.Peek((ushort)(pc + i + 1)):x2}";
|
output += $"{Bus.Peek((ushort)(pc + i + 1)):x2}";
|
||||||
}
|
}
|
||||||
|
|
||||||
var outputFormatSpecification = !this.prefixDD;
|
var outputFormatSpecification = !_prefixDD;
|
||||||
if (this.prefixDD)
|
if (_prefixDD)
|
||||||
{
|
{
|
||||||
if (opCode != 0xdd)
|
if (opCode != 0xdd)
|
||||||
{
|
{
|
||||||
@@ -170,40 +170,40 @@ namespace EightBit
|
|||||||
switch (y)
|
switch (y)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
specification = $"RLC {this.R(z)}";
|
specification = $"RLC {R(z)}";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
specification = $"RRC {this.R(z)}";
|
specification = $"RRC {R(z)}";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
specification = $"RL {this.R(z)}";
|
specification = $"RL {R(z)}";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
specification = $"RR {this.R(z)}";
|
specification = $"RR {R(z)}";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
specification = $"SLA {this.R(z)}";
|
specification = $"SLA {R(z)}";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
specification = $"SRA {this.R(z)}";
|
specification = $"SRA {R(z)}";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
specification = $"SWAP {this.R(z)}";
|
specification = $"SWAP {R(z)}";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
specification = $"SRL {this.R(z)}";
|
specification = $"SRL {R(z)}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 1: // BIT y, r[z]
|
case 1: // BIT y, r[z]
|
||||||
specification = $"BIT {y},{this.R(z)}";
|
specification = $"BIT {y},{R(z)}";
|
||||||
break;
|
break;
|
||||||
case 2: // RES y, r[z]
|
case 2: // RES y, r[z]
|
||||||
specification = $"RES {y},{this.R(z)}";
|
specification = $"RES {y},{R(z)}";
|
||||||
break;
|
break;
|
||||||
case 3: // SET y, r[z]
|
case 3: // SET y, r[z]
|
||||||
specification = $"SET {y},{this.R(z)}";
|
specification = $"SET {y},{R(z)}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,21 +223,21 @@ namespace EightBit
|
|||||||
switch (z)
|
switch (z)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
specification = $"IN {this.R(y)}, (C)";
|
specification = $"IN {R(y)}, (C)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
specification = $"OUT (C), {this.R(y)}";
|
specification = $"OUT (C), {R(y)}";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
switch (q)
|
switch (q)
|
||||||
{
|
{
|
||||||
case 0: // SBC HL,rp
|
case 0: // SBC HL,rp
|
||||||
specification = $"SBC HL,{this.RP(p)}";
|
specification = $"SBC HL,{RP(p)}";
|
||||||
break;
|
break;
|
||||||
case 1: // ADC HL,rp
|
case 1: // ADC HL,rp
|
||||||
specification = $"ADC HL,{this.RP(p)}";
|
specification = $"ADC HL,{RP(p)}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,10 +246,10 @@ namespace EightBit
|
|||||||
switch (q)
|
switch (q)
|
||||||
{
|
{
|
||||||
case 0: // LD (nn),rp
|
case 0: // LD (nn),rp
|
||||||
specification = "LD ({1:X4}H)," + this.RP(p);
|
specification = "LD ({1:X4}H)," + RP(p);
|
||||||
break;
|
break;
|
||||||
case 1: // LD rp,(nn)
|
case 1: // LD rp,(nn)
|
||||||
specification = "LD " + this.RP(p) + ",(%2$04XH)";
|
specification = "LD " + RP(p) + ",(%2$04XH)";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,11 +435,11 @@ namespace EightBit
|
|||||||
switch (q)
|
switch (q)
|
||||||
{
|
{
|
||||||
case 0: // LD rp,nn
|
case 0: // LD rp,nn
|
||||||
specification = "LD " + this.RP(p) + ",{1:X4}H";
|
specification = "LD " + RP(p) + ",{1:X4}H";
|
||||||
dumpCount += 2;
|
dumpCount += 2;
|
||||||
break;
|
break;
|
||||||
case 1: // ADD HL,rp
|
case 1: // ADD HL,rp
|
||||||
specification = $"ADD HL,{this.RP(p)}";
|
specification = $"ADD HL,{RP(p)}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,23 +494,23 @@ namespace EightBit
|
|||||||
switch (q)
|
switch (q)
|
||||||
{
|
{
|
||||||
case 0: // INC rp
|
case 0: // INC rp
|
||||||
specification = $"INC {this.RP(p)}";
|
specification = $"INC {RP(p)}";
|
||||||
break;
|
break;
|
||||||
case 1: // DEC rp
|
case 1: // DEC rp
|
||||||
specification = $"DEC {this.RP(p)}";
|
specification = $"DEC {RP(p)}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 4: // 8-bit INC
|
case 4: // 8-bit INC
|
||||||
specification = $"INC {this.R(y)}";
|
specification = $"INC {R(y)}";
|
||||||
break;
|
break;
|
||||||
case 5: // 8-bit DEC
|
case 5: // 8-bit DEC
|
||||||
specification = $"DEC {this.R(y)}";
|
specification = $"DEC {R(y)}";
|
||||||
break;
|
break;
|
||||||
case 6: // 8-bit load immediate
|
case 6: // 8-bit load immediate
|
||||||
specification = $"LD {this.R(y)}";
|
specification = $"LD {R(y)}";
|
||||||
if (y == 6 && (this.prefixDD || this.prefixFD))
|
if (y == 6 && (_prefixDD || _prefixFD))
|
||||||
{
|
{
|
||||||
specification += ",{4:X2}H";
|
specification += ",{4:X2}H";
|
||||||
dumpCount++;
|
dumpCount++;
|
||||||
@@ -556,10 +556,10 @@ namespace EightBit
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 1: // 8-bit loading
|
case 1: // 8-bit loading
|
||||||
specification = z == 6 && y == 6 ? "HALT" : $"LD {this.R(y)},{this.R(z)}";
|
specification = z == 6 && y == 6 ? "HALT" : $"LD {R(y)},{R(z)}";
|
||||||
break;
|
break;
|
||||||
case 2: // Operate on accumulator and register/memory location
|
case 2: // Operate on accumulator and register/memory location
|
||||||
specification = $"{ALU(y)} A,{this.R(z)}";
|
specification = $"{ALU(y)} A,{R(z)}";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
switch (z)
|
switch (z)
|
||||||
@@ -571,7 +571,7 @@ namespace EightBit
|
|||||||
switch (q)
|
switch (q)
|
||||||
{
|
{
|
||||||
case 0: // POP rp2[p]
|
case 0: // POP rp2[p]
|
||||||
specification = $"POP {this.RP2(p)}";
|
specification = $"POP {RP2(p)}";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
switch (p)
|
switch (p)
|
||||||
@@ -606,8 +606,8 @@ namespace EightBit
|
|||||||
dumpCount += 2;
|
dumpCount += 2;
|
||||||
break;
|
break;
|
||||||
case 1: // CB prefix
|
case 1: // CB prefix
|
||||||
this.prefixCB = true;
|
_prefixCB = true;
|
||||||
output += this.Disassemble(cpu, ++pc);
|
output += Disassemble(cpu, ++pc);
|
||||||
break;
|
break;
|
||||||
case 2: // OUT (n),A
|
case 2: // OUT (n),A
|
||||||
specification = "OUT ({0:X2}H),A";
|
specification = "OUT ({0:X2}H),A";
|
||||||
@@ -640,7 +640,7 @@ namespace EightBit
|
|||||||
switch (q)
|
switch (q)
|
||||||
{
|
{
|
||||||
case 0: // PUSH rp2[p]
|
case 0: // PUSH rp2[p]
|
||||||
specification = $"PUSH {this.RP2(p)}";
|
specification = $"PUSH {RP2(p)}";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
switch (p)
|
switch (p)
|
||||||
@@ -650,16 +650,16 @@ namespace EightBit
|
|||||||
dumpCount += 2;
|
dumpCount += 2;
|
||||||
break;
|
break;
|
||||||
case 1: // DD prefix
|
case 1: // DD prefix
|
||||||
this.prefixDD = true;
|
_prefixDD = true;
|
||||||
output += this.Disassemble(cpu, ++pc);
|
output += Disassemble(cpu, ++pc);
|
||||||
break;
|
break;
|
||||||
case 2: // ED prefix
|
case 2: // ED prefix
|
||||||
this.prefixED = true;
|
_prefixED = true;
|
||||||
output += this.Disassemble(cpu, ++pc);
|
output += Disassemble(cpu, ++pc);
|
||||||
break;
|
break;
|
||||||
case 3: // FD prefix
|
case 3: // FD prefix
|
||||||
this.prefixFD = true;
|
_prefixFD = true;
|
||||||
output += this.Disassemble(cpu, ++pc);
|
output += Disassemble(cpu, ++pc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,12 +691,12 @@ namespace EightBit
|
|||||||
case 1:
|
case 1:
|
||||||
return "DE";
|
return "DE";
|
||||||
case 2:
|
case 2:
|
||||||
if (this.prefixDD)
|
if (_prefixDD)
|
||||||
{
|
{
|
||||||
return "IX";
|
return "IX";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.prefixFD)
|
if (_prefixFD)
|
||||||
{
|
{
|
||||||
return "IY";
|
return "IY";
|
||||||
}
|
}
|
||||||
@@ -706,7 +706,7 @@ namespace EightBit
|
|||||||
return "SP";
|
return "SP";
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new System.ArgumentOutOfRangeException(nameof(rp));
|
throw new ArgumentOutOfRangeException(nameof(rp));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string RP2(int rp)
|
private string RP2(int rp)
|
||||||
@@ -718,12 +718,12 @@ namespace EightBit
|
|||||||
case 1:
|
case 1:
|
||||||
return "DE";
|
return "DE";
|
||||||
case 2:
|
case 2:
|
||||||
if (this.prefixDD)
|
if (_prefixDD)
|
||||||
{
|
{
|
||||||
return "IX";
|
return "IX";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.prefixFD)
|
if (_prefixFD)
|
||||||
{
|
{
|
||||||
return "IY";
|
return "IY";
|
||||||
}
|
}
|
||||||
@@ -733,7 +733,7 @@ namespace EightBit
|
|||||||
return "AF";
|
return "AF";
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new System.ArgumentOutOfRangeException(nameof(rp));
|
throw new ArgumentOutOfRangeException(nameof(rp));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string R(int r)
|
private string R(int r)
|
||||||
@@ -749,38 +749,38 @@ namespace EightBit
|
|||||||
case 3:
|
case 3:
|
||||||
return "E";
|
return "E";
|
||||||
case 4:
|
case 4:
|
||||||
if (this.prefixDD)
|
if (_prefixDD)
|
||||||
{
|
{
|
||||||
return "IXH";
|
return "IXH";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.prefixFD)
|
if (_prefixFD)
|
||||||
{
|
{
|
||||||
return "IYH";
|
return "IYH";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "H";
|
return "H";
|
||||||
case 5:
|
case 5:
|
||||||
if (this.prefixDD)
|
if (_prefixDD)
|
||||||
{
|
{
|
||||||
return "IXL";
|
return "IXL";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.prefixFD)
|
if (_prefixFD)
|
||||||
{
|
{
|
||||||
return "IYL";
|
return "IYL";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "L";
|
return "L";
|
||||||
case 6:
|
case 6:
|
||||||
if (this.prefixDD || this.prefixFD)
|
if (_prefixDD || _prefixFD)
|
||||||
{
|
{
|
||||||
if (this.prefixDD)
|
if (_prefixDD)
|
||||||
{
|
{
|
||||||
return "IX+{4}";
|
return "IX+{4}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.prefixFD)
|
if (_prefixFD)
|
||||||
{
|
{
|
||||||
return "IY+{4}";
|
return "IY+{4}";
|
||||||
}
|
}
|
||||||
@@ -795,7 +795,7 @@ namespace EightBit
|
|||||||
return "A";
|
return "A";
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new System.ArgumentOutOfRangeException(nameof(r));
|
throw new ArgumentOutOfRangeException(nameof(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
namespace EightBit
|
namespace EightBit
|
||||||
{
|
{
|
||||||
public struct RefreshRegister(byte value) : System.IEquatable<RefreshRegister>
|
public struct RefreshRegister(byte value) : IEquatable<RefreshRegister>
|
||||||
{
|
{
|
||||||
private readonly byte high = (byte)(value & (byte)Bits.Bit7);
|
private readonly byte high = (byte)(value & (byte)Bits.Bit7);
|
||||||
private byte variable = (byte)(value & (byte)Mask.Seven);
|
private byte variable = (byte)(value & (byte)Mask.Seven);
|
||||||
|
|||||||
1292
Z80/Z80.cs
1292
Z80/Z80.cs
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user