diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/lib94/lib94.hpp | 62 |
1 files changed, 53 insertions, 9 deletions
diff --git a/include/lib94/lib94.hpp b/include/lib94/lib94.hpp index b8da8a8..86732de 100644 --- a/include/lib94/lib94.hpp +++ b/include/lib94/lib94.hpp @@ -14,6 +14,10 @@ namespace lib94 { + //this type is used to represent values inside the core. + //it has to be at least big enough to represent LIB94_CORE_SIZE squared, + //since it is used as an intermediate for all of the instructions, + //including in particular MUL. typedef int_least32_t number_t; enum opcode : uint8_t { @@ -48,46 +52,86 @@ namespace lib94 { std::string name; std::string author; + //the org of the warrior, as an index into the instructions vector number_t org; + //the instructions of the warrior at the start of a round std::vector<instruction> instructions; }; + //this seeds the prng used to place warriors into the core at the start of a round + //if this is never called, 0 is used as a seed and the placements are deterministic. void seed_prng(uint_fast64_t seed); + //converts an instruction to a string representation like + // dat.f $0, $0 std::string instruction_to_string(const instruction &instr); + //this exception is thrown by any error that occurs in the compile_warrior function, + //including a malformed instruction, a non-existent label being referenced, a division + //division by zero in a compile-time expression, a failed ;assert comment, etc. struct compiler_exception : public std::exception { unsigned source_line_number; std::string message; }; + //takes a string with the full source code of a warrior. on success, returns a pointer + //to a warrior struct representing the compiled warrior (which you must delete when + //you are done with it). on failure, throws a compiler_exception as defined above. warrior *compile_warrior(std::string source); + //fills the core with the supplied instruction; does not effect the address sets. void clear_core(const instruction &background); - void clear_core_random(); - //warrior pointers need to remain valid for other - //functions to return valid things during the round - bool init_round(const warrior *const *warriors, size_t count); + //fills the core with random instructions chosen from a uniform distribution; + //does not effect the address sets. + void clear_core_random(); + //clears the address sets, places the supplied warriors into the core, and starts one + //process for each supplied warrior at its org. the count parameter specifies the + //number of warriors in the array. note that, if the supplied warriors cannot all be + //fit into the core, this will never return. the each of the warriors in the array + //must not be deleted for the duration of the round, but the array itself may be + //deleted after this function returns. note that this function does not clear the core + //before placing the warriors, so you may want to call clear_core or clear_core_random + //before calling this. note also that you probably want to call seed_prng, for example + //with the current time, before the first time you call this. + void init_round(const warrior *const *warriors, size_t count); + + //returns the number of warriors who have at least one process size_t alive_warrior_count(); - //asserts that there is a next warrior + //returns a pointer to the warrior whose turn it will be during the next call + //to single_step. makes an assertion that there is such a warrior, so check + //alive_warrior_count first if you are not sure. const warrior *get_next_warrior(); + + //gets the program counter queue for the specified warrior. fails an assertion if this + //pointer was not one of the pointers in the array passed to init_round. it's okay if + //this warrior has no processes left; in that case this returns an empty deque. const std::deque<number_t> &get_processes(const warrior *for_warrior); - //asserts that there is a next process - number_t get_next_process(const warrior *for_warrior); + //the addresses written to since the last call to init_round or clear_address_sets const std::set<number_t> &get_written_addresses(); + + //the addresses read from since the last call to init_round or clear_address_sets const std::set<number_t> &get_read_addresses(); + + //the addresses executed since the last call to init_round or clear_address_sets const std::set<number_t> &get_executed_addresses(); + void clear_address_sets(); + //the instruction at the specified address of the core const instruction &get_instruction(number_t address); - //assumes that there is a next warrior - //returns a warrior if it dies + //does one step of the simulation. assumes that there is at least one warrior with at + //least one alive process, so check alive_warrior_count first if you aren't sure. + //if the warrior whose turn it is dies during this step, the pointer to that warrior + //is returned. otherwise, a null pointer is returned. the update_address_sets template + //parameter controls whether to update the sets returned by get_written_addresses, + //get_read_addresses, and get_executed_addresses. this is provided so that you can + //improve the performance of the simulation if you do not need that information. template <bool update_address_sets> const warrior *single_step(); |