Add Memory Controllers for SP and PP, add Instruction Set

This commit is contained in:
Joop Schilder 2020-05-10 21:17:12 +02:00
parent ee896160b3
commit fda22052b8
17 changed files with 189 additions and 141 deletions

View File

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

BIN
ref/block_structure.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

BIN
ref/program_code_1.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

BIN
ref/program_code_2.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

BIN
ref/program_code_3.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
ref/programmable_words.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

BIN
ref/spindle_speeds.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

@ -2,7 +2,7 @@
namespace Automata;
class Registers
class DataRegisters
{
public int $B = 0; // Traverse information
public int $X = 0; // Dimension along X-axis
@ -17,5 +17,14 @@ class Registers
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 meanins
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)
}

View File

@ -0,0 +1,41 @@
<?php
namespace Automata;
use Program\Block;
class InstructionSet
{
private Machine $machine;
/** @var callable<Machine>[] */
private array $map;
public function __construct(Machine $machine)
{
$this->machine = $machine;
$this->map = [];
}
public function apply(Block $block): void
{
$words = $block->words;
while ($word = array_shift($words)) {
$method = "{$word}";
if (!method_exists($this, $method)) {
continue;
}
$this->{$method}($block);
break;
}
}
public function G22(Block $block): void
{
$number = $block->valueOf('X');
$this->machine->SPMC->loadProgram($number);
$this->machine->AMC = $this->machine->SPMC;
}
}

View File

