<commit_before>#include "catch.hpp"

#include "../src/population.hpp"
#include "../src/random.hpp"
#include "../src/sequence.hpp"

TEST_CASE( "Test for random", "[random]" ) {
   random::set_seed(1);

   SECTION ( "random float inside range" ) {
      float rand_f = random::f_range(0, 0.5);
      REQUIRE(rand_f < 0.5);
      REQUIRE(rand_f > 0.0);
   }

   SECTION ( "random integer inside positive range" ) {
      int rand_i = random::i_range(0, 5);
      REQUIRE(rand_i <= 5);
      REQUIRE(rand_i >= 0);
   }

   SECTION ( "random integer inside negative range" ) {
      int rand_i = random::i_range(-10, -5);
      REQUIRE(rand_i <= -5);
      REQUIRE(rand_i >= -10);
   }

   SECTION ( "random integer range with both" ) {
      int rand_neg = random::i_range(-5, 5);
      REQUIRE(rand_neg <= 5);
      REQUIRE(rand_neg >= -5);
   }

   SECTION ( "repeat random integers not equal" ) {
      int rand_1 = random::i_range(0, 100);
      int rand_2 = random::i_range(0, 100);
      REQUIRE(rand_1 != rand_2);
   }

   SECTION ( "random reset produces repeatable results" ) {
      random::reset();
      int rand_1 = random::i_range(0, 100);
      random::reset();
      int rand_2 = random::i_range(0, 100);
      REQUIRE(rand_1 == rand_2);
   }

   SECTION ( "different seeds, different results" ) {
      random::set_seed(2);
      int rand_1 = random::i_range(0, 100);
      random::set_seed(3);
      int rand_2 = random::i_range(0, 100);
      REQUIRE(rand_1 != rand_2);
   }
}

TEST_CASE( "Test for genetic::sequence", "[sequence]" ) {
   // Predictable random tests (that passed before)
   random::set_seed(1);
   SECTION ( "genes of two rand inits are different" ) {
      genetic::sequence a, b;
      // Two random individuals don't match
      REQUIRE_FALSE(a == b);
      REQUIRE_FALSE(a.get_fitness() == b.get_fitness());
   }

   SECTION ( "mutations with different rates" ) {
      // Copy constructor
      genetic::sequence a;
      genetic::sequence a_dup = a;
      REQUIRE(a_dup == a);
      // Mutate (0 = none)
      a.mutate(0.0);
      REQUIRE(a_dup == a);
      REQUIRE(a_dup.get_fitness() == a.get_fitness());
      // Mutation > 0.0 should modify genes
      a.mutate(0.5);
      REQUIRE_FALSE(a_dup == a);
      REQUIRE(a_dup.get_fitness() != a.get_fitness());
      // Mutation == 1.0 should modify again
      a.mutate(1.0);
      REQUIRE_FALSE(a_dup == a);
      REQUIRE(a_dup.get_fitness() != a.get_fitness());
   }

   SECTION ( "crossover results in differnet children" ) {
      genetic::sequence a,b;
      // Crossover (child) doesn't exactly match either parent
      genetic::sequence child = genetic::sequence::crossover(a, b);
      REQUIRE_FALSE(child == a);
      REQUIRE_FALSE(child == b);

      // Crossover (siblings) shouldn't match
      genetic::sequence sibling = genetic::sequence::crossover(a, b);
      REQUIRE_FALSE(sibling == child);
      REQUIRE_FALSE(sibling == a);
   }
}

TEST_CASE( "Test for genetic::population", "[population]" ) {
   // Predictable random tests (that passed before)
   random::set_seed(1);

   SECTION ( "population size constant through evoluation, factor of 3" ) {
      genetic::population<genetic::sequence> pop(99);
      REQUIRE(pop.get_size() == 99);
      pop.evolve(1, genetic::sequence::get_max_fitness(), 0.2, true);
      REQUIRE(pop.get_size() == 99);
   }

   SECTION ( "population size constant through evoluation, non-factor of 3" ) {
      genetic::population<genetic::sequence> pop_odd(101);
      REQUIRE(pop_odd.get_size() == 101);
      pop_odd.evolve(1, genetic::sequence::get_max_fitness(), 0.2, true);
      REQUIRE(pop_odd.get_size() == 101);
   }

   SECTION ( "evoluation should improve fitness" ) {
      genetic::population<genetic::sequence> pop(99);
      auto pop_old = pop;
      pop.evolve(1, genetic::sequence::get_max_fitness(), 0.2, true);
      REQUIRE(pop.get_fittest().get_fitness() >= pop_old.get_fittest().get_fitness());
      REQUIRE(pop.get_fitness() >= pop_old.get_fitness());
   }

   SECTION ( "20 evoluation cycles" ) {
      genetic::population<genetic::sequence> pop(99);
      auto pop_old = pop;
      pop.evolve(20, genetic::sequence::get_max_fitness(), 0.1, true);
      REQUIRE(pop.get_fittest().get_fitness() >= pop_old.get_fittest().get_fitness());
      REQUIRE(pop.get_fitness() >= pop_old.get_fitness());
      REQUIRE(pop.get_size() >= pop_old.get_size());
   }
}<commit_msg>add test for previous results of easy solution to prevent convergence degredation<commit_after>#include "catch.hpp"

#include "../src/population.hpp"
#include "../src/random.hpp"
#include "../src/sequence.hpp"

TEST_CASE( "Test for random", "[random]" ) {
   random::set_seed(1);

   SECTION ( "random float inside range" ) {
      float rand_f = random::f_range(0, 0.5);
      REQUIRE(rand_f < 0.5);
      REQUIRE(rand_f > 0.0);
   }

   SECTION ( "random integer inside positive range" ) {
      int rand_i = random::i_range(0, 5);
      REQUIRE(rand_i <= 5);
      REQUIRE(rand_i >= 0);
   }

   SECTION ( "random integer inside negative range" ) {
      int rand_i = random::i_range(-10, -5);
      REQUIRE(rand_i <= -5);
      REQUIRE(rand_i >= -10);
   }

   SECTION ( "random integer range with both" ) {
      int rand_neg = random::i_range(-5, 5);
      REQUIRE(rand_neg <= 5);
      REQUIRE(rand_neg >= -5);
   }

   SECTION ( "repeat random integers not equal" ) {
      int rand_1 = random::i_range(0, 100);
      int rand_2 = random::i_range(0, 100);
      REQUIRE(rand_1 != rand_2);
   }

   SECTION ( "random reset produces repeatable results" ) {
      random::reset();
      int rand_1 = random::i_range(0, 100);
      random::reset();
      int rand_2 = random::i_range(0, 100);
      REQUIRE(rand_1 == rand_2);
   }

   SECTION ( "different seeds, different results" ) {
      random::set_seed(2);
      int rand_1 = random::i_range(0, 100);
      random::set_seed(3);
      int rand_2 = random::i_range(0, 100);
      REQUIRE(rand_1 != rand_2);
   }
}

TEST_CASE( "Test for genetic::sequence", "[sequence]" ) {
   // Predictable random tests (that passed before)
   random::set_seed(1);
   SECTION ( "genes of two rand inits are different" ) {
      genetic::sequence a, b;
      // Two random individuals don't match
      REQUIRE_FALSE(a == b);
      REQUIRE_FALSE(a.get_fitness() == b.get_fitness());
   }

   SECTION ( "mutations with different rates" ) {
      // Copy constructor
      genetic::sequence a;
      genetic::sequence a_dup = a;
      REQUIRE(a_dup == a);
      // Mutate (0 = none)
      a.mutate(0.0);
      REQUIRE(a_dup == a);
      REQUIRE(a_dup.get_fitness() == a.get_fitness());
      // Mutation > 0.0 should modify genes
      a.mutate(0.5);
      REQUIRE_FALSE(a_dup == a);
      REQUIRE(a_dup.get_fitness() != a.get_fitness());
      // Mutation == 1.0 should modify again
      a.mutate(1.0);
      REQUIRE_FALSE(a_dup == a);
      REQUIRE(a_dup.get_fitness() != a.get_fitness());
   }

   SECTION ( "crossover results in differnet children" ) {
      genetic::sequence a,b;
      // Crossover (child) doesn't exactly match either parent
      genetic::sequence child = genetic::sequence::crossover(a, b);
      REQUIRE_FALSE(child == a);
      REQUIRE_FALSE(child == b);

      // Crossover (siblings) shouldn't match
      genetic::sequence sibling = genetic::sequence::crossover(a, b);
      REQUIRE_FALSE(sibling == child);
      REQUIRE_FALSE(sibling == a);
   }
}

TEST_CASE( "Test for genetic::population", "[population]" ) {
   // Predictable random tests (that passed before)
   random::set_seed(1);

   SECTION ( "population size constant through evoluation, factor of 3" ) {
      genetic::population<genetic::sequence> pop(99);
      REQUIRE(pop.get_size() == 99);
      pop.evolve(1, genetic::sequence::get_max_fitness(), 0.2, true);
      REQUIRE(pop.get_size() == 99);
   }

   SECTION ( "population size constant through evoluation, non-factor of 3" ) {
      genetic::population<genetic::sequence> pop_odd(101);
      REQUIRE(pop_odd.get_size() == 101);
      pop_odd.evolve(1, genetic::sequence::get_max_fitness(), 0.2, true);
      REQUIRE(pop_odd.get_size() == 101);
   }

   SECTION ( "evoluation should improve fitness" ) {
      genetic::population<genetic::sequence> pop(99);
      auto pop_old = pop;
      pop.evolve(1, genetic::sequence::get_max_fitness(), 0.2, true);
      REQUIRE(pop.get_fittest().get_fitness() >= pop_old.get_fittest().get_fitness());
      REQUIRE(pop.get_fitness() >= pop_old.get_fitness());
   }

   SECTION ( "20 evoluation cycles" ) {
      genetic::population<genetic::sequence> pop(99);
      auto pop_old = pop;
      pop.evolve(20, genetic::sequence::get_max_fitness(), 0.1, true);
      REQUIRE(pop.get_fittest().get_fitness() >= pop_old.get_fittest().get_fitness());
      REQUIRE(pop.get_fitness() >= pop_old.get_fitness());
      REQUIRE(pop.get_size() >= pop_old.get_size());
   }
}

TEST_CASE( "Test for previous results", "[results]" ) {
   // Predictable random tests (that passed before)
   random::set_seed(1);

   SECTION ( "'easy' solution" ) {
      genetic::sequence::set_solution("easy");
      genetic::population<genetic::sequence> pop(99);
      REQUIRE(pop.evolve(50, genetic::sequence::get_max_fitness(), 0.08, true));
   }
}<|endoftext|>


<commit_before>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string>
#include <vector>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "sandbox.h"

using namespace std;

static const uint32_t STACK_SIZE = 64 * 1024;

bool loadRawData(machine& mach, const string& filename)
{
	// open and mmap input file
	mfile pf(filename);
	if (!pf.open(O_RDONLY))
		return false;

	static unsigned int dataCount = 0;
	char tmpstr[32];

	// alloc new data memory range
	sprintf(tmpstr, "data%u", dataCount++);
	size_t sz = pf.st.st_size;
	addressRange *rdr = new addressRange(tmpstr, sz);

	// copy mmap'd data into local buffer
	rdr->buf.assign((char *) pf.data, sz);
	rdr->updateRoot();

	// add to global memory map
	return mach.mapInsert(rdr);
}

static void usage(const char *progname)
{
	fprintf(stderr,
		"Usage: %s [options]\n"
		"\n"
		"options:\n"
		"-E <directory>\t\tAdd to executable hash search path list\n"
		"-e <hash|pathname>\tLoad specified Moxie executable into address space\n"
		"-D <directory>\t\tAdd to data hash search path list\n"
		"-d <file>\t\tLoad data into address space\n"
		"-o <file>\t\tOutput data to <file>.  \"-\" for stdout\n"
		"-t\t\t\tEnabling simulator tracing\n"
		,
		progname);
}

static void printMemMap(machine &mach)
{
	for (unsigned int i = 0; i < mach.memmap.size(); i++) {
		addressRange *ar = mach.memmap[i];
		fprintf(stderr, "%s %08x-%08x %s\n",
			ar->readOnly ? "ro" : "rw", ar->start, ar->end,
			ar->name.c_str());
	}
}

