Initial implementation of instruction set

This commit is contained in:
Joop Schilder 2020-05-10 23:46:44 +02:00
parent e2bb39006a
commit 63fd73f98c
17 changed files with 389 additions and 222 deletions

View File

@ -1,16 +1,15 @@
<?php <?php
use Automata\Machine; use Automata\NC;
use Automata\ToolData; use Automata\ToolData;
require_once __DIR__ . '/../vendor/autoload.php'; require_once __DIR__ . '/../vendor/autoload.php';
$machine = new Machine(); $nc = new NC();
$machine->TM->write(new ToolData(1, 5500, 2)); $nc->TM->write(new ToolData(1, 5500, 2));
$machine->TM->write(new ToolData(2, 3000, 61379)); $nc->TM->write(new ToolData(2, 3000, 61379));
(new ProgramLoader)->loadPrograms($machine); (new ProgramLoader)->loadPrograms($nc);
$nc->loadProgram(9002);
$nc->run();
$machine->loadProgram(9002);
while ($machine->PPMC->ready()) {
$machine->step();
}

View File

@ -16,15 +16,19 @@ class DataRegisters
public int $S = 0; // Spindle speed in RPM public int $S = 0; // Spindle speed in RPM
public int $T = 0; // Tool number public int $T = 0; // Tool number
public int $H = 0; // Additional functions (unused) public int $H = 0; // Additional functions (unused)
public int $M = 0; // Auxiliary functions
public int $E = 0; // Number of repetitions / multiple meanings public int $E = 0; // Number of repetitions / multiple meanings
// Modals // Modals
public int $TM = 0; // Traverse (0, 1, 2, 3) public int $G_TRAVERSE = 0;
public int $PS = 18; // Plane Selection (18, 19, 20) public int $G_PLANE_SELECTION = 18;
public int $RC = 40; // Radius Compensation public int $G_RADIUS_COMPENSATION = 40;
public int $DM = 90; // Dimension (90, 91) public int $G_DIMENSION_PROGRAMMING = 90;
public int $WC = 0; // Work Cycle (null, 81, 84, 85, 86) public int $G_WORKCYCLE = 0;
public int $CM = 8; // Coolant (8, 9) public int $X_WORKCYCLE = 0;
public int $SM = 5; // Spindle (3, 4, 5) public int $Y_WORKCYCLE = 0;
public int $TC = 10; // Table Clamping (10, 11) public int $Z_WORKCYCLE = 0;
public int $B_WORKCYCLE = 0;
public int $M_PROGRAM = 0;
public int $M_COOLANT = 8;
public int $M_SPINDLE = 5;
public int $M_TABLE_CLAMPING = 10;
} }

View File

