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
use Automata\Machine;
use Automata\NC;
use Automata\ToolData;
require_once __DIR__ . '/../vendor/autoload.php';
$machine = new Machine();
$machine->TM->write(new ToolData(1, 5500, 2));
$machine->TM->write(new ToolData(2, 3000, 61379));
(new ProgramLoader)->loadPrograms($machine);
$nc = new NC();
$nc->TM->write(new ToolData(1, 5500, 2));
$nc->TM->write(new ToolData(2, 3000, 61379));
(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 $T = 0; // Tool number
public int $H = 0; // Additional functions (unused)
public int $M = 0; // Auxiliary functions
public int $E = 0; // Number of repetitions / multiple meanings
// Modals
public int $TM = 0; // Traverse (0, 1, 2, 3)
public int $PS = 18; // Plane Selection (18, 19, 20)
public int $RC = 40; // Radius Compensation
public int $DM = 90; // Dimension (90, 91)
public int $WC = 0; // Work Cycle (null, 81, 84, 85, 86)
public int $CM = 8; // Coolant (8, 9)
public int $SM = 5; // Spindle (3, 4, 5)
public int $TC = 10; // Table Clamping (10, 11)
public int $G_TRAVERSE = 0;
public int $G_PLANE_SELECTION = 18;
public int $G_RADIUS_COMPENSATION = 40;
public int $G_DIMENSION_PROGRAMMING = 90;
public int $G_WORKCYCLE = 0;
public int $X_WORKCYCLE = 0;
public int $Y_WORKCYCLE = 0;
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;
use InvalidArgumentException;
use Program\Block;
use RuntimeException;
class InstructionSet
{
private Machine $machine;
/** @var callable<Machine>[] */
private array $map;
private const SPEEDS = [0, 40, 50, 63, 80, 100, 125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000];
private NC $machine;
public function __construct(Machine $machine)
public function __construct(NC $machine)
{
$this->machine = $machine;
$this->map = [];
}
public function apply(Block $block): void
{
print("$block\n");
$words = $block->words;
while ($word = array_shift($words)) {
$method = "{$word}";
if (!method_exists($this, $method)) {
continue;
system('clear');
print("\n$block\n\n");
foreach ($block->words as $word) {
if (method_exists($this, "$word")) {
// There's a method dedicated to handling the full word (eg G22)
$this->{"$word"}($block);
@$block->pop($word->register);
}
if (method_exists($this, $word->register)) {
// There's a method dedicated to handling data for the given register (eg T, S)
$this->{$word->register}($block->pop($word->register));
}
$this->{$method}($block);
break;
}
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
{
$number = $block->valueOf('X');
$this->machine->SPMC->loadProgram($number);
$N = $block->pop('X');
$this->machine->SPMC->loadProgram($N);
$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
{
private ProgramMemory $memory;
public ?int $N = null;
/** @var Block[]|null */
private ?array $blocks;
private ?array $blockBuffer;
private int $index;
public function __construct(ProgramMemory $memory)
{
$this->memory = $memory;
$this->blocks = null;
$this->blockBuffer = null;
}
@ -27,39 +29,53 @@ class MemoryController implements Countable
if (!$program) {
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
{
$this->blocks = null;
$this->N = null;
$this->blockBuffer = null;
$this->index = 0;
}
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
{
$this->guardNoProgramLoaded();
$block = $this->blockBuffer[$this->index++];
return array_shift($this->blocks);
return $block ? clone $block : null;
}
public function ready(): bool
{
return !empty($this->blocks);
return $this->count() > 0;
}
private function guardNoProgramLoaded(): void
{
if (is_null($this->blocks)) {
if (is_null($this->blockBuffer)) {
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\ToolMemory;
class Machine
class NC
{
public DataRegisters $DR;
public InstructionSet $IS;
@ -15,7 +15,7 @@ class Machine
public ProgramMemory $PPM;
public MemoryController $SPMC;
public MemoryController $PPMC;
public ?MemoryController $AMC;
public MemoryController $AMC;
public function __construct()
@ -48,6 +48,14 @@ class Machine
}
public function run(): void
{
while ($this->PPMC->ready()) {
$this->step();
}
}
public function reset(): void
{
$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) {
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;
}
}
@ -38,7 +64,7 @@ class Block
public function __toString()
{
$buffer = "$this->N\t";
$buffer = "N$this->N\t\t";
foreach ($this->words as $word) {
$buffer .= "$word\t";
}

View File

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