static void addStackMem(machine& mach)
{
	// alloc r/w memory range
	addressRange *rdr = new addressRange("stack", STACK_SIZE);

	rdr->buf.resize(STACK_SIZE);
	rdr->updateRoot();
	rdr->readOnly = false;

	// add memory range to global memory map
	mach.mapInsert(rdr);

	// set SR #7 to now-initialized stack vaddr
	mach.cpu.asregs.sregs[7] = rdr->end;
}

static void addMapDescriptor(machine& mach)
{
	// fill list from existing memory map
	vector<struct mach_memmap_ent> desc;
	mach.fillDescriptors(desc);

	// add entry for the mapdesc range to be added to memory map
	struct mach_memmap_ent mme_self;
	memset(&mme_self, 0, sizeof(mme_self));
	desc.push_back(mme_self);

	// add blank entry for list terminator
	struct mach_memmap_ent mme_end;
	memset(&mme_end, 0, sizeof(mme_end));
	desc.push_back(mme_end);

	// calc total region size
	size_t sz = sizeof(mme_end) * desc.size();

	// manually fill in mapdesc range descriptor
	mme_self.length = sz;
	strcpy(mme_self.tags, "ro,mapdesc,");

	// build entry for global memory map
	addressRange *ar = new addressRange("mapdesc", sz);

	// allocate space for descriptor array
	ar->buf.resize(sz);
	ar->updateRoot();

	// copy 'desc' array into allocated memory space
	unsigned int i = 0;
	for (vector<struct mach_memmap_ent>::iterator it = desc.begin();
	     it != desc.end(); it++, i++) {
		struct mach_memmap_ent& mme = (*it);
		memcpy(&ar->buf[i * sizeof(mme)], &mme, sizeof(mme));
	}

	// add memory range to global memory map
	mach.mapInsert(ar);

	// set SR #6 to now-initialized mapdesc start vaddr
	mach.cpu.asregs.sregs[6] = ar->start;
}

static void gatherOutput(machine& mach, const string& outFilename)
{
	if (!outFilename.size())
		return;

	uint32_t vaddr = mach.cpu.asregs.sregs[6];
	uint32_t length = mach.cpu.asregs.sregs[7];
	if (!vaddr || !length)
		return;

	char *p = (char *) mach.physaddr(vaddr, length);
	if (!p) {
		fprintf(stderr, "Sim exception %d (%s) upon output\n",
			SIGBUS,
			strsignal(SIGBUS));
		exit(EXIT_FAILURE);
	}

	int fd;
	if (outFilename == "-") {
		fd = STDOUT_FILENO;
	} else {
		fd = open(outFilename.c_str(),
			  O_WRONLY | O_CREAT | O_TRUNC, 0666);
		if (fd < 0) {
			perror(outFilename.c_str());
			exit(EXIT_FAILURE);
		}
	}

	while (length > 0) {
		ssize_t bytes = write(fd, p, length);
		if (bytes < 0) {
			perror(outFilename.c_str());
			exit(EXIT_FAILURE);
		}

		length -= bytes;
		p += bytes;
	}

	close(fd);
}

static bool isDir(const char *pathname)
{
	struct stat st;

	if (stat(pathname, &st) < 0)
		return false;

	return S_ISDIR(st.st_mode);
}

int main (int argc, char *argv[])
{
	machine mach;

	vector<string> pathExec;
	vector<string> pathData;

	bool progLoaded = false;
	string outFilename;
	int opt;
	while ((opt = getopt(argc, argv, "E:e:D:d:o:t")) != -1) {
		switch(opt) {
		case 'E':
			if (!isDir(optarg)) {
				fprintf(stderr, "%s not a directory\n", optarg);
				exit(EXIT_FAILURE);
			}
			pathExec.push_back(optarg);
			break;
		case 'e':
			bool rc;
			if (IsHex(optarg))
				rc = loadElfHash(mach, optarg, pathExec);
			else
				rc = loadElfProgram(mach, optarg);
			if (!rc) {
				fprintf(stderr, "ELF load failed for %s\n",
					optarg);
				exit(EXIT_FAILURE);
			}
			progLoaded = true;
			break;
		case 'D':
			if (!isDir(optarg)) {
				fprintf(stderr, "%s not a directory\n", optarg);
				exit(EXIT_FAILURE);
			}
			pathExec.push_back(optarg);
			break;
		case 'd':
			if (!loadRawData(mach, optarg)) {
				fprintf(stderr, "Data load failed for %s\n",
					optarg);
				exit(EXIT_FAILURE);
			}
			break;

		case 'o':
			outFilename = optarg;
			break;

		case 't':
			mach.tracing = true;
			break;

		default:
			usage(argv[0]);
			exit(EXIT_FAILURE);
		}
	}

	if (!progLoaded) {
		fprintf(stderr, "No Moxie program loaded.\n");
		usage(argv[0]);
		exit(EXIT_FAILURE);
	}

	addStackMem(mach);
	addMapDescriptor(mach);

	printMemMap(mach);

	mach.cpu.asregs.regs[PC_REGNO] = mach.startAddr;

	// create new child process
	pid_t child = fork();
	if (child == -1) {
		perror("fork");
		exit(EXIT_FAILURE);
	}

	// child executes sandbox
	if (child == 0) {
		sim_resume(mach);

		if (mach.cpu.asregs.exception != SIGQUIT) {
			fprintf(stderr, "Sim exception %d (%s)\n",
				mach.cpu.asregs.exception,
				strsignal(mach.cpu.asregs.exception));
			exit(EXIT_FAILURE);
		}

		gatherOutput(mach, outFilename);

		// return $r0, the exit status passed to _exit()
		exit(mach.cpu.asregs.regs[2] & 0xff);

	// parent waits
	} else {
		int status = 0;
		pid_t res = wait(&status);
		if (res == -1)
			perror("wait");

		return WEXITSTATUS(status);
	}

	return EXIT_FAILURE;	// not reached
}

<commit_msg>Revert "execute simulator in child process"<commit_after>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string>
#include <vector>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "sandbox.h"

using namespace std;

static const uint32_t STACK_SIZE = 64 * 1024;

bool loadRawData(machine& mach, const string& filename)
{
	// open and mmap input file
	mfile pf(filename);
	if (!pf.open(O_RDONLY))
		return false;

	static unsigned int dataCount = 0;
	char tmpstr[32];

	// alloc new data memory range
	sprintf(tmpstr, "data%u", dataCount++);
	size_t sz = pf.st.st_size;
	addressRange *rdr = new addressRange(tmpstr, sz);

	// copy mmap'd data into local buffer
	rdr->buf.assign((char *) pf.data, sz);
	rdr->updateRoot();

	// add to global memory map
	return mach.mapInsert(rdr);
}

static void usage(const char *progname)
{
	fprintf(stderr,
		"Usage: %s [options]\n"
		"\n"
		"options:\n"
		"-E <directory>\t\tAdd to executable hash search path list\n"
		"-e <hash|pathname>\tLoad specified Moxie executable into address space\n"
		"-D <directory>\t\tAdd to data hash search path list\n"
		"-d <file>\t\tLoad data into address space\n"
		"-o <file>\t\tOutput data to <file>.  \"-\" for stdout\n"
		"-t\t\t\tEnabling simulator tracing\n"
		,
		progname);
}

static void printMemMap(machine &mach)
{
	for (unsigned int i = 0; i < mach.memmap.size(); i++) {
		addressRange *ar = mach.memmap[i];
		fprintf(stderr, "%s %08x-%08x %s\n",
			ar->readOnly ? "ro" : "rw", ar->start, ar->end,
			ar->name.c_str());
	}
}

static void addStackMem(machine& mach)
{
	// alloc r/w memory range
	addressRange *rdr = new addressRange("stack", STACK_SIZE);

	rdr->buf.resize(STACK_SIZE);
	rdr->updateRoot();
	rdr->readOnly = false;

	// add memory range to global memory map
	mach.mapInsert(rdr);

	// set SR #7 to now-initialized stack vaddr
	mach.cpu.asregs.sregs[7] = rdr->end;
}

static void addMapDescriptor(machine& mach)
{
	// fill list from existing memory map
	vector<struct mach_memmap_ent> desc;
	mach.fillDescriptors(desc);

	// add entry for the mapdesc range to be added to memory map
	struct mach_memmap_ent mme_self;
	memset(&mme_self, 0, sizeof(mme_self));
	desc.push_back(mme_self);

	// add blank entry for list terminator
	struct mach_memmap_ent mme_end;
	memset(&mme_end, 0, sizeof(mme_end));
	desc.push_back(mme_end);

	// calc total region size
	size_t sz = sizeof(mme_end) * desc.size();

	// manually fill in mapdesc range descriptor
	mme_self.length = sz;
	strcpy(mme_self.tags, "ro,mapdesc,");

	// build entry for global memory map
	addressRange *ar = new addressRange("mapdesc", sz);

	// allocate space for descriptor array
	ar->buf.resize(sz);
	ar->updateRoot();

	// copy 'desc' array into allocated memory space
	unsigned int i = 0;
	for (vector<struct mach_memmap_ent>::iterator it = desc.begin();
	     it != desc.end(); it++, i++) {
		struct mach_memmap_ent& mme = (*it);
		memcpy(&ar->buf[i * sizeof(mme)], &mme, sizeof(mme));
	}

	// add memory range to global memory map
	mach.mapInsert(ar);

	// set SR #6 to now-initialized mapdesc start vaddr
	mach.cpu.asregs.sregs[6] = ar->start;
}

static void gatherOutput(machine& mach, const string& outFilename)
{
	if (!outFilename.size())
		return;

	uint32_t vaddr = mach.cpu.asregs.sregs[6];
	uint32_t length = mach.cpu.asregs.sregs[7];
	if (!vaddr || !length)
		return;

	char *p = (char *) mach.physaddr(vaddr, length);
	if (!p) {
		fprintf(stderr, "Sim exception %d (%s) upon output\n",
			SIGBUS,
			strsignal(SIGBUS));
		exit(EXIT_FAILURE);
	}

	int fd;
	if (outFilename == "-") {
		fd = STDOUT_FILENO;
	} else {
		fd = open(outFilename.c_str(),
			  O_WRONLY | O_CREAT | O_TRUNC, 0666);
		if (fd < 0) {
			perror(outFilename.c_str());
			exit(EXIT_FAILURE);
		}
	}

	while (length > 0) {
		ssize_t bytes = write(fd, p, length);
		if (bytes < 0) {
			perror(outFilename.c_str());
			exit(EXIT_FAILURE);
		}

		length -= bytes;
		p += bytes;
	}

	close(fd);
}

static bool isDir(const char *pathname)
{
	struct stat st;

	if (stat(pathname, &st) < 0)
		return false;

	return S_ISDIR(st.st_mode);
}

int main (int argc, char *argv[])
{
	machine mach;

	vector<string> pathExec;
	vector<string> pathData;

	bool progLoaded = false;
	string outFilename;
	int opt;
	while ((opt = getopt(argc, argv, "E:e:D:d:o:t")) != -1) {
		switch(opt) {
		case 'E':
			if (!isDir(optarg)) {
				fprintf(stderr, "%s not a directory\n", optarg);
				exit(EXIT_FAILURE);
			}
			pathExec.push_back(optarg);
			break;
		case 'e':
			bool rc;
			if (IsHex(optarg))
				rc = loadElfHash(mach, optarg, pathExec);
			else
				rc = loadElfProgram(mach, optarg);
			if (!rc) {
				fprintf(stderr, "ELF load failed for %s\n",
					optarg);
				exit(EXIT_FAILURE);
			}
			progLoaded = true;
			break;
		case 'D':
			if (!isDir(optarg)) {
				fprintf(stderr, "%s not a directory\n", optarg);
				exit(EXIT_FAILURE);
			}
			pathExec.push_back(optarg);
			break;
		case 'd':
			if (!loadRawData(mach, optarg)) {
				fprintf(stderr, "Data load failed for %s\n",
					optarg);
				exit(EXIT_FAILURE);
			}
			break;

		case 'o':
			outFilename = optarg;
			break;

		case 't':
			mach.tracing = true;
			break;

		default:
			usage(argv[0]);
			exit(EXIT_FAILURE);
		}
	}

	if (!progLoaded) {
		fprintf(stderr, "No Moxie program loaded.\n");
		usage(argv[0]);
		exit(EXIT_FAILURE);
	}

	addStackMem(mach);
	addMapDescriptor(mach);

	printMemMap(mach);

	mach.cpu.asregs.regs[PC_REGNO] = mach.startAddr;
	sim_resume(mach);

	if (mach.cpu.asregs.exception != SIGQUIT) {
		fprintf(stderr, "Sim exception %d (%s)\n",
			mach.cpu.asregs.exception,
			strsignal(mach.cpu.asregs.exception));
		exit(EXIT_FAILURE);
	}

	gatherOutput(mach, outFilename);

	// return $r0, the exit status passed to _exit()
	return mach.cpu.asregs.regs[2];
}

