Skip to content

Commit

Permalink
Add int, iret and cpuid to Assembler
Browse files Browse the repository at this point in the history
  • Loading branch information
Argmaster committed Nov 16, 2024
1 parent 88a28c5 commit 8e71f17
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 5 deletions.
36 changes: 36 additions & 0 deletions src/Bytom.Assembler.Tests/BackendTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1503,5 +1503,41 @@ jmp 16
"
));
}

[Test]
public void TestInt()
{
var frontend = new Frontend();
var instructions = frontend.parse(@"int RD0");

Backend backend = new Backend();
var code = backend.compile(instructions);

Assert.That(code.ToAssembly(), Is.EqualTo("int RD0\n"));
}

[Test]
public void TestIRet()
{
var frontend = new Frontend();
var instructions = frontend.parse(@"iret");

Backend backend = new Backend();
var code = backend.compile(instructions);

Assert.That(code.ToAssembly(), Is.EqualTo("iret\n"));
}

[Test]
public void TestCpuId()
{
var frontend = new Frontend();
var instructions = frontend.parse(@"cpuid RD0");

Backend backend = new Backend();
var code = backend.compile(instructions);

Assert.That(code.ToAssembly(), Is.EqualTo("cpuid RD0\n"));
}
}
}
27 changes: 27 additions & 0 deletions src/Bytom.Assembler.Tests/FrontendTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -586,5 +586,32 @@ public void TestCmp()
Assert.That(instructions.Count, Is.EqualTo(1));
Assert.IsInstanceOf<Cmp>(instructions[0]);
}

[Test]
public void TestInt()
{
Frontend frontend = new Frontend();
var instructions = frontend.parse("INT RD0").nodes;
Assert.That(instructions.Count, Is.EqualTo(1));
Assert.IsInstanceOf<Int>(instructions[0]);
}

[Test]
public void TestIRet()
{
Frontend frontend = new Frontend();
var instructions = frontend.parse("IRET").nodes;
Assert.That(instructions.Count, Is.EqualTo(1));
Assert.IsInstanceOf<IRet>(instructions[0]);
}

[Test]
public void TestCpuId()
{
Frontend frontend = new Frontend();
var instructions = frontend.parse("CPUID RD0").nodes;
Assert.That(instructions.Count, Is.EqualTo(1));
Assert.IsInstanceOf<CpuId>(instructions[0]);
}
}
}
20 changes: 20 additions & 0 deletions src/Bytom.Assembler/Frontend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,13 +261,33 @@ private Instruction dispatchInstruction(string instruction_name, string[] parame
case "ret":
expectOperandsCount(parameters, 0);
return new Ret();

case "cmp":
{
expectOperandsCount(parameters, 2);
OpRegister left = parseRegister(parameters[0]);
OpRegister right = parseRegister(parameters[1]);
return new Cmp(left, right);
}

case "int":
{
expectOperandsCount(parameters, 1);
OpRegister interrupt = parseRegister(parameters[0]);
return new Int(interrupt);
}

case "iret":
expectOperandsCount(parameters, 0);
return new IRet();

case "cpuid":
{
expectOperandsCount(parameters, 1);
OpRegister destination = parseRegister(parameters[0]);
return new CpuId(destination);
}

default:
throw new Exception($"Invalid instruction {instruction_name} in line {lineIndex}: '{currentLine}'");
}
Expand Down
74 changes: 74 additions & 0 deletions src/Bytom.Assembler/Nodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1756,4 +1756,78 @@ public override string ToAssembly()
return $"cmp {left.ToAssembly()}, {right.ToAssembly()}";
}
}

public class Int : Instruction
{
public OpRegister interrupt { get; set; }

public Int(OpRegister interrupt)
{
this.interrupt = interrupt;
}

public override OpCode GetOpCode()
{
return OpCode.Int;
}

public override byte[] ToMachineCode()
{
return new MachineInstructionBuilder(GetOpCode())
.SetFirstRegisterID(interrupt.name)
.GetInstruction();
}

public override string ToAssembly()
{
return $"int {interrupt.ToAssembly()}";
}
}

public class IRet : Instruction
{
public IRet() { }

public override OpCode GetOpCode()
{
return OpCode.IRet;
}

public override byte[] ToMachineCode()
{
return new MachineInstructionBuilder(GetOpCode())
.GetInstruction();
}

public override string ToAssembly()
{
return "iret";
}
}

public class CpuId : Instruction
{
public OpRegister code { get; set; }

public CpuId(OpRegister code)
{
this.code = code;
}

public override OpCode GetOpCode()
{
return OpCode.CpuId;
}

public override byte[] ToMachineCode()
{
return new MachineInstructionBuilder(GetOpCode())
.GetInstruction();
}

public override string ToAssembly()
{
return $"cpuid {code.ToAssembly()}";
}
}
}
17 changes: 14 additions & 3 deletions src/Bytom.Assembler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,14 +459,25 @@ Software interrupt. The int instruction generates a software interrupt by invoki
interrupt handler specified by the interrupt code in the second operand.

- `int <reg>` - `0b0000_xxxx_xx00_0000_1000_0000_0000_0000` # 32 bit
- `int <con>` - `0b0000_0000_zzzz_zzzz_1000_0000_0000_0000` # 32 bit (zzzz_zzzz is 8 bit
interrupt code)

### iret

Return to the instruction following the last interrupt.

- `iret` - `0b0000_0000_0000_0000_1000_0000_0000_0001` # 32 bit
- `iret` - `0b0000_0000_0000_0000_1000_0000_0000_0100` # 32 bit

### cpuid

Query the CPU for information about its capabilities. Information queried is identified
by the value of register operand.

- `cpuid <reg>` - `0b0000_xxxx_xx00_0000_1000_0000_0000_1000` # 32 bit

Available information:

- `0x00` - Manufacturer name returned in `RD0`, `RD1`, `RD2`, `RD3` in that order.
- `0x0A` - CPU core index `RD0`, CPU thread index `RD1`, CPU package index `RD2`
- `0x0B` - CPU core count `RD0`, CPU thread count `RD1`, CPU package count `RD2`

## Address translation

Expand Down
14 changes: 14 additions & 0 deletions src/Bytom.Hardware/Bios/bios.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
start:
mov RD0, 0x0
cpuid RD0
cmp RD0, 0x0
jne idle
cmp RD1, 0x0
jne idle
cmp RD2, 0x0
jne idle
jmp core0
idle:
jmp idle
core0:
jmp core0
1 change: 0 additions & 1 deletion src/Bytom.Hardware/CPU/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,6 @@ public IoController GetMemoryController()
// Function used as main execution loop of the thread representing running core.
public virtual void executionLoop()
{
primeMicroOpDecoding();
while (!requested_power_off)
{
executeMicroOp();
Expand Down
3 changes: 2 additions & 1 deletion src/Bytom.Hardware/CPU/InstructionDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ public enum OpCode
OutConCon = 0b0000_1000_0010_0011,
// Kernel related instructions
Int = 0b1000_0000_0000_0000,
IRet = 0b1000_0000_0000_0001,
IRet = 0b1000_0000_0000_0100,
CpuId = 0b1000_0000_0000_1000,
}

public class InstructionDecoder
Expand Down

0 comments on commit 8e71f17

Please sign in to comment.