@ -2,41 +2,330 @@
namespace Automata; namespace Automata;
use InvalidArgumentException;
use Program\Block; use Program\Block;
use RuntimeException;
class InstructionSet class InstructionSet
{ {
private Machine $machine; private const SPEEDS = [0, 40, 50, 63, 80, 100, 125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000];
/** @var callable<Machine>[] */
private array $map; private NC $machine;
public function __construct(Machine $machine) public function __construct(NC $machine)
{ {
$this->machine = $machine; $this->machine = $machine;
$this->map = [];
} }
public function apply(Block $block): void public function apply(Block $block): void
{ {
print("$block\n"); system('clear');
$words = $block->words; print("\n$block\n\n");
while ($word = array_shift($words)) { foreach ($block->words as $word) {
$method = "{$word}"; if (method_exists($this, "$word")) {
if (!method_exists($this, $method)) { // There's a method dedicated to handling the full word (eg G22)
continue; $this->{"$word"}($block);
@$block->pop($word->register);
} }
$this->{$method}($block); if (method_exists($this, $word->register)) {
break; // There's a method dedicated to handling data for the given register (eg T, S)
$this->{$word->register}($block->pop($word->register));
} }
} }
foreach ($block->words as $word) {
// The word value may be put into the machine registers directly
if (property_exists($this->machine->DR, $word->register)) {
$this->machine->DR->{$word->register} = $block->pop($word->register);
} else {
print("WARNING: No method or register for word '{$word}'\n");
}
}
dump($this->machine->DR);
readline();
}
protected function E(int $value): void
{
print("WARNING: Line repetitions are not implemented yet");
}
protected function T(int $value): void
{
// Triggers an exception if not found, good enough for now.
// Might implement compensations and more explicit tool registers later on
$this->machine->TM->read($value);
$this->machine->DR->T = $value;
}
protected function S(int $value): void
{
if (!in_array($value, self::SPEEDS)) {
throw new InvalidArgumentException(sprintf(
"Speed not supported: '$value'. Supported are: \n%s\n",
implode(', ', self::SPEEDS)
));
}
$this->machine->DR->S = $value;
}
protected function G0(Block $block): void
{
$this->machine->DR->G_TRAVERSE = $block->read('G');
}
protected function G1(Block $block): void
{
$this->machine->DR->G_TRAVERSE = $block->read('G');
}
protected function G2(Block $block): void
{
$this->machine->DR->G_TRAVERSE = $block->read('G');
}
protected function G3(Block $block): void
{
$this->machine->DR->G_TRAVERSE = $block->read('G');
}
protected function G4(Block $block): void
{
print("Ignoring dwell setting: {$block->pop('X')}\n");
}
protected function G17(Block $block): void
{
$this->machine->DR->G_PLANE_SELECTION = $block->read('G');
}
protected function G18(Block $block): void
{
$this->machine->DR->G_PLANE_SELECTION = $block->read('G');
}
protected function G19(Block $block): void
{
$this->machine->DR->G_PLANE_SELECTION = $block->read('G');
}
protected function G22(Block $block): void protected function G22(Block $block): void
{ {
$number = $block->valueOf('X'); $N = $block->pop('X');
$this->machine->SPMC->loadProgram($number); $this->machine->SPMC->loadProgram($N);
$this->machine->AMC = $this->machine->SPMC; $this->machine->AMC = $this->machine->SPMC;
} }
protected function G40(Block $block): void
{
$this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G');
}
protected function G41(Block $block): void
{
$this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G');
}
protected function G42(Block $block): void
{
$this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G');
}
protected function G43(Block $block): void
{
$this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G');
}
protected function G44(Block $block): void
{
$this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G');
}
protected function G79(Block $block): void
{
// Ignore... ?? The action will be executed on set location
if ($this->machine->DR->B_WORKCYCLE === 0) {
throw new RuntimeException('No workcycle prepared!');
}
}
protected function G81(Block $block): void
{
$this->machine->DR->G_WORKCYCLE = $block->read('G');
$this->getWorkcycleParameters($block);
}
protected function G84(Block $block): void
{
$this->machine->DR->G_WORKCYCLE = $block->read('G');
$this->getWorkcycleParameters($block);
}
protected function G85(Block $block): void
{
$this->machine->DR->G_WORKCYCLE = $block->read('G');
$this->getWorkcycleParameters($block);
}
protected function G86(Block $block): void
{
$this->machine->DR->G_WORKCYCLE = $block->read('G');
$this->getWorkcycleParameters($block);
}
private function getWorkcycleParameters(Block $block): void
{
$this->machine->DR->X_WORKCYCLE = $block->has('X') ? $block->pop('X') : 0;
$this->machine->DR->Y_WORKCYCLE = $block->has('Y') ? $block->pop('Y') : 0;
$this->machine->DR->Z_WORKCYCLE = $block->has('Z') ? $block->pop('Z') : 0;
$this->machine->DR->B_WORKCYCLE = $block->has('B') ? $block->pop('B') : 0;
}
protected function G90(Block $block): void
{
$this->machine->DR->G_DIMENSION_PROGRAMMING = $block->read('G');
}
protected function G91(Block $block): void
{
$this->machine->DR->G_DIMENSION_PROGRAMMING = $block->read('G');
}
protected function G92(Block $block): void
{
// Incremental
foreach (['X', 'Y', 'Z'] as $R) {
if ($block->has($R)) {
$this->machine->DR->{$R} = -$block->pop($R);
}
}
}
protected function G93(Block $block): void
{
// Absolute zero datum shift
foreach (['X', 'Y', 'Z'] as $R) {
if ($block->has($R)) {
$this->machine->DR->{$R} -= $block->pop($R);
}
}
}
protected function G98(Block $block): void
{
// Automatic positioning to reference datum point
print("Ignoring automatic positioning to zero datum point\n");
}
protected function M0(Block $block): void
{
$this->machine->DR->M_PROGRAM = 0;
$this->machine->DR->M_SPINDLE = 5;
$this->machine->DR->M_COOLANT = 9;
}
protected function M2(Block $block): void
{
$this->machine->DR->M_PROGRAM = 2;
$this->machine->DR->M_SPINDLE = 5;
$this->machine->DR->M_COOLANT = 9;
}
protected function M3(Block $block): void
{
$this->machine->DR->M_SPINDLE = 3;
}
protected function M4(Block $block): void
{
$this->machine->DR->M_SPINDLE = 4;
}
protected function M5(Block $block): void
{
$this->machine->DR->M_SPINDLE = 5;
}
protected function M6(Block $block): void
{
$this->machine->DR->M_SPINDLE = 5;
$this->machine->DR->M_COOLANT = 9;
}
protected function M8(Block $block): void
{
$this->machine->DR->M_COOLANT = 8;
}
protected function M9(Block $block): void
{
$this->machine->DR->M_COOLANT = 9;
}
protected function M10(Block $block): void
{
$this->machine->DR->M_TABLE_CLAMPING = 10;
}
protected function M11(Block $block): void
{
$this->machine->DR->M_TABLE_CLAMPING = 11;
}
protected function M30(Block $block): void
{
$this->machine->DR->M_SPINDLE = 5;
$this->machine->DR->M_COOLANT = 9;
$N = $this->machine->PPMC->N;
$this->machine->PPMC->reset();
$this->machine->SPMC->reset();
$this->machine->PPMC->loadProgram($N);
$this->machine->AMC = $this->machine->PPMC;
}
protected function M67(Block $block): void
{
throw new RuntimeException('[Enter new tool information without machine stop] is not implemented');
}
} }