<|endoftext|>


<commit_before>//
//  1770.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 17/09/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "1770.hpp"
#include "../../Storage/Disk/Encodings/MFM.hpp"

using namespace WD;

WD1770::WD1770() :
	Storage::Disk::Drive(8000000, 1, 300),
	status_(0),
	interesting_event_mask_(Event::Command),
	resume_point_(0),
	delay_time_(0)
{
	set_is_double_density(false);
	posit_event(Event::Command);
}

void WD1770::set_is_double_density(bool is_double_density)
{
	is_double_density_ = is_double_density;
	Storage::Time bit_length;
	bit_length.length = 1;
	bit_length.clock_rate = is_double_density ? 500000 : 250000;
	set_expected_bit_length(bit_length);
}

void WD1770::set_register(int address, uint8_t value)
{
	switch(address&3)
	{
		case 0:
			command_ = value;
			posit_event(Event::Command);
			// TODO: is this force interrupt?
		break;
		case 1:		track_ = value;		break;
		case 2:		sector_ = value;	break;
		case 3:		data_ = value;		break;
	}
}

uint8_t WD1770::get_register(int address)
{
	switch(address&3)
	{
		default:	return status_;
		case 1:		return track_;
		case 2:		return sector_;
		case 3:		status_ &= ~Flag::DataRequest; return data_;
	}
}

void WD1770::run_for_cycles(unsigned int number_of_cycles)
{
	if(status_ & Flag::MotorOn) Storage::Disk::Drive::run_for_cycles((int)number_of_cycles);

	if(delay_time_)
	{
		if(delay_time_ <= number_of_cycles)
		{
			delay_time_ = 0;
			posit_event(Event::Timer);
		}
		else
		{
			delay_time_ -= number_of_cycles;
		}
	}
}

void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole)
{
	shift_register_ = (shift_register_ << 1) | value;
	bits_since_token_++;

	Token::Type token_type = Token::Byte;
	if(!is_double_density_)
	{
		switch(shift_register_ & 0xffff)
		{
			case Storage::Encodings::MFM::FMIndexAddressMark:
				token_type = Token::Index;
			break;
			case Storage::Encodings::MFM::FMIDAddressMark:
				token_type = Token::ID;
			break;
			case Storage::Encodings::MFM::FMDataAddressMark:
				token_type = Token::Data;
			break;
			case Storage::Encodings::MFM::FMDeletedDataAddressMark:
				token_type = Token::DeletedData;
			break;
			default:
			break;
		}
	}
	else
	{
		// TODO: MFM
	}

	if(token_type != Token::Byte)
	{
		latest_token_.type = token_type;
		bits_since_token_ = 0;
		posit_event(Event::Token);
		return;
	}

	if(bits_since_token_ == 16)
	{
		latest_token_.type = Token::Byte;
		latest_token_.byte_value = (uint8_t)(
			((shift_register_ & 0x0001) >> 0) |
			((shift_register_ & 0x0004) >> 1) |
			((shift_register_ & 0x0010) >> 2) |
			((shift_register_ & 0x0040) >> 3) |
			((shift_register_ & 0x0100) >> 4) |
			((shift_register_ & 0x0400) >> 5) |
			((shift_register_ & 0x1000) >> 6) |
			((shift_register_ & 0x4000) >> 7));
		bits_since_token_ = 0;
		posit_event(Event::Token);
		return;
	}
}

void WD1770::process_index_hole()
{
	index_hole_count_++;
	posit_event(Event::IndexHole);

	// motor power-down
//	if(index_hole_count_ == 9 && !(status_&Flag::Busy)) status_ &= ~Flag::MotorOn;
}

//     +------+----------+-------------------------+
//     !	    !	       !	   BITS 	 !
//     ! TYPE ! COMMAND  !  7  6	5  4  3  2  1  0 !
//     +------+----------+-------------------------+
//     !	 1  ! Restore  !  0  0	0  0  h  v r1 r0 !
//     !	 1  ! Seek     !  0  0	0  1  h  v r1 r0 !
//     !	 1  ! Step     !  0  0	1  u  h  v r1 r0 !
//     !	 1  ! Step-in  !  0  1	0  u  h  v r1 r0 !
//     !	 1  ! Step-out !  0  1	1  u  h  v r1 r0 !
//     !	 2  ! Rd sectr !  1  0	0  m  h  E  0  0 !
//     !	 2  ! Wt sectr !  1  0	1  m  h  E  P a0 !
//     !	 3  ! Rd addr  !  1  1	0  0  h  E  0  0 !
//     !	 3  ! Rd track !  1  1	1  0  h  E  0  0 !
//     !	 3  ! Wt track !  1  1	1  1  h  E  P  0 !
//     !	 4  ! Forc int !  1  1	0  1 i3 i2 i1 i0 !
//     +------+----------+-------------------------+

#define WAIT_FOR_EVENT(mask)	resume_point_ = __LINE__; interesting_event_mask_ = mask; return; case __LINE__:
#define WAIT_FOR_TIME(ms)		resume_point_ = __LINE__; interesting_event_mask_ = Event::Timer; delay_time_ = ms * 8000; if(delay_time_) return; case __LINE__:
#define BEGIN_SECTION()	switch(resume_point_) { default:
#define END_SECTION()	0; }

void WD1770::posit_event(Event new_event_type)
{
	if(!(interesting_event_mask_ & (int)new_event_type)) return;
	interesting_event_mask_ &= ~new_event_type;

	BEGIN_SECTION()

	// Wait for a new command, branch to the appropriate handler.
	wait_for_command:
		printf("Idle...\n");
		status_ &= ~Flag::Busy;
		index_hole_count_ = 0;
		WAIT_FOR_EVENT(Event::Command);
		printf("Starting %02x\n", command_);
		status_ |= Flag::Busy;
		if(!(command_ & 0x80)) goto begin_type_1;
		if(!(command_ & 0x40)) goto begin_type_2;
		goto begin_type_3;

	/*
		Type 1 entry point.
	*/
	begin_type_1:
		// Set initial flags, skip spin-up if possible.
		status_ &= ~(Flag::DataRequest | Flag::DataRequest | Flag::SeekError);
		set_interrupt_request(false);
		if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type1_type;

		// Perform spin up.
		status_ |= Flag::MotorOn;
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		status_ |= Flag::SpinUp;

	test_type1_type:
		// Set step direction if this is a step in or out.
		if((command_ >> 5) == 2) step_direction_ = 1;
		if((command_ >> 5) == 3) step_direction_ = 0;
		if((command_ >> 5) != 0) goto perform_step_command;

		// This is now definitely either a seek or a restore; if it's a restore then set track to 0xff and data to 0x00.
		if(!(command_ & 0x10))
		{
			track_ = 0xff;
			data_ = 0;
		}

	perform_seek_or_restore_command:
		if(track_ == data_) goto verify;
		step_direction_ = (data_ > track_);

	adjust_track:
		if(step_direction_) track_++; else track_--;

	perform_step:
		if(!step_direction_ && get_is_track_zero())
		{
			track_ = 0;
			goto verify;
		}
		step(step_direction_ ? 1 : -1);
		int time_to_wait;
		switch(command_ & 3)
		{
			default:
			case 0: time_to_wait = 6;	break;	// 2 on a 1772
			case 1: time_to_wait = 12;	break;	// 3 on a 1772
			case 2: time_to_wait = 20;	break;	// 5 on a 1772
			case 3: time_to_wait = 30;	break;	// 6 on a 1772
		}
		WAIT_FOR_TIME(time_to_wait);
		if(command_ >> 5) goto verify;
		goto perform_seek_or_restore_command;

	perform_step_command:
		if(command_ & 0x10) goto adjust_track;
		goto perform_step;

	verify:
		if(!(command_ & 0x04))
		{
			set_interrupt_request(true);
			goto wait_for_command;
		}

		printf("!!!TODO: verify a type 1!!!\n");

	/*
		Type 2 entry point.
	*/
	begin_type_2:
		status_ &= ~(Flag::DataRequest | Flag::LostData | Flag::RecordNotFound | Flag::WriteProtect | Flag::RecordType);
		set_interrupt_request(false);
		distance_into_section_ = 0;
		if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type2_delay;

		// Perform spin up.
		status_ |= Flag::MotorOn;
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);

	test_type2_delay:
		index_hole_count_ = 0;
		if(!(command_ & 0x04)) goto test_type2_write_protection;
		WAIT_FOR_TIME(30);

	test_type2_write_protection:
		if(command_&0x20) // TODO:: && is_write_protected
		{
			set_interrupt_request(true);
			status_ |= Flag::WriteProtect;
			goto wait_for_command;
		}

	type2_get_header:
		WAIT_FOR_EVENT(Event::IndexHole | Event::Token);
		if(new_event_type == Event::Token)
		{
			if(!distance_into_section_ && latest_token_.type == Token::ID) distance_into_section_++;
			else if(distance_into_section_ && latest_token_.type == Token::Byte)
			{
				header[distance_into_section_ - 1] = latest_token_.byte_value;
				distance_into_section_++;
				if(distance_into_section_ == 6)
				{
					if(header[0] == track_ && header[2] == sector_)
					{
						// TODO: test CRC
						goto type2_read_or_write_data;
					}
					else
					{
						distance_into_section_ = 0;
					}
				}
			}
		}
		else if(index_hole_count_ == 5)
		{
			set_interrupt_request(true);
			status_ |= Flag::RecordNotFound;
			goto wait_for_command;
		}
		goto type2_get_header;

	type2_read_or_write_data:
		if(command_&0x20) goto type2_write_data;
		goto type2_read_data;

	type2_read_data:
		WAIT_FOR_EVENT(Event::Token);
		// TODO: timeout
		if(latest_token_.type == Token::Data || latest_token_.type == Token::DeletedData)
		{
			status_ |= (latest_token_.type == Token::DeletedData) ? Flag::RecordType : 0;
			distance_into_section_ = 0;
			goto type2_read_byte;
		}
		goto type2_read_data;

	type2_read_byte:
		WAIT_FOR_EVENT(Event::Token);
		if(latest_token_.type != Token::Byte) goto type2_read_byte;
		if(status_ & Flag::DataRequest) status_ |= Flag::LostData;
		data_ = latest_token_.byte_value;
		status_ |= Flag::DataRequest;
		distance_into_section_++;
		if(distance_into_section_ == 128 << header[3])
		{
			distance_into_section_ = 0;
			goto type2_check_crc;
		}
		goto type2_read_byte;

	type2_check_crc:
		WAIT_FOR_EVENT(Event::Token);
		if(latest_token_.type != Token::Byte) goto type2_read_byte;
		header[distance_into_section_] = latest_token_.byte_value;
		distance_into_section_++;
		if(distance_into_section_ == 2)
		{
			// TODO: check CRC
			if(command_ & 0x10)
			{
				sector_++;
				goto test_type2_write_protection;
			}
			set_interrupt_request(true);
			goto wait_for_command;
		}
		goto type2_check_crc;

	type2_write_data:
		printf("!!!TODO: data portion of sector!!!\n");

	begin_type_3:
		printf("!!!TODO: type 3 commands!!!\n");

	END_SECTION()
}
<commit_msg>Sought to implement the verify step of type 1 commands.<commit_after>//
//  1770.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 17/09/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "1770.hpp"
#include "../../Storage/Disk/Encodings/MFM.hpp"

using namespace WD;

WD1770::WD1770() :
	Storage::Disk::Drive(8000000, 1, 300),
	status_(0),
	interesting_event_mask_(Event::Command),
	resume_point_(0),
	delay_time_(0)
{
	set_is_double_density(false);
	posit_event(Event::Command);
}