@ -2,79 +2,57 @@
namespace Automata;
use Automata\Storage\ProgramMemory;
use Automata\Storage\ToolMemory;
use Program\Block;
use Program\Program;
use Program\Word;
use RuntimeException;
use SplStack;
use Automata\Memory\MemoryController;
use Automata\Memory\ProgramMemory;
use Automata\Memory\ToolMemory;
/*
* executing a program:
* - load parts program
* - execute line by line
* - load sub program
* - execute lines from subprogram
* - back to parts program
*/
class Machine
{
public State $state;
public ToolMemory $toolMemory;
public ProgramMemory $subProgramMemory;
public ProgramMemory $partProgramMemory;
/** @var SplStack|Program[] */
private SplStack $programStack;
private ?Program $activeProgram = null;
private Definitions $definitions;
public DataRegisters $DR;
public InstructionSet $IS;
public ToolMemory $TM;
public ProgramMemory $SPM;
public ProgramMemory $PPM;
public MemoryController $SPMC;
public MemoryController $PPMC;
public ?MemoryController $AMC;
public function __construct()
{
$this->state = new State();
$this->definitions = new Definitions();
$this->toolMemory = new ToolMemory();
$this->subProgramMemory = new ProgramMemory();
$this->partProgramMemory = new ProgramMemory();
$this->programStack = new SplStack();
$this->DR = new DataRegisters();
$this->IS = new InstructionSet($this);
$this->TM = new ToolMemory();
$this->SPM = new ProgramMemory();
$this->PPM = new ProgramMemory();
$this->SPMC = new MemoryController($this->SPM);
$this->PPMC = new MemoryController($this->PPM);
$this->AMC = $this->PPMC;
}
public function loadProgram(int $N): void
{
$this->programStack = new SplStack();
$program = $this->partProgramMemory->read($N);
$this->programStack->push($program);
$this->PPMC->loadProgram($N);
$this->AMC = $this->PPMC;
}
public function start(): void
public function step(): void
{
$this->activeProgram = $this->programStack->pop();
if (is_null($this->activeProgram)) {
throw new RuntimeException('No program loaded');
}
foreach ($this->activeProgram as $block) {
$this->executeBlock($block);
}
}
private function executeBlock(Block $block): void
{
/** @var Word[] $words */
$words = $block->words;
while ($word = array_shift($words)) {
$this->state->apply($word);
system('clear');
dump($this->state);
readline();
$block = $this->AMC->next();
if (is_null($block) && $this->AMC === $this->SPMC) {
// SP ended, back to PP
$this->AMC = $this->PPMC;
$block = $this->AMC->next();
}
$this->IS->apply($block);
}
public function reset(): void
{
$this->activeProgram = null;
$this->PPMC->reset();
$this->SPMC->reset();
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace Automata\Memory;
use Countable;
use InvalidArgumentException;
use Program\Block;
use RuntimeException;
class MemoryController implements Countable
{
private ProgramMemory $memory;
/** @var Block[]|null */
private ?array $blocks;
public function __construct(ProgramMemory $memory)
{
$this->memory = $memory;
$this->blocks = null;
}
public function loadProgram(int $N): void
{
$program = $this->memory->read($N);
if (!$program) {
throw new InvalidArgumentException("Program N{$N} not found");
}
$this->blocks = $program->getIterator()->getArrayCopy();
}
public function reset(): void
{
$this->blocks = null;
}
public function count()
{
return count($this->blocks);
}
public function next(): ?Block
{
$this->guardNoProgramLoaded();
return array_shift($this->blocks);
}
public function ready(): bool
{
return !empty($this->blocks);
}
private function guardNoProgramLoaded(): void
{
if (is_null($this->blocks)) {
throw new RuntimeException('No program loaded in memory');
}
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace Automata\Storage;
namespace Automata\Memory;
use InvalidArgumentException;
use Program\Program;
@ -11,7 +11,7 @@ class ProgramMemory
private array $memory = [];
public function save(Program $program): void
public function write(Program $program): void
{
$this->guardInvalidProgramNumber($program->N);
$this->memory[$program->N] = $program;
@ -30,5 +30,4 @@ class ProgramMemory
throw new InvalidArgumentException('Program number must be in range 9001 - 9998');
}
}
}

View File

@ -1,24 +1,24 @@
<?php
namespace Automata\Storage;
namespace Automata\Memory;
use Automata\Tool;
use Automata\ToolData;
use InvalidArgumentException;
class ToolMemory
{
/** @var Tool[] */
/** @var ToolData[] */
private array $memory = [];
public function save(Tool $tool): void
public function write(ToolData $tool): void
{
$this->guardInvalidToolNumber($tool->T);
$this->memory[$tool->T] = $tool;
}
public function read(int $T): ?Tool
public function read(int $T): ?ToolData
{
return @$this->memory[$T];
}
@ -30,5 +30,4 @@ class ToolMemory
throw new InvalidArgumentException('Tool number must be in range 1 - 64');
}
}
}

View File

@ -1,71 +0,0 @@
<?php
namespace Automata;
use Automata\Modes\G\DimensionMode;
use Automata\Modes\G\PlaneSelection;
use Automata\Modes\G\RadiusCompensation;
use Automata\Modes\G\TraverseMode;
use Automata\Modes\G\WorkCycle;
use Automata\Modes\M\CoolantMode;
use Automata\Modes\M\SpindleMode;
use Automata\Modes\M\TableClampingMode;
use Program\Word;
class State
{
public Registers $registers;
// G
public TraverseMode $traverseMode;
public PlaneSelection $planeSelection;
public RadiusCompensation $radiusCompensation;
public DimensionMode $dimensionMode;
public WorkCycle $workCycleSelection;
// M
public CoolantMode $coolantMode;
public SpindleMode $spindleMode;
public TableClampingMode $tableClamping;
public function __construct()
{
$this->registers = new Registers();
$this->traverseMode = new TraverseMode(0);
$this->planeSelection = new PlaneSelection(17);
$this->radiusCompensation = new RadiusCompensation(40);
$this->dimensionMode = new DimensionMode(90);
$this->workCycleSelection = new WorkCycle(0);
$this->coolantMode = new CoolantMode(9);
$this->spindleMode = new SpindleMode(5);
$this->tableClamping = new TableClampingMode(10);
}
public function apply(Word $word): void
{
if ($word->register === 'G') {
$this->traverseMode->apply($word->value);
$this->planeSelection->apply($word->value);
$this->radiusCompensation->apply($word->value);
$this->dimensionMode->apply($word->value);
$this->workCycleSelection->apply($word->value);
// TODO Handle other G commands
return;
}
if ($word->register === 'M') {
$this->coolantMode->apply($word->value);
$this->spindleMode->apply($word->value);
$this->tableClamping->apply($word->value);
// TODO Handle other M commands
return;
}
if (property_exists($this->registers, $word->register)) {
$this->registers->{$word->register} = $word->value;
}
}
}

View File

@ -2,7 +2,7 @@
namespace Automata;
class Tool
class ToolData
{
public int $T; // Tool number
public int $X; // Radius in 0.001 mm

View File

@ -2,6 +2,8 @@
namespace Program;
use RuntimeException;
class Block
{
public string $N;
@ -20,4 +22,27 @@ class Block
{
$this->words[] = $word;
}
public function valueOf(string $register): int
{
foreach ($this->words as $word) {
if ($word->register === $register) {
return $word->value;
}
}
throw new RuntimeException("No word in block for register '$register'");
}
public function __toString()
{
$buffer = "$this->N\t";
foreach ($this->words as $word) {
$buffer .= "$word\t";
}
return $buffer;
}
}

View File

@ -11,12 +11,12 @@ class ProgramLoader
foreach (glob(__DIR__ . '/../programs/part/*') as $partProgramFile) {
$partProgram = $parser->parseFile($partProgramFile);
$machine->partProgramMemory->save($partProgram);
$machine->PPM->write($partProgram);
}
foreach (glob(__DIR__ . '/../programs/sub/*') as $subProgramFile) {
$subProgram = $parser->parseFile($subProgramFile);
$machine->subProgramMemory->save($subProgram);
$machine->SPM->write($subProgram);
}
}
}