From 2e77d2beb637b147bd79172caa4a1a017f0b6767 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 6 Jan 2017 15:25:16 +0000 Subject: [PATCH] Having found rust wasn't going to work, I've hacked up a rough core of the cons space in C. None of this is tested. --- Makefile | 23 +++++++ src/conspage.c | 156 ++++++++++++++++++++++++++++++++++++++++++ src/conspage.h | 36 ++++++++++ src/consspaceobject.c | 14 ++++ src/consspaceobject.h | 116 +++++++++++++++++++++++++++++++ src/init.c | 22 ++++++ src/quickbool.h | 19 +++++ src/version.h | 12 ++++ 8 files changed, 398 insertions(+) create mode 100644 Makefile create mode 100644 src/conspage.c create mode 100644 src/conspage.h create mode 100644 src/consspaceobject.c create mode 100644 src/consspaceobject.h create mode 100644 src/init.c create mode 100644 src/quickbool.h create mode 100644 src/version.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..144dbf5 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ + +TARGET ?= target/psse +SRC_DIRS ?= ./src + +SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c -or -name *.s) +OBJS := $(addsuffix .o,$(basename $(SRCS))) +DEPS := $(OBJS:.o=.d) + +INC_DIRS := $(shell find $(SRC_DIRS) -type d) +INC_FLAGS := $(addprefix -I,$(INC_DIRS)) + +VERSION := "0.0.0" + +CPPFLAGS ?= $(INC_FLAGS) -MMD -MP + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -DVERSION=$(VERSION) -o $@ $(LOADLIBES) $(LDLIBS) + +.PHONY: clean +clean: + $(RM) $(TARGET) $(OBJS) $(DEPS) + +-include $(DEPS) diff --git a/src/conspage.c b/src/conspage.c new file mode 100644 index 0000000..541dc86 --- /dev/null +++ b/src/conspage.c @@ -0,0 +1,156 @@ +/** + * conspage.c + * + * Setup and tear down cons pages, and (FOR NOW) do primitive + * allocation/deallocation of cells. + * NOTE THAT before we go multi-threaded, these functions must be + * aggressively + * thread safe. + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include +#include +#include +#include + +#include "consspaceobject.h" +#include "conspage.h" + + + +/** + * Flag indicating whether conspage initialisation has been done. + */ +bool conspageinitihasbeencalled = false; + +/** + * The (global) pointer to the (global) freelist. Not sure whether this ultimately belongs in this file. + */ +struct cons_pointer freelist = NIL; + +/** + * An array of pointers to cons pages. + */ +struct cons_page* conspages[NCONSPAGES]; + +/** + * the number of cons pages which have thus far been initialised. + */ +int initialisedconspages = 0; + + +/** + * Make a cons page whose serial number (i.e. index in the conspages directory) is pageno. + * Initialise all cells and prepend each to the freelist; if pageno is zero, do not prepend + * cells 0 and 1 to the freelist but initialise them as NIL and T respectively. + */ +void makeconspage() { + struct cons_page* result = malloc( sizeof( struct cons_page)); + + if ( result != NULL) { + for (int i = 0; i < CONSPAGESIZE; i++) { + if ( initialisedconspages == 0 && i < 2) { + if ( i == 0) { + /* initialise cell as NIL */ + strncpy( result->cell[i].tag, NILTAG, 4); + result->cell[i].count = (2 ^ 32) - 1; // should be max value of unsigned 32 bit integer + result->cell[i].payload.free.car = NIL; + result->cell[i].payload.free.cdr = NIL; + } else if ( i == 1) { + /* initialise cell as T */ + strncpy( result->cell[i].tag, TRUETAG, 4); + result->cell[i].count = (2 ^ 32) - 1; // should be max value of unsigned 32 bit integer + result->cell[i].payload.free.car = (struct cons_pointer){ 0, 1}; + result->cell[i].payload.free.cdr = (struct cons_pointer){ 0, 1}; + } + } + + /* otherwise, standard initialisation */ + strncpy( result->cell[i].tag, FREETAG, 4); + result->cell[i].payload.free.car = NIL; + result->cell[i].payload.free.cdr = freelist; + freelist.page = initialisedconspages; + freelist.offset = i; + } + } else { + fprintf( stderr, "FATAL: Failed to allocate memory for cons page %d\n", initialisedconspages); + exit(1); + } + + conspages[initialisedconspages] = result; + initialisedconspages++; +} + + +/** + * Frees the cell at the specified pointer. Dangerous, primitive, low + * level. + * + * @pointer the cell to free + */ +void free_cell(struct cons_pointer pointer) { + struct cons_space_object cell = conspages[pointer.page]->cell[pointer.offset]; + + if ( strncmp( cell.tag, FREETAG, 4) != 0) { + if ( cell.count == 0) { + strncpy( cell.tag, FREETAG, 4); + cell.payload.free.car = NIL; + cell.payload.free.cdr = freelist; + freelist = pointer; + } else { + fprintf( stderr, "Attempt to free cell with %d dangling references at page %d, offset %d\n", + cell.count, pointer.page, pointer.offset); + } + } else { + fprintf( stderr, "Attempt to free cell which is already FREE at page %d, offset %d\n", + pointer.page, pointer.offset); + } +} + + +/** + * Allocates a cell with the specified tag. Dangerous, primitive, low + * level. + * + * @param tag the tag of the cell to allocate - must be a valid cons space tag. + * @return the cons pointer which refers to the cell allocated. + */ +struct cons_pointer allocatecell( char* tag) { + struct cons_pointer result = freelist; + + if ( result.page == NIL.page && result.offset == NIL.offset) { + makeconspage(); + result = allocatecell( tag); + } else { + struct cons_space_object cell = conspages[result.page]->cell[result.offset]; + + freelist = cell.payload.free.cdr; + + strncpy( cell.tag, tag, 4); + cell.count = 1; + cell.payload.cons.car = NIL; + cell.payload.cons.cdr = NIL; + } + + return result; +} + + +/** + * initialise the cons page system; to be called exactly once during startup. + */ +void conspagesinit() { + if ( conspageinitihasbeencalled == false) { + for (int i = 0; i < NCONSPAGES; i++) { + conspages[i] = (struct cons_page *) NULL; + } + + makeconspage(); + conspageinitihasbeencalled = true; + } else { + fprintf( stderr, "WARNING: conspageinit() called a second or subsequent time\n"); + } +} diff --git a/src/conspage.h b/src/conspage.h new file mode 100644 index 0000000..4a60900 --- /dev/null +++ b/src/conspage.h @@ -0,0 +1,36 @@ +#include "consspaceobject.h" + +#ifndef __conspage_h +#define __conspage_h + + +/** + * the number of cons cells on a cons page. The maximum value this can be (and consequently, + * the size which, by version 1, it will default to) is the maximum value of an unsigned 32 + * bit integer, which is to say 4294967296. However, we'll start small. + */ +#define CONSPAGESIZE 256 + +/** + * the number of cons pages we will initially allow for. For convenience we'll set up an array + * of cons pages this big; however, later we will want a mechanism for this to be able to grow + * dynamically to the maximum we can currently allow, which is 4294967296. + */ +#define NCONSPAGES 256 + +/** + * a cons page is essentially just an array of cons space objects. It might later have a local + * free list (i.e. list of free cells on this page) and a pointer to the next cons page, but + * my current view is that that's probably unneccessary. + */ +struct cons_page { + struct cons_space_object cell[CONSPAGESIZE]; +}; + + +/** + * initialise the cons page system; to be called exactly once during startup. + */ +void conspagesinit(); + +#endif diff --git a/src/consspaceobject.c b/src/consspaceobject.c new file mode 100644 index 0000000..8c5e433 --- /dev/null +++ b/src/consspaceobject.c @@ -0,0 +1,14 @@ +/** + * consspaceobject.c + * + * Structures common to all cons space objects. + * + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + + +#include + +#include "consspaceobject.h" diff --git a/src/consspaceobject.h b/src/consspaceobject.h new file mode 100644 index 0000000..d6d7d56 --- /dev/null +++ b/src/consspaceobject.h @@ -0,0 +1,116 @@ +/** + * consspaceobject.h + * + * Declarations common to all cons space objects. + * + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + + +#include + +#ifndef __consspaceobject_h +#define __consspaceobject_h + +/** + * The length of a tag, in bytes. + */ +#define TAGLENGTH 4 + +/** + * tag values, all of which must be 4 bytes. Must not collide with vector space tag values + */ +#define CONSTAG "CONS" +#define FREETAG "FREE" +#define INTEGERTAG "INTR" +#define NILTAG "NIL " +#define READTAG "READ" +#define REALTAG "REAL" +#define STRINGTAG "STRG" +#define TRUETAG "TRUE" +#define VECTORPOINTTAG "VECP" +#define WRITETAG "WRIT" + +/** + * a cons pointer which points to the special NIL cell + */ +#define NIL (struct cons_pointer){ 0, 0} + + +/** + * An indirect pointer to a cons cell + */ +struct cons_pointer { + uint32_t page; /* the index of the page on which this cell resides */ + uint32_t offset; /* the index of the cell within the page */ +}; + + +/** + * payload of a cons cell. + */ +struct cons_payload { + struct cons_pointer car; + struct cons_pointer cdr; +}; + +/** + * payload of a free cell. For the time being identical to a cons cell, + * but it may not be so in future. + */ +struct free_payload { + struct cons_pointer car; + struct cons_pointer cdr; +}; + +/** + * payload of an integer cell. For the time being just a signed integer; + * later might be a signed 128 bit integer, or might have some flag to point to an + * optional bignum object. + */ +struct integer_payload { + long int integer; +}; + + +/** + * payload for a real number cell. Internals of this liable to change to give 128 bits + * precision, but I'm not sure of the detail. + */ +struct real_payload { + long double real; +}; + +/** + * payload of a string cell. At least at first, only one UTF character will be stored in each cell. + */ +struct string_payload { + uint32_t character; /* the actual character stored in this cell */ + uint32_t padding; /* unused padding to word-align the cdr */ + struct cons_pointer cdr; +}; + +/** + * an object in cons space. + */ +struct cons_space_object { + char tag[TAGLENGTH]; /* the tag (type) of this cons cell */ + uint32_t count; /* the count of the number of references to this cell */ + struct cons_pointer access; /* cons pointer to the access control list of this cell */ + union { + /* if tag == CONSTAG */ + struct cons_payload cons; + /* if tag == FREETAG */ + struct free_payload free; + struct integer_payload integer; + struct cons_payload nil; + struct real_payload real; + struct string_payload string; + struct cons_payload t; + } payload; +}; + + +#endif diff --git a/src/init.c b/src/init.c new file mode 100644 index 0000000..03dc60d --- /dev/null +++ b/src/init.c @@ -0,0 +1,22 @@ +/** + * init.c + * + * Start up and initialise the environement - just enough to get working and (ultimately) + * hand off to the executive. + * + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include + +#include "version.h" +#include "conspage.h" + +int main (int argc, char *argv[]) { + printf( "Post scarcity software environment version %s\n", VERSION); + conspagesinit(); + + return(0); +} diff --git a/src/quickbool.h b/src/quickbool.h new file mode 100644 index 0000000..ab3ee10 --- /dev/null +++ b/src/quickbool.h @@ -0,0 +1,19 @@ +/** + * quickbool.h + * + * Currently, just a macro to test whether a cons_pointer is the + * special NIL cons_pointer. + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include "consspaceobject.h" + +#ifndef __quickbool_h +#define __quickbool_h + +/* true if conspointer points to the special cell NIL, else false */ +#define nilp(conspoint) ((((struct cons_pointer)conspoint).page == NIL.page) && ((struct conspoint).offser == NIL.offset)) + +#endif diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..3603e70 --- /dev/null +++ b/src/version.h @@ -0,0 +1,12 @@ +/** + * version.h + * + * Just the version number. There's DEFINITELY a better way to do this! + * + * + * (c) 2017 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + + +#define VERSION "0.0.0"