void WD1770::set_is_double_density(bool is_double_density)
{
	is_double_density_ = is_double_density;
	Storage::Time bit_length;
	bit_length.length = 1;
	bit_length.clock_rate = is_double_density ? 500000 : 250000;
	set_expected_bit_length(bit_length);
}

void WD1770::set_register(int address, uint8_t value)
{
	switch(address&3)
	{
		case 0:
			command_ = value;
			posit_event(Event::Command);
			// TODO: is this force interrupt?
		break;
		case 1:		track_ = value;		break;
		case 2:		sector_ = value;	break;
		case 3:		data_ = value;		break;
	}
}

uint8_t WD1770::get_register(int address)
{
	switch(address&3)
	{
		default:	return status_;
		case 1:		return track_;
		case 2:		return sector_;
		case 3:		status_ &= ~Flag::DataRequest; return data_;
	}
}

void WD1770::run_for_cycles(unsigned int number_of_cycles)
{
	if(status_ & Flag::MotorOn) Storage::Disk::Drive::run_for_cycles((int)number_of_cycles);

	if(delay_time_)
	{
		if(delay_time_ <= number_of_cycles)
		{
			delay_time_ = 0;
			posit_event(Event::Timer);
		}
		else
		{
			delay_time_ -= number_of_cycles;
		}
	}
}

void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole)
{
	shift_register_ = (shift_register_ << 1) | value;
	bits_since_token_++;

	Token::Type token_type = Token::Byte;
	if(!is_double_density_)
	{
		switch(shift_register_ & 0xffff)
		{
			case Storage::Encodings::MFM::FMIndexAddressMark:
				token_type = Token::Index;
			break;
			case Storage::Encodings::MFM::FMIDAddressMark:
				token_type = Token::ID;
			break;
			case Storage::Encodings::MFM::FMDataAddressMark:
				token_type = Token::Data;
			break;
			case Storage::Encodings::MFM::FMDeletedDataAddressMark:
				token_type = Token::DeletedData;
			break;
			default:
			break;
		}
	}
	else
	{
		// TODO: MFM
	}

	if(token_type != Token::Byte)
	{
		latest_token_.type = token_type;
		bits_since_token_ = 0;
		posit_event(Event::Token);
		return;
	}

	if(bits_since_token_ == 16)
	{
		latest_token_.type = Token::Byte;
		latest_token_.byte_value = (uint8_t)(
			((shift_register_ & 0x0001) >> 0) |
			((shift_register_ & 0x0004) >> 1) |
			((shift_register_ & 0x0010) >> 2) |
			((shift_register_ & 0x0040) >> 3) |
			((shift_register_ & 0x0100) >> 4) |
			((shift_register_ & 0x0400) >> 5) |
			((shift_register_ & 0x1000) >> 6) |
			((shift_register_ & 0x4000) >> 7));
		bits_since_token_ = 0;
		posit_event(Event::Token);
		return;
	}
}

void WD1770::process_index_hole()
{
	index_hole_count_++;
	posit_event(Event::IndexHole);

	// motor power-down
//	if(index_hole_count_ == 9 && !(status_&Flag::Busy)) status_ &= ~Flag::MotorOn;
}

//     +------+----------+-------------------------+
//     !	    !	       !	   BITS 	 !
//     ! TYPE ! COMMAND  !  7  6	5  4  3  2  1  0 !
//     +------+----------+-------------------------+
//     !	 1  ! Restore  !  0  0	0  0  h  v r1 r0 !
//     !	 1  ! Seek     !  0  0	0  1  h  v r1 r0 !
//     !	 1  ! Step     !  0  0	1  u  h  v r1 r0 !
//     !	 1  ! Step-in  !  0  1	0  u  h  v r1 r0 !
//     !	 1  ! Step-out !  0  1	1  u  h  v r1 r0 !
//     !	 2  ! Rd sectr !  1  0	0  m  h  E  0  0 !
//     !	 2  ! Wt sectr !  1  0	1  m  h  E  P a0 !
//     !	 3  ! Rd addr  !  1  1	0  0  h  E  0  0 !
//     !	 3  ! Rd track !  1  1	1  0  h  E  0  0 !
//     !	 3  ! Wt track !  1  1	1  1  h  E  P  0 !
//     !	 4  ! Forc int !  1  1	0  1 i3 i2 i1 i0 !
//     +------+----------+-------------------------+

#define WAIT_FOR_EVENT(mask)	resume_point_ = __LINE__; interesting_event_mask_ = mask; return; case __LINE__:
#define WAIT_FOR_TIME(ms)		resume_point_ = __LINE__; interesting_event_mask_ = Event::Timer; delay_time_ = ms * 8000; if(delay_time_) return; case __LINE__:
#define BEGIN_SECTION()	switch(resume_point_) { default:
#define END_SECTION()	0; }

#define READ_ID()	\
		if(new_event_type == Event::Token)	\
		{	\
			if(!distance_into_section_ && latest_token_.type == Token::ID) distance_into_section_++;	\
			else if(distance_into_section_ && distance_into_section_ < 7 && latest_token_.type == Token::Byte)	\
			{	\
				header[distance_into_section_ - 1] = latest_token_.byte_value;	\
				distance_into_section_++;	\
			}	\
		}

void WD1770::posit_event(Event new_event_type)
{
	if(!(interesting_event_mask_ & (int)new_event_type)) return;
	interesting_event_mask_ &= ~new_event_type;

	BEGIN_SECTION()

	// Wait for a new command, branch to the appropriate handler.
	wait_for_command:
		printf("Idle...\n");
		status_ &= ~Flag::Busy;
		index_hole_count_ = 0;
		WAIT_FOR_EVENT(Event::Command);
		printf("Starting %02x\n", command_);
		status_ |= Flag::Busy;
		if(!(command_ & 0x80)) goto begin_type_1;
		if(!(command_ & 0x40)) goto begin_type_2;
		goto begin_type_3;

	/*
		Type 1 entry point.
	*/
	begin_type_1:
		// Set initial flags, skip spin-up if possible.
		status_ &= ~(Flag::DataRequest | Flag::DataRequest | Flag::SeekError);
		set_interrupt_request(false);
		if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type1_type;

		// Perform spin up.
		status_ |= Flag::MotorOn;
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		status_ |= Flag::SpinUp;

	test_type1_type:
		// Set step direction if this is a step in or out.
		if((command_ >> 5) == 2) step_direction_ = 1;
		if((command_ >> 5) == 3) step_direction_ = 0;
		if((command_ >> 5) != 0) goto perform_step_command;

		// This is now definitely either a seek or a restore; if it's a restore then set track to 0xff and data to 0x00.
		if(!(command_ & 0x10))
		{
			track_ = 0xff;
			data_ = 0;
		}

	perform_seek_or_restore_command:
		if(track_ == data_) goto verify;
		step_direction_ = (data_ > track_);

	adjust_track:
		if(step_direction_) track_++; else track_--;

	perform_step:
		if(!step_direction_ && get_is_track_zero())
		{
			track_ = 0;
			goto verify;
		}
		step(step_direction_ ? 1 : -1);
		int time_to_wait;
		switch(command_ & 3)
		{
			default:
			case 0: time_to_wait = 6;	break;	// 2 on a 1772
			case 1: time_to_wait = 12;	break;	// 3 on a 1772
			case 2: time_to_wait = 20;	break;	// 5 on a 1772
			case 3: time_to_wait = 30;	break;	// 6 on a 1772
		}
		WAIT_FOR_TIME(time_to_wait);
		if(command_ >> 5) goto verify;
		goto perform_seek_or_restore_command;

	perform_step_command:
		if(command_ & 0x10) goto adjust_track;
		goto perform_step;

	verify:
		if(!(command_ & 0x04))
		{
			set_interrupt_request(true);
			goto wait_for_command;
		}

		index_hole_count_ = 0;

	verify_read_data:
		WAIT_FOR_EVENT(Event::IndexHole | Event::Token);
		READ_ID();

		if(index_hole_count_ == 6)
		{
			set_interrupt_request(true);
			status_ |= Flag::SeekError;
			goto wait_for_command;
		}
		if(distance_into_section_ == 7)
		{
			// TODO: CRC check
			if(header[0] == track_)
			{
				status_ &= ~Flag::CRCError;
				set_interrupt_request(true);
				goto wait_for_command;
			}

			distance_into_section_ = 0;
		}
		goto verify_read_data;

	/*
		Type 2 entry point.
	*/
	begin_type_2:
		status_ &= ~(Flag::DataRequest | Flag::LostData | Flag::RecordNotFound | Flag::WriteProtect | Flag::RecordType);
		set_interrupt_request(false);
		distance_into_section_ = 0;
		if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type2_delay;

		// Perform spin up.
		status_ |= Flag::MotorOn;
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);
		WAIT_FOR_EVENT(Event::IndexHole);

	test_type2_delay:
		index_hole_count_ = 0;
		if(!(command_ & 0x04)) goto test_type2_write_protection;
		WAIT_FOR_TIME(30);

	test_type2_write_protection:
		if(command_&0x20) // TODO:: && is_write_protected
		{
			set_interrupt_request(true);
			status_ |= Flag::WriteProtect;
			goto wait_for_command;
		}

	type2_get_header:
		WAIT_FOR_EVENT(Event::IndexHole | Event::Token);
		READ_ID();

		if(index_hole_count_ == 5)
		{
			set_interrupt_request(true);
			status_ |= Flag::RecordNotFound;
			goto wait_for_command;
		}
		if(distance_into_section_ == 7)
		{
			if(header[0] == track_ && header[2] == sector_)
			{
				// TODO: test CRC
				goto type2_read_or_write_data;
			}
			distance_into_section_ = 0;
		}
		goto type2_get_header;

	type2_read_or_write_data:
		if(command_&0x20) goto type2_write_data;
		goto type2_read_data;

	type2_read_data:
		WAIT_FOR_EVENT(Event::Token);
		// TODO: timeout
		if(latest_token_.type == Token::Data || latest_token_.type == Token::DeletedData)
		{
			status_ |= (latest_token_.type == Token::DeletedData) ? Flag::RecordType : 0;
			distance_into_section_ = 0;
			goto type2_read_byte;
		}
		goto type2_read_data;

	type2_read_byte:
		WAIT_FOR_EVENT(Event::Token);
		if(latest_token_.type != Token::Byte) goto type2_read_byte;
		if(status_ & Flag::DataRequest) status_ |= Flag::LostData;
		data_ = latest_token_.byte_value;
		status_ |= Flag::DataRequest;
		distance_into_section_++;
		if(distance_into_section_ == 128 << header[3])
		{
			distance_into_section_ = 0;
			goto type2_check_crc;
		}
		goto type2_read_byte;

	type2_check_crc:
		WAIT_FOR_EVENT(Event::Token);
		if(latest_token_.type != Token::Byte) goto type2_read_byte;
		header[distance_into_section_] = latest_token_.byte_value;
		distance_into_section_++;
		if(distance_into_section_ == 2)
		{
			// TODO: check CRC
			if(command_ & 0x10)
			{
				sector_++;
				goto test_type2_write_protection;
			}
			set_interrupt_request(true);
			goto wait_for_command;
		}
		goto type2_check_crc;

	type2_write_data:
		printf("!!!TODO: data portion of sector!!!\n");

	begin_type_3:
		printf("!!!TODO: type 3 commands!!!\n");

	END_SECTION()
}
<|endoftext|>


<commit_before>/**
 * Process control - running other tasks and manipulating their input/output
 */

#include <v8.h>
#include <string>
#include "macros.h"
#include "common.h"
#include <stdlib.h>
#include <paths.h>  // for _PATH_BSHELL