View File

@ -10,14 +10,16 @@ use RuntimeException;
class MemoryController implements Countable class MemoryController implements Countable
{ {
private ProgramMemory $memory; private ProgramMemory $memory;
public ?int $N = null;
/** @var Block[]|null */ /** @var Block[]|null */
private ?array $blocks; private ?array $blockBuffer;
private int $index;
public function __construct(ProgramMemory $memory) public function __construct(ProgramMemory $memory)
{ {
$this->memory = $memory; $this->memory = $memory;
$this->blocks = null; $this->blockBuffer = null;
} }
@ -27,39 +29,53 @@ class MemoryController implements Countable
if (!$program) { if (!$program) {
throw new InvalidArgumentException("Program N{$N} not found"); throw new InvalidArgumentException("Program N{$N} not found");
} }
$this->blocks = $program->getIterator()->getArrayCopy(); $this->N = $N;
$this->blockBuffer = $program->getIterator()->getArrayCopy();
$this->index = 0;
} }
public function reset(): void public function reset(): void
{ {
$this->blocks = null; $this->N = null;
$this->blockBuffer = null;
$this->index = 0;
} }
public function count() public function count()
{ {
return count($this->blocks); return count($this->blockBuffer) - $this->index;
}
public function previous(): ?Block
{
$this->guardNoProgramLoaded();
$block = $this->blockBuffer[$this->index--];
return $block ? clone $block : null;
} }
public function next(): ?Block public function next(): ?Block
{ {
$this->guardNoProgramLoaded(); $this->guardNoProgramLoaded();
$block = $this->blockBuffer[$this->index++];
return array_shift($this->blocks); return $block ? clone $block : null;
} }
public function ready(): bool public function ready(): bool
{ {
return !empty($this->blocks); return $this->count() > 0;
} }
private function guardNoProgramLoaded(): void private function guardNoProgramLoaded(): void
{ {
if (is_null($this->blocks)) { if (is_null($this->blockBuffer)) {
throw new RuntimeException('No program loaded in memory'); throw new RuntimeException('No program loaded in memory');
} }
} }

View File

@ -1,11 +0,0 @@
<?php
namespace Automata\Modes\G;
class DimensionMode extends G
{
public function supports(int $G): bool
{
return in_array($G, [90, 91]);
}
}

View File

@ -1,24 +0,0 @@
<?php
namespace Automata\Modes\G;
abstract class G
{
public int $G;
public function __construct(int $G)
{
$this->G = $G;
}
public final function apply(int $G): void
{
if ($this->supports($G)) {
$this->G = $G;
}
}
public abstract function supports(int $G): bool;
}

View File