namespace {

JS_METHOD(_process) {
	ASSERT_CONSTRUCTOR;
	SAVE_PTR(0, NULL);
	return args.This();
}

JS_METHOD(_system) {
	if (args.Length() != 1) {
		return JS_EXCEPTION("Wrong argument count. Use new Process().system(\"command\")");
	}

	v8::String::Utf8Value cmd(args[0]);
	int result = system(*cmd);
	return JS_INT(result);
}

/**
 * The initial .exec method for stream buffering system commands
 */
JS_METHOD(_exec) {
	if (args.Length() != 1) {
		return JS_EXCEPTION("Wrong argument count. Use new Process().exec(\"command\")");
	}

	std::string data;
	FILE *stream;
	const int MAX_BUFFER = 256;
	char buffer[MAX_BUFFER];

	v8::String::Utf8Value cmd(args[0]);
	stream = popen(*cmd, "r");
	while ( fgets(buffer, MAX_BUFFER, stream) != NULL ) {
		data.append(buffer);
	}
	pclose(stream);

	if(data.c_str() != NULL) {
		return JS_STR(data.c_str());
	} else {
		return JS_NULL;
	}
}

/**
 * Execute the given command, and return exit code and stdout/stderr data
 *
 * TODO: any reason to keep exec?  Either remove exec and rename exec2 to exec,
 * or rename exec2 to something else.
 *
 * @param command    {String}  bash command
 * @param input      {String}  optional; text to send to process as stdin
 *
 * @return a JavaScript object like: {
 *   status: {Integer} the return code from the process
 *   out:    {String}  contents of stdout
 *   err:    {String}  contents of stderr
 * }
 */
JS_METHOD(_exec2) {
	int arg_count = args.Length();
	if (arg_count < 1 || arg_count > 2) {
		return JS_EXCEPTION("Wrong argument count. Use new Process().exec2(\"command\", [\"standard input\"])");
}

	const int MAX_BUFFER = 256;
	char buffer[MAX_BUFFER + 1];

	v8::String::Utf8Value command_arg(args[0]);

	// File descriptors all named from perspective of child process.
	int input_fd[2];
	int out_fd[2];
	int err_fd[2];

	pipe(input_fd); // Where the parent is going to write to
	pipe(out_fd); // From where parent is going to read
	pipe(err_fd);

	int pid = fork();
	switch (pid) {

	case -1:  // Error case.
		return JS_EXCEPTION("Failed to fork process");

	case 0:  // Child process.

		close(STDOUT_FILENO);
		close(STDERR_FILENO);
		close(STDIN_FILENO);

		dup2(input_fd[0], STDIN_FILENO);
		dup2(out_fd[1], STDOUT_FILENO);
		dup2(err_fd[1], STDERR_FILENO);

		close(input_fd[0]); // Not required for the child
		close(input_fd[1]);
		close(out_fd[0]);
		close(out_fd[1]);
		close(err_fd[0]);
		close(err_fd[1]);

		execl(_PATH_BSHELL, "sh", "-c", *command_arg, NULL);
#if defined(__CYGWIN__) || defined(__MSYS__)
                // On cygwin or msys, we may not have /bin/sh.  In that case,
                // try to find sh on PATH.
		execlp("sh", "sh", "-c", *command_arg, NULL);
#endif
		exit(127);  // "command not found"
		return JS_NULL;  // unreachable

	default:  // Parent process.

		close(input_fd[0]); // These are being used by the child
		close(out_fd[1]);
		close(err_fd[1]);

		if (arg_count >= 2) {
			v8::String::Utf8Value input_arg(args[1]);
			write(input_fd[1], *input_arg, input_arg.length()); // Write to child’s stdin
		}
		close(input_fd[1]);

		std::string ret_out;
		while (true) {
			int bytes_read = read(out_fd[0], buffer, MAX_BUFFER);
			if (bytes_read == 0) {
				break;
			} else if (bytes_read < 0) {
				return JS_NULL;  // TODO: throw JavaScript exception
			}
			buffer[bytes_read] = 0;
			ret_out.append(buffer);
		}
		close(out_fd[0]);

		std::string ret_err;
		while (true) {
			int bytes_read = read(err_fd[0], buffer, MAX_BUFFER);
			if (bytes_read == 0) {
				break;
			} else if (bytes_read < 0) {
				return JS_NULL;  // TODO: throw JavaScript exception
			}
			buffer[bytes_read] = 0;
			ret_err.append(buffer);
		}
		close(err_fd[0]);

		int status;
		waitpid(pid, &status, 0);

		v8::Handle<v8::Object> ret = v8::Object::New();
		ret->Set(JS_STR("status"), JS_INT(status));
		ret->Set(JS_STR("out"), JS_STR(ret_out.c_str()));
		ret->Set(JS_STR("err"), JS_STR(ret_err.c_str()));
		return ret;
	}
}

/**
 * Execute the given command as a background process.
 *
 * @param command    {String}  bash command
 * @param input      {String}  optional; text to send to process as stdin
 * @return undefined
 */
JS_METHOD(_fork) {
	int arg_count = args.Length();
	if (arg_count < 1 || arg_count > 2) {
		return JS_EXCEPTION("Wrong argument count. Use new Process().exec2(\"command\", [\"standard input\"])");
	}

	v8::String::Utf8Value command_arg(args[0]);

	int input_fd[2];
	pipe(input_fd); // Where the parent is going to write to

	int pid = fork();
	switch (pid) {

	case -1:  // Error case.
		return JS_EXCEPTION("Failed to fork process");

	case 0:  // Child process.

		close(STDIN_FILENO);
		dup2(input_fd[0], STDIN_FILENO);
		close(input_fd[0]); // Not required for the child
		close(input_fd[1]);

		execl(_PATH_BSHELL, "sh", "-c", *command_arg, NULL);
#if defined(__CYGWIN__) || defined(__MSYS__)
                // On cygwin or msys, we may not have /bin/sh.  In that case,
                // try to find sh on PATH.
		execlp("sh", "sh", "-c", *command_arg, NULL);
#endif
		exit(127);  // "command not found"
		return JS_NULL;  // unreachable

	default:  // Parent process.

		close(input_fd[0]); // These are being used by the child
		if (arg_count >= 2) {
			v8::String::Utf8Value input_arg(args[1]);
			write(input_fd[1], *input_arg, input_arg.length()); // Write to child’s stdin
		}
		close(input_fd[1]);
		return JS_UNDEFINED;
	}
}

}

SHARED_INIT() {
	v8::HandleScope handle_scope;
	v8::Handle<v8::FunctionTemplate> funct = v8::FunctionTemplate::New(_process);
	funct->SetClassName(JS_STR("Process"));
	v8::Handle<v8::ObjectTemplate> ot = funct->InstanceTemplate();
	ot->SetInternalFieldCount(1);
	v8::Handle<v8::ObjectTemplate> process = funct->PrototypeTemplate();

	/* this module provides a set of (static) functions */
	process->Set(JS_STR("system"), v8::FunctionTemplate::New(_system)->GetFunction());
	process->Set(JS_STR("exec"), v8::FunctionTemplate::New(_exec)->GetFunction());
	process->Set(JS_STR("exec2"), v8::FunctionTemplate::New(_exec2)->GetFunction());
	process->Set(JS_STR("fork"), v8::FunctionTemplate::New(_fork)->GetFunction());

	exports->Set(JS_STR("Process"), funct->GetFunction());
}
<commit_msg>include sys/wait.h in process module<commit_after>/**
 * Process control - running other tasks and manipulating their input/output
 */

#include <v8.h>
#include <string>
#include "macros.h"
#include "common.h"
#include <stdlib.h>
#include <sys/wait.h>
#include <paths.h>  // for _PATH_BSHELL

namespace {

JS_METHOD(_process) {
	ASSERT_CONSTRUCTOR;
	SAVE_PTR(0, NULL);
	return args.This();
}

JS_METHOD(_system) {
	if (args.Length() != 1) {
		return JS_EXCEPTION("Wrong argument count. Use new Process().system(\"command\")");
	}

	v8::String::Utf8Value cmd(args[0]);
	int result = system(*cmd);
	return JS_INT(result);
}

/**
 * The initial .exec method for stream buffering system commands
 */
JS_METHOD(_exec) {
	if (args.Length() != 1) {
		return JS_EXCEPTION("Wrong argument count. Use new Process().exec(\"command\")");
	}

	std::string data;
	FILE *stream;
	const int MAX_BUFFER = 256;
	char buffer[MAX_BUFFER];

	v8::String::Utf8Value cmd(args[0]);
	stream = popen(*cmd, "r");
	while ( fgets(buffer, MAX_BUFFER, stream) != NULL ) {
		data.append(buffer);
	}
	pclose(stream);

	if(data.c_str() != NULL) {
		return JS_STR(data.c_str());
	} else {
		return JS_NULL;
	}
}

/**
 * Execute the given command, and return exit code and stdout/stderr data
 *
 * TODO: any reason to keep exec?  Either remove exec and rename exec2 to exec,
 * or rename exec2 to something else.
 *
 * @param command    {String}  bash command
 * @param input      {String}  optional; text to send to process as stdin
 *
 * @return a JavaScript object like: {
 *   status: {Integer} the return code from the process
 *   out:    {String}  contents of stdout
 *   err:    {String}  contents of stderr
 * }
 */
JS_METHOD(_exec2) {
	int arg_count = args.Length();
	if (arg_count < 1 || arg_count > 2) {
		return JS_EXCEPTION("Wrong argument count. Use new Process().exec2(\"command\", [\"standard input\"])");
}

	const int MAX_BUFFER = 256;
	char buffer[MAX_BUFFER + 1];

	v8::String::Utf8Value command_arg(args[0]);

	// File descriptors all named from perspective of child process.
	int input_fd[2];
	int out_fd[2];
	int err_fd[2];

	pipe(input_fd); // Where the parent is going to write to
	pipe(out_fd); // From where parent is going to read
	pipe(err_fd);

	int pid = fork();
	switch (pid) {

	case -1:  // Error case.
		return JS_EXCEPTION("Failed to fork process");

	case 0:  // Child process.

		close(STDOUT_FILENO);
		close(STDERR_FILENO);
		close(STDIN_FILENO);

		dup2(input_fd[0], STDIN_FILENO);
		dup2(out_fd[1], STDOUT_FILENO);
		dup2(err_fd[1], STDERR_FILENO);

		close(input_fd[0]); // Not required for the child
		close(input_fd[1]);
		close(out_fd[0]);
		close(out_fd[1]);
		close(err_fd[0]);
		close(err_fd[1]);

		execl(_PATH_BSHELL, "sh", "-c", *command_arg, NULL);
#if defined(__CYGWIN__) || defined(__MSYS__)
                // On cygwin or msys, we may not have /bin/sh.  In that case,
                // try to find sh on PATH.
		execlp("sh", "sh", "-c", *command_arg, NULL);
#endif
		exit(127);  // "command not found"
		return JS_NULL;  // unreachable

	default:  // Parent process.

		close(input_fd[0]); // These are being used by the child
		close(out_fd[1]);
		close(err_fd[1]);

		if (arg_count >= 2) {
			v8::String::Utf8Value input_arg(args[1]);
			write(input_fd[1], *input_arg, input_arg.length()); // Write to child’s stdin
		}
		close(input_fd[1]);

		std::string ret_out;
		while (true) {
			int bytes_read = read(out_fd[0], buffer, MAX_BUFFER);
			if (bytes_read == 0) {
				break;
			} else if (bytes_read < 0) {
				return JS_NULL;  // TODO: throw JavaScript exception
			}
			buffer[bytes_read] = 0;
			ret_out.append(buffer);
		}
		close(out_fd[0]);

		std::string ret_err;
		while (true) {
			int bytes_read = read(err_fd[0], buffer, MAX_BUFFER);
			if (bytes_read == 0) {
				break;
			} else if (bytes_read < 0) {
				return JS_NULL;  // TODO: throw JavaScript exception
			}
			buffer[bytes_read] = 0;
			ret_err.append(buffer);
		}
		close(err_fd[0]);

		int status;
		waitpid(pid, &status, 0);

		v8::Handle<v8::Object> ret = v8::Object::New();
		ret->Set(JS_STR("status"), JS_INT(status));
		ret->Set(JS_STR("out"), JS_STR(ret_out.c_str()));
		ret->Set(JS_STR("err"), JS_STR(ret_err.c_str()));
		return ret;
	}
}

/**
 * Execute the given command as a background process.
 *
 * @param command    {String}  bash command
 * @param input      {String}  optional; text to send to process as stdin
 * @return undefined
 */
JS_METHOD(_fork) {
	int arg_count = args.Length();
	if (arg_count < 1 || arg_count > 2) {
		return JS_EXCEPTION("Wrong argument count. Use new Process().exec2(\"command\", [\"standard input\"])");
	}

	v8::String::Utf8Value command_arg(args[0]);

	int input_fd[2];
	pipe(input_fd); // Where the parent is going to write to

	int pid = fork();
	switch (pid) {

	case -1:  // Error case.
		return JS_EXCEPTION("Failed to fork process");

	case 0:  // Child process.

		close(STDIN_FILENO);
		dup2(input_fd[0], STDIN_FILENO);
		close(input_fd[0]); // Not required for the child
		close(input_fd[1]);

		execl(_PATH_BSHELL, "sh", "-c", *command_arg, NULL);
#if defined(__CYGWIN__) || defined(__MSYS__)
                // On cygwin or msys, we may not have /bin/sh.  In that case,
                // try to find sh on PATH.
		execlp("sh", "sh", "-c", *command_arg, NULL);
#endif
		exit(127);  // "command not found"
		return JS_NULL;  // unreachable

	default:  // Parent process.

		close(input_fd[0]); // These are being used by the child
		if (arg_count >= 2) {
			v8::String::Utf8Value input_arg(args[1]);
			write(input_fd[1], *input_arg, input_arg.length()); // Write to child’s stdin
		}
		close(input_fd[1]);
		return JS_UNDEFINED;
	}
}

}

SHARED_INIT() {
	v8::HandleScope handle_scope;
	v8::Handle<v8::FunctionTemplate> funct = v8::FunctionTemplate::New(_process);
	funct->SetClassName(JS_STR("Process"));
	v8::Handle<v8::ObjectTemplate> ot = funct->InstanceTemplate();
	ot->SetInternalFieldCount(1);
	v8::Handle<v8::ObjectTemplate> process = funct->PrototypeTemplate();

	/* this module provides a set of (static) functions */
	process->Set(JS_STR("system"), v8::FunctionTemplate::New(_system)->GetFunction());
	process->Set(JS_STR("exec"), v8::FunctionTemplate::New(_exec)->GetFunction());
	process->Set(JS_STR("exec2"), v8::FunctionTemplate::New(_exec2)->GetFunction());
	process->Set(JS_STR("fork"), v8::FunctionTemplate::New(_fork)->GetFunction());

	exports->Set(JS_STR("Process"), funct->GetFunction());
}
<|endoftext|>


<commit_before>//
//  6850.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 10/10/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#include "6850.hpp"

#include <cassert>

using namespace Motorola::ACIA;

const HalfCycles ACIA::SameAsTransmit;

ACIA::ACIA(HalfCycles transmit_clock_rate, HalfCycles receive_clock_rate) :
	transmit_clock_rate_(transmit_clock_rate),
	receive_clock_rate_((receive_clock_rate != SameAsTransmit) ? receive_clock_rate : transmit_clock_rate) {
	transmit.set_writer_clock_rate(transmit_clock_rate);
	request_to_send.set_writer_clock_rate(transmit_clock_rate);
}

uint8_t ACIA::read(int address) {
	if(address&1) {
		overran_ = false;
		received_data_ |= NoValueMask;
		update_interrupt_line();
		return uint8_t(received_data_);
	} else {
		return get_status();
	}
}

void ACIA::reset() {
	transmit.reset_writing();
	transmit.write(true);
	request_to_send.reset_writing();

	bits_received_ = bits_incoming_ = 0;
	receive_interrupt_enabled_ = transmit_interrupt_enabled_ = false;
	overran_ = false;
	next_transmission_ = received_data_ = NoValueMask;

	update_interrupt_line();
	assert(!interrupt_line_);
}

void ACIA::write(int address, uint8_t value) {
	if(address&1) {
		next_transmission_ = value;
		consider_transmission();
		update_interrupt_line();
	} else {
		if((value&3) == 3) {
			reset();
		} else {
			switch(value & 3) {
				default:
				case 0: divider_ = 1;	break;
				case 1: divider_ = 16;	break;
				case 2: divider_ = 64;	break;
			}
			switch((value >> 2) & 7) {
				default:
				case 0:	data_bits_ = 7; stop_bits_ = 2; parity_ = Parity::Even;	break;
				case 1:	data_bits_ = 7; stop_bits_ = 2; parity_ = Parity::Odd;	break;
				case 2:	data_bits_ = 7; stop_bits_ = 1; parity_ = Parity::Even;	break;
				case 3:	data_bits_ = 7; stop_bits_ = 1; parity_ = Parity::Odd;	break;
				case 4:	data_bits_ = 8; stop_bits_ = 2; parity_ = Parity::None;	break;
				case 5:	data_bits_ = 8; stop_bits_ = 1; parity_ = Parity::None;	break;
				case 6:	data_bits_ = 8; stop_bits_ = 1; parity_ = Parity::Even;	break;
				case 7:	data_bits_ = 8; stop_bits_ = 1; parity_ = Parity::Odd;	break;
			}
			switch((value >> 5) & 3) {
				case 0:	request_to_send.write(false); transmit_interrupt_enabled_ = false;	break;
				case 1:	request_to_send.write(false); transmit_interrupt_enabled_ = true;	break;
				case 2:	request_to_send.write(true); transmit_interrupt_enabled_ = false;	break;
				case 3:
					request_to_send.write(false);
					transmit_interrupt_enabled_ = false;
					transmit.reset_writing();
					transmit.write(false);
				break;
			}
			receive.set_read_delegate(this, Storage::Time(divider_ * 2, int(receive_clock_rate_.as_integral())));
			receive_interrupt_enabled_ = value & 0x80;

			update_interrupt_line();
		}
	}
	update_clocking_observer();
}

void ACIA::consider_transmission() {
	if(next_transmission_ != NoValueMask && !transmit.write_data_time_remaining()) {
		// Establish start bit and [7 or 8] data bits.
		if(data_bits_ == 7) next_transmission_ &= 0x7f;
		int transmission = next_transmission_ << 1;

		// Add a parity bit, if any.
		int mask = 0x2 << data_bits_;
		if(parity_ != Parity::None) {
			transmission |= parity(uint8_t(next_transmission_)) ? mask : 0;
			mask <<= 1;
		}

		// Add stop bits.
		for(int c = 0; c < stop_bits_; ++c) {
			transmission |= mask;
			mask <<= 1;
		}

		// Output all that.
		const int total_bits = expected_bits();
		transmit.write(divider_ * 2, total_bits, transmission);

		// Mark the transmit register as empty again.
		next_transmission_ = NoValueMask;
	}
}

ClockingHint::Preference ACIA::preferred_clocking() const {
	// Real-time clocking is required if a transmission is ongoing; this is a courtesy for whomever
	// is on the receiving end.
	if(transmit.transmission_data_time_remaining() > 0) return ClockingHint::Preference::RealTime;

	// If a bit reception is ongoing that might lead to an interrupt, ask for real-time clocking
	// because it's unclear when the interrupt might come.
	if(bits_incoming_ && receive_interrupt_enabled_) return ClockingHint::Preference::RealTime;

	// No clocking required then.
	return ClockingHint::Preference::None;
}

bool ACIA::get_interrupt_line() const {
	return interrupt_line_;
}

int ACIA::expected_bits() {
	return 1 + data_bits_ + stop_bits_ + (parity_ != Parity::None);
}

uint8_t ACIA::parity(uint8_t value) {
	value ^= value >> 4;
	value ^= value >> 2;
	value ^= value >> 1;
	return value ^ (parity_ == Parity::Even);
}

bool ACIA::serial_line_did_produce_bit(Serial::Line *, int bit) {
	// Shift this bit into the 11-bit input register; this is big enough to hold
	// the largest transmission symbol.
	++bits_received_;
	bits_incoming_ = (bits_incoming_ >> 1) | (bit << 10);

	// If that's the now-expected number of bits, update.
	const int bit_target = expected_bits();
	if(bits_received_ >= bit_target) {
		bits_received_ = 0;
		overran_ |= get_status() & 1;
		received_data_ = uint8_t(bits_incoming_ >> (12 - bit_target));
		update_interrupt_line();
		update_clocking_observer();
		return false;
	}

	// TODO: overrun, and parity.

	// Keep receiving, and consider a potential clocking change.
	if(bits_received_ == 1) update_clocking_observer();
	return true;
}

void ACIA::set_interrupt_delegate(InterruptDelegate *delegate) {
	interrupt_delegate_ = delegate;
}

void ACIA::update_interrupt_line() {
	const bool old_line = interrupt_line_;

	/*
		"Bit 7 of the control register is the rie bit. When the rie bit is high, the rdrf, ndcd,
		and ovr bits will assert the nirq output. When the rie bit is low, nirq generation is disabled."

		rie = read interrupt enable
		rdrf = receive data register full (status word bit 0)
		ndcd = data carrier detect (status word bit 2)
		over = receiver overrun (status word bit 5)

		"Bit 1 of the status register is the tdre bit. When high, the tdre bit indicates that data has been
		transferred from the transmitter data register to the output shift register. At this point, the a6850
		is ready to accept a new transmit data byte. However, if the ncts signal is high, the tdre bit remains
		low regardless of the status of the transmitter data register. Also, if transmit interrupt is enabled,
		the nirq output is asserted."

		tdre = transmitter data register empty
		ncts = clear to send
	*/
	const auto status = get_status();
	interrupt_line_ =
		(receive_interrupt_enabled_ && (status & 0x25)) ||
		(transmit_interrupt_enabled_ && (status & 0x02));

	if(interrupt_delegate_ && old_line != interrupt_line_) {
		interrupt_delegate_->acia6850_did_change_interrupt_status(this);
	}
}

uint8_t ACIA::get_status() {
	return
		((received_data_ & NoValueMask) ? 0x00 : 0x01) |
		((next_transmission_ == NoValueMask) ? 0x02 : 0x00) |
//		(data_carrier_detect.read() ? 0x04 : 0x00) |
//		(clear_to_send.read() ? 0x08 : 0x00) |
		(overran_ ? 0x20 : 0x00) |
		(interrupt_line_ ? 0x80 : 0x00)
	;

	// b0: receive data full.
	// b1: transmit data empty.
	// b2: DCD.
	// b3: CTS.
	// b4: framing error (i.e. no first stop bit where expected).
	// b5: receiver overran.
	// b6: parity error.
	// b7: IRQ state.
}
<commit_msg>Retain 6850 time tracking at all times.<commit_after>//
//  6850.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 10/10/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#include "6850.hpp"

#include <cassert>

using namespace Motorola::ACIA;

const HalfCycles ACIA::SameAsTransmit;

ACIA::ACIA(HalfCycles transmit_clock_rate, HalfCycles receive_clock_rate) :
	transmit_clock_rate_(transmit_clock_rate),
	receive_clock_rate_((receive_clock_rate != SameAsTransmit) ? receive_clock_rate : transmit_clock_rate) {
	transmit.set_writer_clock_rate(transmit_clock_rate);
	request_to_send.set_writer_clock_rate(transmit_clock_rate);
}

uint8_t ACIA::read(int address) {
	if(address&1) {
		overran_ = false;
		received_data_ |= NoValueMask;
		update_interrupt_line();
		return uint8_t(received_data_);
	} else {
		return get_status();
	}
}

void ACIA::reset() {
	transmit.reset_writing();
	transmit.write(true);
	request_to_send.reset_writing();

	bits_received_ = bits_incoming_ = 0;
	receive_interrupt_enabled_ = transmit_interrupt_enabled_ = false;
	overran_ = false;
	next_transmission_ = received_data_ = NoValueMask;

	update_interrupt_line();
	assert(!interrupt_line_);
}

void ACIA::write(int address, uint8_t value) {
	if(address&1) {
		next_transmission_ = value;
		consider_transmission();
		update_interrupt_line();
	} else {
		if((value&3) == 3) {
			reset();
		} else {
			switch(value & 3) {
				default:
				case 0: divider_ = 1;	break;
				case 1: divider_ = 16;	break;
				case 2: divider_ = 64;	break;
			}
			switch((value >> 2) & 7) {
				default:
				case 0:	data_bits_ = 7; stop_bits_ = 2; parity_ = Parity::Even;	break;
				case 1:	data_bits_ = 7; stop_bits_ = 2; parity_ = Parity::Odd;	break;
				case 2:	data_bits_ = 7; stop_bits_ = 1; parity_ = Parity::Even;	break;
				case 3:	data_bits_ = 7; stop_bits_ = 1; parity_ = Parity::Odd;	break;
				case 4:	data_bits_ = 8; stop_bits_ = 2; parity_ = Parity::None;	break;
				case 5:	data_bits_ = 8; stop_bits_ = 1; parity_ = Parity::None;	break;
				case 6:	data_bits_ = 8; stop_bits_ = 1; parity_ = Parity::Even;	break;
				case 7:	data_bits_ = 8; stop_bits_ = 1; parity_ = Parity::Odd;	break;
			}
			switch((value >> 5) & 3) {
				case 0:	request_to_send.write(false); transmit_interrupt_enabled_ = false;	break;
				case 1:	request_to_send.write(false); transmit_interrupt_enabled_ = true;	break;
				case 2:	request_to_send.write(true); transmit_interrupt_enabled_ = false;	break;
				case 3:
					request_to_send.write(false);
					transmit_interrupt_enabled_ = false;
					transmit.reset_writing();
					transmit.write(false);
				break;
			}
			receive.set_read_delegate(this, Storage::Time(divider_ * 2, int(receive_clock_rate_.as_integral())));
			receive_interrupt_enabled_ = value & 0x80;

			update_interrupt_line();
		}
	}
	update_clocking_observer();
}