@ -1,11 +0,0 @@
<?php
namespace Automata\Modes\G;
class PlaneSelection extends G
{
public function supports(int $G): bool
{
return in_array($G, [17, 18, 19]);
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace Automata\Modes\G;
class RadiusCompensation extends G
{
public function supports(int $G): bool
{
return in_array($G, [40, 41, 42, 43, 44]);
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace Automata\Modes\G;
class TraverseMode extends G
{
public function supports(int $G): bool
{
return in_array($G, [0, 1, 2, 3]);
}
}

View File

@ -1,17 +0,0 @@
<?php
namespace Automata\Modes\G;
class WorkCycle extends G
{
public int $X = 0;
public int $Y = 0;
public int $Z = 0;
public int $B = 0;
public function supports(int $G): bool
{
return in_array($G, [81, 84, 85, 86]);
}
}

View File

@ -1,29 +0,0 @@
<?php
namespace Automata\Modes\M;
class CoolantMode extends M
{
public function supports(int $M): bool
{
return in_array($M, [0, 2, 6, 8, 9, 30]);
}
public function apply(int $M): void
{
if (!$this->supports($M)) {
return;
}
if (in_array($M, [0, 2, 6, 30])) {
$this->M = 9;
return;
}
// 8 or 9
$this->M = $M;
}
}

View File

@ -1,24 +0,0 @@
<?php
namespace Automata\Modes\M;
abstract class M
{
public int $M;
public function __construct(int $M)
{
$this->M = $M;
}
public function apply(int $M): void
{
if ($this->supports($M)) {
$this->M = $M;
}
}
public abstract function supports(int $M): bool;
}

View File

@ -1,26 +0,0 @@
<?php
namespace Automata\Modes\M;
class SpindleMode extends M
{
public function supports(int $M): bool
{
return in_array($M, [0, 2, 3, 4, 5, 6, 30]);
}
public function apply(int $M): void
{
if (!$this->supports($M)) {
return;
}
if (in_array($M, [0, 2, 6, 30])) {
$this->M = 5;
return;
}
// 3, 4 or 5
$this->M = $M;
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace Automata\Modes\M;
class TableClampingMode extends M
{
public function supports(int $M): bool
{
return in_array($M, [10, 11]);
}
}

View File

@ -6,7 +6,7 @@ use Automata\Memory\MemoryController;
use Automata\Memory\ProgramMemory; use Automata\Memory\ProgramMemory;
use Automata\Memory\ToolMemory; use Automata\Memory\ToolMemory;
class Machine class NC
{ {
public DataRegisters $DR; public DataRegisters $DR;
public InstructionSet $IS; public InstructionSet $IS;
@ -15,7 +15,7 @@ class Machine
public ProgramMemory $PPM; public ProgramMemory $PPM;
public MemoryController $SPMC; public MemoryController $SPMC;
public MemoryController $PPMC; public MemoryController $PPMC;
public ?MemoryController $AMC; public MemoryController $AMC;
public function __construct() public function __construct()
@ -48,6 +48,14 @@ class Machine
} }
public function run(): void
{
while ($this->PPMC->ready()) {
$this->step();
}
}
public function reset(): void public function reset(): void
{ {
$this->PPMC->reset(); $this->PPMC->reset();

View File

@ -24,10 +24,36 @@ class Block
} }
public function valueOf(string $register): int public function has(string $register): bool
{ {
foreach ($this->words as $word) { foreach ($this->words as $word) {
if ($word->register === $register) { if ($word->register === $register) {
return true;
}
}
return false;
}
public function read(string $register): int
{
foreach ($this->words as $index => $word) {
if ($word->register === $register) {
return $word->value;
}
}
throw new RuntimeException("No word in block for register '$register'");
}
public function pop(string $register): int
{
foreach ($this->words as $index => $word) {
if ($word->register === $register) {
unset($this->words[$index]);
return $word->value; return $word->value;
} }
} }
@ -38,7 +64,7 @@ class Block
public function __toString() public function __toString()
{ {
$buffer = "$this->N\t"; $buffer = "N$this->N\t\t";
foreach ($this->words as $word) { foreach ($this->words as $word) {
$buffer .= "$word\t"; $buffer .= "$word\t";
} }

View File

@ -1,11 +1,11 @@
<?php <?php
use Automata\Machine; use Automata\NC;
use Program\ProgramParser; use Program\ProgramParser;
class ProgramLoader class ProgramLoader
{ {
public function loadPrograms(Machine $machine): void public function loadPrograms(NC $machine): void
{ {
$parser = new ProgramParser(); $parser = new ProgramParser();