void ACIA::consider_transmission() {
	if(next_transmission_ != NoValueMask && !transmit.write_data_time_remaining()) {
		// Establish start bit and [7 or 8] data bits.
		if(data_bits_ == 7) next_transmission_ &= 0x7f;
		int transmission = next_transmission_ << 1;

		// Add a parity bit, if any.
		int mask = 0x2 << data_bits_;
		if(parity_ != Parity::None) {
			transmission |= parity(uint8_t(next_transmission_)) ? mask : 0;
			mask <<= 1;
		}

		// Add stop bits.
		for(int c = 0; c < stop_bits_; ++c) {
			transmission |= mask;
			mask <<= 1;
		}

		// Output all that.
		const int total_bits = expected_bits();
		transmit.write(divider_ * 2, total_bits, transmission);

		// Mark the transmit register as empty again.
		next_transmission_ = NoValueMask;
	}
}

ClockingHint::Preference ACIA::preferred_clocking() const {
	// Real-time clocking is required if a transmission is ongoing; this is a courtesy for whomever
	// is on the receiving end.
	if(transmit.transmission_data_time_remaining() > 0) return ClockingHint::Preference::RealTime;

	// If a bit reception is ongoing that might lead to an interrupt, ask for real-time clocking
	// because it's unclear when the interrupt might come.
	if(bits_incoming_ && receive_interrupt_enabled_) return ClockingHint::Preference::RealTime;

	// Real-time clocking not required then.
	return ClockingHint::Preference::JustInTime;
}

bool ACIA::get_interrupt_line() const {
	return interrupt_line_;
}

int ACIA::expected_bits() {
	return 1 + data_bits_ + stop_bits_ + (parity_ != Parity::None);
}

uint8_t ACIA::parity(uint8_t value) {
	value ^= value >> 4;
	value ^= value >> 2;
	value ^= value >> 1;
	return value ^ (parity_ == Parity::Even);
}

bool ACIA::serial_line_did_produce_bit(Serial::Line *, int bit) {
	// Shift this bit into the 11-bit input register; this is big enough to hold
	// the largest transmission symbol.
	++bits_received_;
	bits_incoming_ = (bits_incoming_ >> 1) | (bit << 10);

	// If that's the now-expected number of bits, update.
	const int bit_target = expected_bits();
	if(bits_received_ >= bit_target) {
		bits_received_ = 0;
		overran_ |= get_status() & 1;
		received_data_ = uint8_t(bits_incoming_ >> (12 - bit_target));
		update_interrupt_line();
		update_clocking_observer();
		return false;
	}

	// TODO: overrun, and parity.

	// Keep receiving, and consider a potential clocking change.
	if(bits_received_ == 1) update_clocking_observer();
	return true;
}

void ACIA::set_interrupt_delegate(InterruptDelegate *delegate) {
	interrupt_delegate_ = delegate;
}

void ACIA::update_interrupt_line() {
	const bool old_line = interrupt_line_;

	/*
		"Bit 7 of the control register is the rie bit. When the rie bit is high, the rdrf, ndcd,
		and ovr bits will assert the nirq output. When the rie bit is low, nirq generation is disabled."

		rie = read interrupt enable
		rdrf = receive data register full (status word bit 0)
		ndcd = data carrier detect (status word bit 2)
		over = receiver overrun (status word bit 5)

		"Bit 1 of the status register is the tdre bit. When high, the tdre bit indicates that data has been
		transferred from the transmitter data register to the output shift register. At this point, the a6850
		is ready to accept a new transmit data byte. However, if the ncts signal is high, the tdre bit remains
		low regardless of the status of the transmitter data register. Also, if transmit interrupt is enabled,
		the nirq output is asserted."

		tdre = transmitter data register empty
		ncts = clear to send
	*/
	const auto status = get_status();
	interrupt_line_ =
		(receive_interrupt_enabled_ && (status & 0x25)) ||
		(transmit_interrupt_enabled_ && (status & 0x02));

	if(interrupt_delegate_ && old_line != interrupt_line_) {
		interrupt_delegate_->acia6850_did_change_interrupt_status(this);
	}
}

uint8_t ACIA::get_status() {
	return
		((received_data_ & NoValueMask) ? 0x00 : 0x01) |
		((next_transmission_ == NoValueMask) ? 0x02 : 0x00) |
//		(data_carrier_detect.read() ? 0x04 : 0x00) |
//		(clear_to_send.read() ? 0x08 : 0x00) |
		(overran_ ? 0x20 : 0x00) |
		(interrupt_line_ ? 0x80 : 0x00)
	;

	// b0: receive data full.
	// b1: transmit data empty.
	// b2: DCD.
	// b3: CTS.
	// b4: framing error (i.e. no first stop bit where expected).
	// b5: receiver overran.
	// b6: parity error.
	// b7: IRQ state.
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-2016, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

#include <TSystem.h>
#include <TString.h>
#include <TError.h>

#include "AliPWGJETrainHelpers.h"

std::vector<std::string> AliPWGJETrainHelpers::ExtractAliEnProductionValuesForLEGOTrain()
{
  // Automatically set shared common variables
  // The run period (ex. "LHC15o")
  std::string period = gSystem->Getenv("ALIEN_JDL_LPMPRODUCTIONTAG");
  // either "pp", "pPb" or "PbPb"
  std::string collType = gSystem->Getenv("ALIEN_JDL_LPMINTERACTIONTYPE");
  // Used to get mc
  std::string prodType = gSystem->Getenv("ALIEN_JDL_LPMPRODUCTIONTYPE");

  // In the case of the metadataset, the standard environment variables above will not be set.
  // Instead, we attempt to retrieve the variable from the first enabled metadataset. This requires looping
  // over the available metadatasets untils we find a non-null value.
  // We assume that all children in the metadataset should have the same collision system and production type.
  // Although this isn't the case for the period, since the variables are supposed to be the same
  // in all metadatasets (according to Markus Z.), the track cuts presumably must all be the same for
  // all periods in a metadataset.
  const std::string childDatasets = gSystem->Getenv("CHILD_DATASETS"); // Used to get mc
  const int nChildDatasets = std::atoi(childDatasets.c_str());
  for (int i = 1; i <= nChildDatasets; i++) {
    if (period == "") {
      period = gSystem->Getenv(TString::Format("ALIEN_JDL_child_%i_LPMPRODUCTIONTAG", i));
    }
    if (collType == "") {
      collType = gSystem->Getenv(TString::Format("ALIEN_JDL_child_%i_LPMINTERACTIONTYPE", i));
    }
    if (prodType == "") {
      prodType = gSystem->Getenv(TString::Format("ALIEN_JDL_child_%i_LPMPRODUCTIONTYPE", i));
    }
  }
  // Validate the extract variables. Each one must be set at this point.
  if (period == "" || collType == "" || prodType == "") {
    // Somehow failed to extract the variables which should always be available.
    ::Fatal("AliPWGJETrainHelpers", "Somehow failed to extract the period, collision type, or production type.\n");
  }

  // Determine if it's an MC production.
  const bool mc = (prodType == "MC");

  // Determine if it's Run2
  std::string yearString = period.substr(3, 2);
  int productionYear = std::atoi(yearString.c_str());
  const bool isRun2 = productionYear > 14;

  // We need to return multiple values, so we use a vector and convert the bools to strings temporarily.
  // They should be converted back after returning.
  // (Not that the bool text doesn't really matter as long as it's non-zero, but we select "true" as it
  // corresponds to the variables being true).
  return std::vector<std::string>{period, collType, mc ? "true" : "", isRun2 ? "true" : ""};
}

<commit_msg>Fix handling of Getenv<commit_after>/**************************************************************************
 * Copyright(c) 1998-2016, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

#include <TSystem.h>
#include <TString.h>
#include <TError.h>

#include "AliPWGJETrainHelpers.h"

std::vector<std::string> AliPWGJETrainHelpers::ExtractAliEnProductionValuesForLEGOTrain()
{
  // NOTE: `Getenv(...)` returns `nullptr` if the environment variable isn't available.
  //       std::string _cannot_ be set to `nullptr`, so we retrieve the result as a `const char*`
  //       and then convert it to a `std::string` if it is not null. We use std::string for
  //       convenience and to simplify string comparison.

  // Automatically set shared common variables
  // The run period (ex. "LHC15o")
  const char * tempPeriod = gSystem->Getenv("ALIEN_JDL_LPMPRODUCTIONTAG");
  std::string period = tempPeriod ? tempPeriod : "";
  // Either "pp", "pPb" or "PbPb"
  const char * tempCollType = gSystem->Getenv("ALIEN_JDL_LPMINTERACTIONTYPE");
  std::string collType = tempCollType ? tempCollType : "";
  // Used to get MC.
  const char * tempProdType = gSystem->Getenv("ALIEN_JDL_LPMPRODUCTIONTYPE");
  std::string prodType = tempProdType ? tempProdType : "";

  // In the case of the metadataset, the standard environment variables above will not be set.
  // Instead, we attempt to retrieve the variable from the first enabled metadataset. This requires looping
  // over the available metadatasets until we find a non-null value.
  // We assume that all children in the metadataset should have the same collision system and production type.
  // Although this isn't the case for the period, since the variables are supposed to be the same
  // in all metadatasets (according to Markus Z.), the track cuts presumably must all be the same for
  // all periods in a metadataset.
  const char * tempChildDatasets = gSystem->Getenv("CHILD_DATASETS");
  // Used to get MC.
  const std::string childDatasets = tempChildDatasets ? tempChildDatasets : "";
  const int nChildDatasets = std::atoi(childDatasets.c_str());
  for (int i = 1; i <= nChildDatasets; i++) {
    if (period == "") {
      tempPeriod = gSystem->Getenv(TString::Format("ALIEN_JDL_child_%i_LPMPRODUCTIONTAG", i));
      period = tempPeriod ? tempPeriod : "";
    }
    if (collType == "") {
      tempCollType = gSystem->Getenv(TString::Format("ALIEN_JDL_child_%i_LPMINTERACTIONTYPE", i));
      collType = tempCollType ? tempCollType : "";
    }
    if (prodType == "") {
      tempProdType = gSystem->Getenv(TString::Format("ALIEN_JDL_child_%i_LPMPRODUCTIONTYPE", i));
      prodType = tempProdType ? tempProdType : "";
    }
  }
  // Validate the extract variables. Each one must be set at this point.
  if (period == "" || collType == "" || prodType == "") {
    // Somehow failed to extract the variables which should always be available.
    ::Fatal("AliPWGJETrainHelpers", "Somehow failed to extract the period, collision type, or production type.\n");
  }

  // Determine if it's an MC production.
  const bool mc = (prodType == "MC");

  // Determine if it's Run 2
  std::string yearString = period.substr(3, 2);
  int productionYear = std::atoi(yearString.c_str());
  const bool isRun2 = productionYear > 14;

  // We need to return multiple values, so we use a vector and convert the bools to strings temporarily.
  // They should be converted back after returning.
  // (Not that the bool text doesn't really matter as long as it's non-zero, but we select "true" as it
  // corresponds to the variables being true).
  return std::vector<std::string>{period, collType, mc ? "true" : "", isRun2 ? "true" : ""};
}

<|endoftext|>


<commit_before>#include "qmtopology.h"
#include "qmnblist.h"

QMTopology::QMTopology()
{}

QMTopology::~QMTopology()
{}

void QMTopology::Initialize(Topology& cg_top)
{
    CopyTopologyData(&cg_top);
    this->InitChargeUnits();
}

void QMTopology::Cleanup()
{
    vector<CrgUnit *>::iterator iter;
    for(iter=_crgunits.begin(); iter!=_crgunits.end(); ++iter)
        delete *iter;
    _crgunits.clear();
    _mcharges.clear();
    Topology::Cleanup();
}

void QMTopology::Update(Topology& cg_top)
{
    BeadContainer::iterator iter;
    BeadContainer::iterator iter_cg;

    assert(cg_top.Beads().size() == _beads.size());

    _box = cg_top.getBox();
    _time = cg_top.getTime();
    _step = cg_top.getStep();

    iter_cg = cg_top.Beads().begin();
    for(iter=_beads.begin(); iter!=_beads.end(); ++iter, ++iter_cg) {
        (*iter)->setPos((*iter_cg)->getPos());
        if((*iter_cg)->HasU())
            (*iter)->setU((*iter_cg)->getU());
        if((*iter_cg)->HasV())
            (*iter)->setV((*iter_cg)->getV());
        if((*iter_cg)->HasW())
            (*iter)->setW((*iter_cg)->getW());
        QMBead * b = (QMBead*)(*iter);

        if(!(*iter_cg)->HasU()) {
            (*iter)->setU(vec(1,0,0));
            (*iter)->setV(vec(0,1,0));
            (*iter)->setW(vec(0,0,1));
        }

        b->UpdateCrg();
    }
}

void QMTopology::LoadListCharges(const string &file)
{
    _jcalc.Initialize(file);
}

void QMTopology::AddAtomisticBeads(CrgUnit *crg, Topology * totop){

    mol_and_orb * atoms = crg->rotate_translate_beads();
    totop->CreateResidue("DUM");
    Molecule *mi = totop->CreateMolecule((crg)->getName());
    mi->setUserData(crg);   //mi->getUserData<CrgUnit>();
    for (int i=0;i<atoms->getN();i++){
        vec pos = unit<bohr,nm>::to(atoms->GetPos(i));
        string atomtype = string( atoms->gettype(i) )+ string("-") + lexical_cast<string>(crg->getId());
        BeadType * bt= totop->GetOrCreateBeadType(atomtype);
        Bead * bead = totop ->CreateBead(1, atomtype,bt,0, 0, 0.);
        bead->setPos(pos);
        mi->AddBead(bead,"???");
        if(crg->getType()->GetCrgUnit().getChargesNeutr()) {
            double charge_of_bead_neutral=crg->getType()->GetCrgUnit().getChargesNeutr()->mpls[i];
            bead->setQ(charge_of_bead_neutral);
        }

    }
    delete atoms->getorbs();
    delete atoms;
}

Bead *QMTopology::CreateBead(byte_t symmetry, string name, BeadType *type, int resnr, double m, double q)
{
    QMBead *bead = new QMBead(this, _beads.size(), type, symmetry, name, resnr, m, q);
    _beads.push_back(bead);
    return bead;
}

void QMTopology::InitChargeUnits(){
    BeadContainer::iterator itb;
    for (itb = _beads.begin() ; itb< _beads.end(); ++itb){
        QMBead * bead = dynamic_cast<QMBead *>(*itb);
        //initialise the crgunit * only if appropriate extra info is in the cg.xml file
        if ( (bead->Options()).exists("qm.crgunitname")){
            string namecrgunittype = bead->getType()->getName();
            int intpos = (bead->Options()).get("qm.position").as<int>();
            string namecrgunit = (bead->Options()).get("qm.crgunitname").as<string>();

            //determine whether it  has been created already
            int molid= bead->getMolecule()->getId();
            string molandtype = lexical_cast<string>(molid)+":"+namecrgunit;

            CrgUnit * acrg = GetCrgUnitByName(molandtype);
            if(acrg == NULL)
                acrg = CreateCrgUnit(molandtype, namecrgunittype, molid);

            bead->setCrg(acrg);
            bead->setiPos(intpos);
        }
        else{
            bead->setCrg(NULL);
        }
    }
}

// TODO: this function should not be in qmtopology!
void QMTopology::ComputeAllTransferIntegrals(){
    for(QMNBList::iterator iter = _nblist.begin();
        iter!=_nblist.end();++iter) {
        CrgUnit *crg1 = (*iter)->Crg1();
        CrgUnit *crg2 = (*iter)->Crg2();
        vector <double> Js = GetJCalc().CalcJ(*crg1, *crg2);
        (*iter)->setJs(Js);
    }
}

   // In topology.cc???
//Copy charges to either charged or neutral case

void QMTopology::CopyCharges(CrgUnit *crg, Molecule *mol)
{
    if(mol->BeadCount() != crg->getType()->GetCrgUnit().getN())
        throw std::runtime_error("QMTopology::CopyCharges: number of atoms in crgunit does not match number of beads in molecule");

    if(!crg->getType()->GetCrgUnit().getChargesNeutr())
        throw std::runtime_error("QMTopology::CopyCharges: no charges defined");

    //loop over all beads in that molecule
    for (int i = 0; i < mol->BeadCount(); i++) {
        //get charge
        double charge_of_bead_i_neutral = crg->getType()->GetCrgUnit().getChargesNeutr()->mpls[i];
        //set charge
        mol->getBead(i)->setQ(charge_of_bead_i_neutral);
    }
}

//Copy charges to either charged or neutral case
void QMTopology::CopyChargesOccupied(CrgUnit *crg, Molecule *mol)
{
    if(mol->BeadCount() != crg->getType()->GetCrgUnit().getN())
        throw std::runtime_error("QMTopology::CopyCharges: number of atoms in crgunit does not match number of beads in molecule");

    if(!crg->getType()->GetCrgUnit().getChargesCrged())
        throw std::runtime_error("QMTopology::CopyCharges: no charges defined");

    //loop over all beads in that molecule
    for (int i = 0; i < mol->BeadCount(); i++) {
        //get charge
        double charge_of_bead_i_charged = crg->getType()->GetCrgUnit().getChargesCrged()->mpls[i];
        //set charge
        mol->getBead(i)->setQ(charge_of_bead_i_charged);
    }
}
<commit_msg>better check for bead symmetry + positions<commit_after>#include "qmtopology.h"
#include "qmnblist.h"

QMTopology::QMTopology()
{}

QMTopology::~QMTopology()
{}

void QMTopology::Initialize(Topology& cg_top)
{
    CopyTopologyData(&cg_top);
    this->InitChargeUnits();
}

void QMTopology::Cleanup()
{
    vector<CrgUnit *>::iterator iter;
    for(iter=_crgunits.begin(); iter!=_crgunits.end(); ++iter)
        delete *iter;
    _crgunits.clear();
    _mcharges.clear();
    Topology::Cleanup();
}

void QMTopology::Update(Topology& cg_top)
{
    BeadContainer::iterator iter;
    BeadContainer::iterator iter_cg;

    assert(cg_top.Beads().size() == _beads.size());

    _box = cg_top.getBox();
    _time = cg_top.getTime();
    _step = cg_top.getStep();

    iter_cg = cg_top.Beads().begin();
    for(iter=_beads.begin(); iter!=_beads.end(); ++iter, ++iter_cg) {
        (*iter)->setPos((*iter_cg)->getPos());
        if((*iter_cg)->HasU())
            (*iter)->setU((*iter_cg)->getU());
        if((*iter_cg)->HasV())
            (*iter)->setV((*iter_cg)->getV());
        if((*iter_cg)->HasW())
            (*iter)->setW((*iter_cg)->getW());
        QMBead * b = (QMBead*)(*iter);

        if((*iter_cg)->getSymmetry() == 1) {
            (*iter)->setU(vec(1,0,0));
            (*iter)->setV(vec(0,1,0));
            (*iter)->setW(vec(0,0,1));
        }

        b->UpdateCrg();
    }
}

void QMTopology::LoadListCharges(const string &file)
{
    _jcalc.Initialize(file);
}

void QMTopology::AddAtomisticBeads(CrgUnit *crg, Topology * totop){

    mol_and_orb * atoms = crg->rotate_translate_beads();
    totop->CreateResidue("DUM");
    Molecule *mi = totop->CreateMolecule((crg)->getName());
    mi->setUserData(crg);   //mi->getUserData<CrgUnit>();
    for (int i=0;i<atoms->getN();i++){
        vec pos = unit<bohr,nm>::to(atoms->GetPos(i));
        string atomtype = string( atoms->gettype(i) )+ string("-") + lexical_cast<string>(crg->getId());
        BeadType * bt= totop->GetOrCreateBeadType(atomtype);
        Bead * bead = totop ->CreateBead(1, atomtype,bt,0, 0, 0.);
        bead->setPos(pos);
        mi->AddBead(bead,"???");
        if(crg->getType()->GetCrgUnit().getChargesNeutr()) {
            double charge_of_bead_neutral=crg->getType()->GetCrgUnit().getChargesNeutr()->mpls[i];
            bead->setQ(charge_of_bead_neutral);
        }

    }
    delete atoms->getorbs();
    delete atoms;
}

Bead *QMTopology::CreateBead(byte_t symmetry, string name, BeadType *type, int resnr, double m, double q)
{
    QMBead *bead = new QMBead(this, _beads.size(), type, symmetry, name, resnr, m, q);
    _beads.push_back(bead);
    return bead;
}

void QMTopology::InitChargeUnits(){
    BeadContainer::iterator itb;
    for (itb = _beads.begin() ; itb< _beads.end(); ++itb){
        QMBead * bead = dynamic_cast<QMBead *>(*itb);
        //initialise the crgunit * only if appropriate extra info is in the cg.xml file
        if ( (bead->Options()).exists("qm.crgunitname")){
            string namecrgunittype = bead->getType()->getName();
            int intpos = (bead->Options()).get("qm.position").as<int>();
            string namecrgunit = (bead->Options()).get("qm.crgunitname").as<string>();

            //determine whether it  has been created already
            int molid= bead->getMolecule()->getId();
            string molandtype = lexical_cast<string>(molid)+":"+namecrgunit;

            CrgUnit * acrg = GetCrgUnitByName(molandtype);
            if(acrg == NULL)
                acrg = CreateCrgUnit(molandtype, namecrgunittype, molid);

            bead->setCrg(acrg);
            bead->setiPos(intpos);
        }
        else{
            bead->setCrg(NULL);
        }
    }
}

// TODO: this function should not be in qmtopology!
void QMTopology::ComputeAllTransferIntegrals(){
    for(QMNBList::iterator iter = _nblist.begin();
        iter!=_nblist.end();++iter) {
        CrgUnit *crg1 = (*iter)->Crg1();
        CrgUnit *crg2 = (*iter)->Crg2();
        vector <double> Js = GetJCalc().CalcJ(*crg1, *crg2);
        (*iter)->setJs(Js);
    }
}

   // In topology.cc???
//Copy charges to either charged or neutral case

void QMTopology::CopyCharges(CrgUnit *crg, Molecule *mol)
{
    if(mol->BeadCount() != crg->getType()->GetCrgUnit().getN())
        throw std::runtime_error("QMTopology::CopyCharges: number of atoms in crgunit does not match number of beads in molecule");

    if(!crg->getType()->GetCrgUnit().getChargesNeutr())
        throw std::runtime_error("QMTopology::CopyCharges: no charges defined");

    //loop over all beads in that molecule
    for (int i = 0; i < mol->BeadCount(); i++) {
        //get charge
        double charge_of_bead_i_neutral = crg->getType()->GetCrgUnit().getChargesNeutr()->mpls[i];
        //set charge
        mol->getBead(i)->setQ(charge_of_bead_i_neutral);
    }
}

//Copy charges to either charged or neutral case
void QMTopology::CopyChargesOccupied(CrgUnit *crg, Molecule *mol)
{
    if(mol->BeadCount() != crg->getType()->GetCrgUnit().getN())
        throw std::runtime_error("QMTopology::CopyCharges: number of atoms in crgunit does not match number of beads in molecule");

    if(!crg->getType()->GetCrgUnit().getChargesCrged())
        throw std::runtime_error("QMTopology::CopyCharges: no charges defined");

    //loop over all beads in that molecule
    for (int i = 0; i < mol->BeadCount(); i++) {
        //get charge
        double charge_of_bead_i_charged = crg->getType()->GetCrgUnit().getChargesCrged()->mpls[i];
        //set charge
        mol->getBead(i)->setQ(charge_of_bead_i_charged);
    }
}
<|endoftext|>