From 6ce27f8d4257d6b4f4419a5245a23ab6fb2b7459 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Luk=C3=A1=C5=A1=20Ji=C5=99i=C5=A1t=C4=9B?= Date: Sun, 14 Jan 2024 17:34:41 +0100 Subject: [PATCH] Add basic commands and refactor the code Implement parsing of basic commands (help, next, add...) -Mostly (?) as wrapper around function from previous commit -It should be possible to do it in a much better way Give the project some structure -split main.c -create src and inc directories --- Libft | 2 +- Makefile | 26 +++- TODO | 7 +- inc/FET_sim.h | 127 +++++++++++++++ main.c | 378 --------------------------------------------- src/build_helper.c | 58 +++++++ src/c_addfet.c | 27 ++++ src/c_addnode.c | 46 ++++++ src/c_bind.c | 21 +++ src/c_draw.c | 26 ++++ src/c_help.c | 12 ++ src/c_next.c | 28 ++++ src/c_setnode.c | 21 +++ src/colors.c | 54 +++++++ src/main.c | 280 +++++++++++++++++++++++++++++++++ src/sim_main.c | 38 +++++ src/sim_node.c | 86 +++++++++++ src/sim_state.c | 86 +++++++++++ src/text.c | 124 +++++++++++++++ 19 files changed, 1065 insertions(+), 382 deletions(-) create mode 100644 inc/FET_sim.h delete mode 100644 main.c create mode 100644 src/build_helper.c create mode 100644 src/c_addfet.c create mode 100644 src/c_addnode.c create mode 100644 src/c_bind.c create mode 100644 src/c_draw.c create mode 100644 src/c_help.c create mode 100644 src/c_next.c create mode 100644 src/c_setnode.c create mode 100644 src/colors.c create mode 100644 src/main.c create mode 100644 src/sim_main.c create mode 100644 src/sim_node.c create mode 100644 src/sim_state.c create mode 100644 src/text.c diff --git a/Libft b/Libft index 2447a14..988bd41 160000 --- a/Libft +++ b/Libft @@ -1 +1 @@ -Subproject commit 2447a14f38be8e2de8f3984dc708800b36f36c98 +Subproject commit 988bd412d9b3d0681457c4c169d398c273d0c6ff diff --git a/Makefile b/Makefile index dbc9185..4267c89 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,33 @@ RM := rm -f SUBPROJECTS := Libft -INCDIR := . +INCDIR := inc INCDIR += $(addsuffix /inc, $(SUBPROJECTS)); INCLUDE := $(addprefix -I, $(INCDIR)) -SOURCES := main.c +SRCDIR := src + +SOURCES := main.c \ + \ + sim_main.c \ + sim_node.c \ + sim_state.c \ + \ + text.c \ + colors.c \ + \ + build_helper.c \ + \ + c_addnode.c \ + c_addfet.c \ + c_setnode.c \ + c_bind.c \ + c_draw.c \ + c_next.c \ + c_help.c \ + +SOURCES := $(addprefix $(SRCDIR)/, $(SOURCES)) + OBJECTS := $(SOURCES:.c=.o) NAME := FET_sim diff --git a/TODO b/TODO index eb13eec..25d0489 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,15 @@ TODO +rewrite t_fet and t_node to store indexes insted of pointers to connected parts +rewrite command parsing (what I've created is just ugly) +come up with better file structure create language to write circuits in (circuit language?) (something like MHRD language?) implement circuit builder that converts circuit language to FET_sim representation in order to simulate -expand simulator commands +add even more simulation commands(eg. delete node/fet) test the project improve simulator io (maybe add graphics?) optimize +pass 42 norminette DONE foundations of logic +expand simulator commands diff --git a/inc/FET_sim.h b/inc/FET_sim.h new file mode 100644 index 0000000..612fc5d --- /dev/null +++ b/inc/FET_sim.h @@ -0,0 +1,127 @@ +#ifndef FET_SIM_H +# define FET_SIM_H + +# include "libft.h" + +# define MAX_ARGS 3 + +// zkrat means short circuit in my language. I opted for this because +// C does not permit short (it is type) and short_circuit was too long +typedef enum e_state +{ + off, + on, + pull_down, + pull_up, + floating, + zkrat, + unknown, +} t_state; + +typedef enum e_terminal +{ + source, + drain, + gate, +} t_terminal; + +typedef struct s_node +{ + int checked; + t_state state; + t_state set_state; + t_vec connected; +} t_node; + +typedef enum e_type +{ + p = 'p', + n = 'n', +} t_type; + +typedef struct s_mosfet +{ + int is_opened; + t_type type; + t_node *gate; + t_node *source; + t_node *drain; +} t_mosfet; + +typedef enum e_command +{ + none, + next, + draw, + setnode, + addfet, + addnode, + bind, + help, + exitsim, +} t_command; + +typedef enum e_arg_type +{ + num, + terminal, + state, + type, + command, +} t_arg_type; + +typedef union u_arg_val +{ + size_t num; + t_terminal terminal; + t_state state; + t_type type; + t_command command; +} t_arg_val; + +typedef struct s_arg +{ + t_arg_type type; + t_arg_val val; +} t_arg; + +typedef struct s_input +{ + t_command command; + size_t argc; + t_arg argv[MAX_ARGS]; +} t_input; + + +void add_node(t_vec *nodes, t_state set_state); +void add_mosfet(t_vec *mosfets, t_type type); +void bind_fet_node(t_mosfet *mosfet, t_node *node, t_terminal terminal); + +void free_node(void *node); +int process_input(t_vec *nodes, t_vec *mosfets); +int get_input(t_input *input); + +const char *state_color_escape(t_state state); +void draw_single(t_vec *nodes, t_vec *mosfets, size_t i); + +void update_nodes(t_vec *nodes); +int sim_step(t_vec *nodes, t_vec *mosfets); + +void print_start(void); +void command_not_found(const char *input); +void print_help(t_command c); +void print_index_error(size_t index, size_t size); + +t_state simple_resolve_state(t_state s1, t_state s2); +t_state resolve_state(t_vec *connected_nodes); +void apply_state(t_state state, t_vec *connected_nodes); +t_state reduce_state(t_state state); + +int c_addfet(t_input input, t_vec *mosfets); +int c_addnode(t_input input, t_vec *nodes); +int c_bind(t_input input, t_vec *nodes, t_vec *mosfets); +int c_draw(t_input input, t_vec *nodes, t_vec *mosfets); +int c_help(t_input input); +int c_next(t_input input, t_vec *nodes, t_vec *mosfets); +int c_setnode(t_input input, t_vec *nodes); +#endif //FET_SIM_H diff --git a/main.c b/main.c deleted file mode 100644 index aea46bb..0000000 --- a/main.c +++ /dev/null @@ -1,378 +0,0 @@ - -#include "libft.h" -#include - -// zkrat means short circuit in my language. I opted for this because -// C does not permit short (it is type) and short_circuit was too long -typedef enum e_state -{ - off, - on, - pull_down, - pull_up, - floating, - zkrat, - unknown, -} t_state; - -typedef enum e_terminal -{ - source, - drain, - gate, -} t_terminal; - -typedef struct s_node -{ - int checked; - t_state state; - t_state set_state; - t_vec connected; -} t_node; - -typedef enum e_type -{ - p = 'p', - n = 'n', -} t_type; - -typedef struct s_mosfet -{ - int is_opened; - t_type type; - t_node *gate; - t_node *source; - t_node *drain; -} t_mosfet; - -/* Monospace table of state resolution - * s2 \ s1 | short | off | on | pull_d | pull_u | float | unknown - * --------|-------|-------|-------|--------|--------|--------|--------- - * short | short | short | short | short | short | short | short - * --------|-------|-------|-------|--------|--------|--------|--------- - * off | short | off | short | off | off | off | off - * --------|-------|-------|-------|--------|--------|--------|--------- - * on | short | short | on | on | on | on | on - * --------|-------|-------|-------|--------|--------|--------|--------- - * pull_d | short | off | on | pull_d | pull_d | pull_d | pull_d - * --------|-------|-------|-------|--------|--------|--------|--------- - * pull_u | short | off | on | pull_d | pull_u | pull_u | pull_u - * --------|-------|-------|-------|--------|--------|--------|--------- - * float | short | off | on | pull_d | pull_u | float | float - * --------|-------|-------|-------|--------|--------|--------|--------- - * unknown | short | off | on | pull_d | pull_u | float | unknown - * - * It may be possible to construct the enum e_state in such a way that - * this function is easy arithmetics. - */ -t_state simple_resolve_state(t_state s1, t_state s2) -{ - if (s1 == s2) - return (s1); - if (s1 == zkrat || s2 == zkrat) - return (zkrat); - if ((s1 == off && s2 == on) || (s1 == on && s2 == off)) - return (zkrat); - if (s1 == on || s2 == on) - return (on); - if (s1 == off || s2 == off) - return (off); - if (s1 == pull_down || s2 == pull_down) - return (pull_down); - if (s1 == pull_up || s2 == pull_up) - return (pull_up); - if (s1 == floating || s2 == floating) - return (floating); - return (unknown); -} - -t_state resolve_state(t_vec *connected_nodes) -{ - size_t i; - t_state state; - t_node *node; - - i = 0; - state = unknown; - while (i < connected_nodes->size) - { - node = *(t_node **)ft_vec_access(connected_nodes, i); - state = simple_resolve_state(state, node->set_state); - ++i; - } - return (state); -} - -t_node *get_neighbour_node(const t_mosfet *mosfet, const t_node *start) -{ - if (mosfet->source == start) - return (mosfet->drain); - return (mosfet->source); -} - -void find_connected(t_node *node, t_vec *connected_nodes) -{ - size_t i; - t_node *neigh_node; - t_mosfet *mosfet; - - if (node->checked) - return ; - node->checked = 1; - ft_vec_append(connected_nodes, &node); - i = 0; - while (i < node->connected.size) - { - mosfet = *(t_mosfet **)ft_vec_access(&node->connected, i); - if (mosfet->is_opened) - { - neigh_node = get_neighbour_node(mosfet, node); - find_connected(neigh_node, connected_nodes); - } - ++i; - } - return ; -} - -void apply_state(t_state state, t_vec *connected_nodes) -{ - size_t i; - t_node *node; - - i = 0; - while (i < connected_nodes->size) - { - node = *(t_node **)ft_vec_access(connected_nodes, i); - node->state = state; - ++i; - } - return ; -} - -t_state reduce_state(t_state state) -{ - if (state == pull_down) - return (off); - if (state == pull_up) - return (on); - if (state == unknown) - return (floating); - return (state); -} - -void update_nodes(t_vec *nodes) -{ - size_t i; - t_state state; - t_node *cur_node; - t_vec connected_nodes; - - ft_vec_init(&connected_nodes, sizeof(t_node *)); - i = 0; - while (i < nodes->size) - { - cur_node = ft_vec_access(nodes, i); - if (!cur_node->checked) - { - find_connected(cur_node, &connected_nodes); - state = resolve_state(&connected_nodes); - apply_state(reduce_state(state), &connected_nodes); - ft_vec_forget_range(&connected_nodes, connected_nodes.size, 0); - } - ++i; - } - ft_vec_free(&connected_nodes, NULL); - return ; -} - -void update_mosfet(t_mosfet *mosfet) -{ - t_state state; - - state = mosfet->gate->state; - if (mosfet->type == p && state == on) - mosfet->is_opened = 1; - else if (mosfet->type == n && state == off) - mosfet->is_opened = 1; - else - mosfet->is_opened = 0; - return ; -} - -void update_mosfets(t_vec *mosfets) -{ - size_t i; - t_mosfet *mosfet; - - i = 0; - while (i < mosfets->size) - { - mosfet = ft_vec_access(mosfets, i); - update_mosfet(mosfet); - ++i; - } - return ; -} - -void reset_nodes(t_vec *nodes) -{ - size_t i; - t_node *node; - - i = 0; - while (i < nodes->size) - { - node = ft_vec_access(nodes, i); - node->checked = 0; - ++i; - } - return ; -} - -// memset is used to initialize struct padding -void add_node(t_vec *nodes, t_state set_state) -{ - t_node node; - - ft_memset(&node, 0, sizeof(node)); - node.checked = 0; - node.state = set_state; - node.set_state = set_state; - ft_vec_init(&node.connected, sizeof(t_mosfet *)); - ft_vec_append(nodes, &node); - return ; -} - -void add_mosfet(t_vec *mosfets, t_type type) -{ - t_mosfet mosfet; - - mosfet.is_opened = 0; - mosfet.type = type; - mosfet.gate = NULL; - mosfet.drain = NULL; - mosfet.source = NULL; - ft_vec_append(mosfets, &mosfet); - return ; -} - -void bind_fet_node(t_mosfet *mosfet, t_node *node, t_terminal terminal) -{ - t_node *old; - size_t index; - - old = NULL; - if (terminal == source) - { - old = mosfet->source; - mosfet->source = node; - ft_vec_append(&node->connected, &mosfet); - } - else if (terminal == drain) - { - old = mosfet->drain; - mosfet->drain = node; - ft_vec_append(&node->connected, &mosfet); - } - else - { - mosfet->gate = node; - } - if (old && ft_vec_find_index(&old->connected, &mosfet, &index) == success) - { - ft_vec_forget(&old->connected, index); - } - return ; -} - -void build_graph(__attribute__((unused)) const char *filename, t_vec *nodes, t_vec *mosfets) -{ - add_node(nodes, off); - add_node(nodes, off); - add_node(nodes, pull_up); - add_mosfet(mosfets, p); - bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 0), gate); - bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 1), drain); - bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 2), source); - return ; -} - -void free_node(void *node) -{ - ft_vec_free(&((t_node *)node)->connected, NULL); - return ; -} - -const char *state_color_escape(t_state state) -{ - if (state == on) - return ("\033[32m"); - if (state == off) - return ("\033[39m"); - if (state == floating) - return ("\033[34m"); - return ("\033[31m"); -} - -void draw(t_vec *nodes, t_vec *mosfets) -{ - size_t i; - size_t index; - t_mosfet *mosfet; - const char default_color[] = "\033[39m"; - - i = 0; - ft_printf("\n"); - while (i < mosfets->size) - { - mosfet = ft_vec_access(mosfets, i); - ft_vec_find_index(nodes, mosfet->source, &index); - ft_printf(" %u\n", index); - ft_printf(" %s|%s\n", state_color_escape(mosfet->source->state), default_color); - ft_vec_find_index(nodes, mosfet->gate, &index); - ft_printf("%u%s--%s%c\n", index, state_color_escape(mosfet->gate->state), default_color, mosfet->type); - ft_printf(" %s|%s\n", state_color_escape(mosfet->drain->state), default_color); - ft_vec_find_index(nodes, mosfet->drain, &index); - ft_printf(" %u\n\n", index); - ++i; - } - return ; -} - -int take_input(__attribute__((unused)) t_vec *nodes,__attribute__((unused)) t_vec *mosfets) -{ - int res; - char *input; - - ft_printf("FET_sim>"); - input = get_next_line(0); - res = 0; - if (input && (input[0] == n || (!ft_strncmp(input, "next", 4)))) - res = 1; - free(input); - return (res); -} - -int main(__attribute__((unused)) int argc, char **argv) -{ - int run; - t_vec nodes; - t_vec mosfets; - - ft_vec_init(&nodes, sizeof(t_node)); - ft_vec_init(&mosfets, sizeof(t_mosfet)); - build_graph(argv[1], &nodes, &mosfets); - run = 1; - while (run) - { - update_nodes(&nodes); - draw(&nodes, &mosfets); - update_mosfets(&mosfets); - reset_nodes(&nodes); - ((t_node *)ft_vec_access(&nodes, 0))->set_state = on; - run = take_input(&nodes, &mosfets); - } - ft_vec_free(&nodes, free_node); - ft_vec_free(&mosfets, NULL); - return (0); -} diff --git a/src/build_helper.c b/src/build_helper.c new file mode 100644 index 0000000..20a9f7d --- /dev/null +++ b/src/build_helper.c @@ -0,0 +1,58 @@ +#include "FET_sim.h" +#include "libft.h" + +void bind_fet_node(t_mosfet *mosfet, t_node *node, t_terminal terminal) +{ + t_node *old; + size_t index; + + old = NULL; + if (terminal == source) + { + old = mosfet->source; + mosfet->source = node; + ft_vec_append(&node->connected, &mosfet); + } + else if (terminal == drain) + { + old = mosfet->drain; + mosfet->drain = node; + ft_vec_append(&node->connected, &mosfet); + } + else + { + mosfet->gate = node; + } + if (old && ft_vec_find_index(&old->connected, &mosfet, &index) == success) + { + ft_vec_forget(&old->connected, index); + } + return ; +} + +// memset is used to initialize struct padding +void add_node(t_vec *nodes, t_state set_state) +{ + t_node node; + + ft_memset(&node, 0, sizeof(node)); + node.checked = 0; + node.state = set_state; + node.set_state = set_state; + ft_vec_init(&node.connected, sizeof(t_mosfet *)); + ft_vec_append(nodes, &node); + return ; +} + +void add_mosfet(t_vec *mosfets, t_type type) +{ + t_mosfet mosfet; + + mosfet.is_opened = 0; + mosfet.type = type; + mosfet.gate = NULL; + mosfet.drain = NULL; + mosfet.source = NULL; + ft_vec_append(mosfets, &mosfet); + return ; +} diff --git a/src/c_addfet.c b/src/c_addfet.c new file mode 100644 index 0000000..6ce663b --- /dev/null +++ b/src/c_addfet.c @@ -0,0 +1,27 @@ +#include "FET_sim.h" +#include "libft.h" + +int c_addfet(t_input input, t_vec *mosfets) +{ + size_t i; + + if (input.argc == 1 && input.argv[0].type == type) + { + add_mosfet(mosfets, input.argv[0].val.type); + ft_printf("Index of added FET: %u\n", mosfets->size - 1); + } + else if (input.argc == 2 && input.argv[0].type == type && input.argv[1].type == num) + { + i = 0; + ft_printf("Index of added FETs:\n\t"); + while (i < input.argv[1].val.num) + { + ft_printf("%u ", mosfets->size); + add_mosfet(mosfets, input.argv[0].val.type); + ++i; + } + } + /*else + print_wrong_usage(input);*/ + return (1); +} diff --git a/src/c_addnode.c b/src/c_addnode.c new file mode 100644 index 0000000..d98efc2 --- /dev/null +++ b/src/c_addnode.c @@ -0,0 +1,46 @@ +#include "FET_sim.h" +#include "libft.h" + +static int add_nodes(t_vec *nodes, size_t num, t_state state) +{ + size_t i; + + i = 0; + ft_printf("Indexes of added nodes:\n\t"); + while (i < num) + { + ft_printf("%u ", nodes->size); + add_node(nodes, state); + ++i; + } + ft_printf("\n"); + return (1); +} + +int c_addnode(t_input input, t_vec *nodes) +{ + size_t new_nodes_num; + t_state set_state; + + /*if (input.argc > 2 + || (input.argc == 1 + && input.argv[0].type != num && input.argv[0].type != state) + || (input.argc == 2 + && (input.argv[0].type != state || input.argv[1].type != num))) + { + print_wrong_usage(input); + return (1); + }*/ + new_nodes_num = 1; + set_state = unknown; + if (input.argc == 1 && input.argv[0].type == state) + set_state = input.argv[0].val.state; + else if (input.argc == 1) + new_nodes_num= input.argv[0].val.num; + else if (input.argc == 2) + { + set_state = input.argv[0].val.state; + new_nodes_num = input.argv[1].val.num; + } + return (add_nodes(nodes, new_nodes_num, set_state)); +} diff --git a/src/c_bind.c b/src/c_bind.c new file mode 100644 index 0000000..87e412d --- /dev/null +++ b/src/c_bind.c @@ -0,0 +1,21 @@ +#include "FET_sim.h" +#include "libft.h" + +int c_bind(t_input input, t_vec *nodes, t_vec *mosfets) +{ + t_node *node; + t_mosfet *mosfet; + t_terminal term; + + /*if (input.argc != 3 || input.argv[0].type != num + || input.argv[1].type != num || input.argv[2].type != terminal) + { + print_wrong_usage(input); + return (1); + }*/ + node = ft_vec_access(nodes, input.argv[0].val.num); + mosfet = ft_vec_access(mosfets, input.argv[1].val.num); + term = input.argv[2].val.terminal; + bind_fet_node(mosfet, node, term); + return (1); +} diff --git a/src/c_draw.c b/src/c_draw.c new file mode 100644 index 0000000..b9d354c --- /dev/null +++ b/src/c_draw.c @@ -0,0 +1,26 @@ +#include "FET_sim.h" +#include "libft.h" + +int c_draw(t_input input, t_vec *nodes, t_vec *mosfets) +{ + size_t i; + + if (input.argc == 0) + { + i = 0; + while (i < mosfets->size) + { + draw_single(nodes, mosfets, i); + ++i; + } + } + else if (input.argc == 1 && input.argv[0].type == num) + { + draw_single(nodes, mosfets, input.argv[0].val.num); + } + /*else + { + print_wrong_usage(input); + }*/ + return (1); +} diff --git a/src/c_help.c b/src/c_help.c new file mode 100644 index 0000000..3ebad7f --- /dev/null +++ b/src/c_help.c @@ -0,0 +1,12 @@ +#include "FET_sim.h" + +int c_help(t_input input) +{ + if (input.argc == 0) + print_help(none); + else if (input.argc == 1 && input.argv[0].type == command) + print_help(input.argv[0].val.command); + /*else + print_wrong_usage(input);*/ + return (1); +} diff --git a/src/c_next.c b/src/c_next.c new file mode 100644 index 0000000..2bf6a81 --- /dev/null +++ b/src/c_next.c @@ -0,0 +1,28 @@ +#include "FET_sim.h" +#include "libft.h" + +int c_next(t_input input, t_vec *nodes, t_vec *mosfets) +{ + size_t i; + + if (input.argc == 0) + { + if (!sim_step(nodes, mosfets)) + return (0); + } + else if (input.argc == 1 && input.argv[0].type == num) + { + i = 0; + while (i < input.argv[0].val.num) + { + if (!sim_step(nodes, mosfets)) + return (0); + ++i; + } + } + /*else + { + print_wrong_usage(input); + }*/ + return (1); +} diff --git a/src/c_setnode.c b/src/c_setnode.c new file mode 100644 index 0000000..ab849b0 --- /dev/null +++ b/src/c_setnode.c @@ -0,0 +1,21 @@ +#include "FET_sim.h" +#include "libft.h" + +int c_setnode(t_input input, t_vec *nodes) +{ + t_node *node; + + /*if (input.argc != 2 || input.argv[0].type != num || input.argv[1].type != state) + { + print_wrong_usage(input); + return (1); + }*/ + node = ft_vec_access(nodes, input.argv[0].val.num); + if (!node) + { + print_index_error(input.argv[0].val.num, nodes->size); + return (1); + } + node->set_state = input.argv[1].val.state; + return (1); +} diff --git a/src/colors.c b/src/colors.c new file mode 100644 index 0000000..deb0795 --- /dev/null +++ b/src/colors.c @@ -0,0 +1,54 @@ +#include "FET_sim.h" +#include "libft.h" + +// ac stands for ANSI (escape code) color +const char g_default_ac[] = "\033[39m"; + +const char g_red_ac[] = "\033[31m"; +const char g_green_ac[] = "\033[32m"; +const char g_blue_ac[] = "\033[34m"; +const char g_white_ac[] = "\033[97m"; + +const char *state_color_escape(t_state state) +{ + if (state == on) + return (g_green_ac); + if (state == off) + return (g_white_ac); + if (state == floating) + return (g_blue_ac); + return (g_red_ac); +} + +void draw_single(t_vec *nodes, t_vec *mosfets, size_t i) +{ + t_mosfet *mosfet; + size_t index; + + mosfet = ft_vec_access(mosfets, i); + if (ft_vec_find_index(nodes, mosfet->source, &index) == success) + { + ft_printf(" %u\n", index); + ft_printf(" %s|%s\n", state_color_escape(mosfet->source->state), g_default_ac); + } + else + { + ft_printf(" %sNULL%s\n", g_red_ac, g_default_ac); + ft_printf(" %s|%s\n", g_red_ac, g_default_ac); + } + if (ft_vec_find_index(nodes, mosfet->gate, &index) == success) + ft_printf("%4u%s--%s%c\n", index, state_color_escape(mosfet->gate->state), g_default_ac, mosfet->type); + else + ft_printf("%sNULL--%s%c\n", g_red_ac, g_default_ac, mosfet->type); + if (ft_vec_find_index(nodes, mosfet->drain, &index) == success) + { + ft_printf(" %s|%s\n", state_color_escape(mosfet->drain->state), g_default_ac); + ft_printf(" %u\n\n", index); + } + else + { + ft_printf(" %s|%s\n", g_red_ac, g_default_ac); + ft_printf(" %sNULL%s\n\n", g_red_ac, g_default_ac); + } + ++i; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..55a773f --- /dev/null +++ b/src/main.c @@ -0,0 +1,280 @@ +#include "FET_sim.h" +#include "libft.h" +#include + +void build_graph(__attribute__((unused)) const char *filename, t_vec *nodes, t_vec *mosfets) +{ + add_node(nodes, off); + add_node(nodes, off); + add_node(nodes, pull_up); + add_mosfet(mosfets, p); + bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 0), gate); + bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 1), drain); + bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 2), source); + return ; +} + +void free_node(void *node) +{ + ft_vec_free(&((t_node *)node)->connected, NULL); + return ; +} + +void free_split(char **sp) +{ + size_t i; + + i = 0; + while (sp[i]) + { + free(sp[i]); + ++i; + } + free(sp); + return ; +} + +size_t split_length(char **sp) +{ + size_t i; + + i = 0; + while (sp[i]) + ++i; + return (i); +} + +int parse_command(const char *str, t_command *cmd) +{ + if (!ft_strcmp(str, "n") || !ft_strcmp(str, "next")) + *cmd = next; + else if (!ft_strcmp(str, "d") || !ft_strcmp(str, "draw")) + *cmd = draw; + else if (!ft_strcmp(str, "s") || !ft_strcmp(str, "set") || !ft_strcmp(str, "setnode")) + *cmd = setnode; + else if (!ft_strcmp(str, "an") || !ft_strcmp(str, "addn") || !ft_strcmp(str, "addnode")) + *cmd = addnode; + else if (!ft_strcmp(str, "af") || !ft_strcmp(str, "addf") || !ft_strcmp(str, "addfet")) + *cmd = addfet; + else if (!ft_strcmp(str, "b") || !ft_strcmp(str, "bind")) + *cmd = bind; + else if (!ft_strcmp(str, "h") || !ft_strcmp(str, "help")) + *cmd = help; + else if (!ft_strcmp(str, "e") || !ft_strcmp(str, "exit")) + *cmd = exitsim; + else + return (0); + return (1); +} + +int parse_type(const char *str, t_type *type) +{ + if (!ft_strcmp(str, "p")) + *type = p; + else if (!ft_strcmp(str, "n")) + *type = n; + else + return (0); + return (1); +} + +int parse_terminal(const char *str, t_terminal *term) +{ + if (!ft_strcmp(str, "s") || !ft_strcmp(str, "source")) + *term = source; + else if (!ft_strcmp(str, "d") || !ft_strcmp(str, "drain")) + *term = drain; + else if (!ft_strcmp(str, "g") || !ft_strcmp(str, "gate")) + *term = gate; + else + return (0); + return (1); +} + +int parse_state(const char *str, t_state *state) +{ + if(!ft_strcmp(str, "on")) + *state = on; + else if (!ft_strcmp(str, "off")) + *state = off; + else if (!ft_strcmp(str, "pd") || !ft_strcmp(str, "pull_down")) + *state = pull_down; + else if (!ft_strcmp(str, "pu") || !ft_strcmp(str, "pull_up")) + *state = pull_up; + else if (!ft_strcmp(str, "f") || !ft_strcmp(str, "float") || !ft_strcmp(str, "floating")) + *state = floating; + else if (!ft_strcmp(str, "s") || !ft_strcmp(str, "short")) + *state = zkrat; + else if (!ft_strcmp(str, "u") || !ft_strcmp(str, "unknown")) + *state = unknown; + else + return (0); + return (1); +} + +int has_correct_argc(t_input input) +{ + t_command c; + size_t argc; + + c = input.command; + argc = input.argc; + if ((c == next || c == draw || c == addfet || c == help) && argc > 1) + return (0); + if (c == setnode && argc != 2) + return (0); + if (c == bind && argc != 3) + return (0); + if (c == addnode && argc > 2) + return (0); + return (1); +} + +static int str_is_num(const char *str) +{ + size_t i; + + i = 0; + while (ft_isdigit(str[i])) + ++i; + return (str[i] == '\0'); +} + +// maybe atos (alphanum to size_t) should be implemented +int parse_arg(t_input *input, const char *str, size_t i) +{ + const int is_num = str_is_num(str); + const size_t num_i = (size_t)ft_atoll(str); + const t_command c = input->command; + int res; + + res = 0; + if (is_num != 0 && (c == next || c == draw || (c == setnode && i == 0) + || (c == addfet && i == 1) || (c == addnode && (input->argc == 1 || i == 1)) + || (c == bind && i < 2))) + { + input->argv[i].val.num = num_i; + input->argv[i].type = num; + res = 1; + } + else if (!is_num) + { + if ((c == addnode && i == 0) || (c == setnode && i == 1)) + { + res = parse_state(str, &input->argv[i].val.state); + input->argv[i].type = state; + } + else if (c == addfet && i == 0) + { + res = parse_type(str, &input->argv[i].val.type); + input->argv[i].type = type; + } + else if (c == help) + { + res = parse_command(str, &input->argv[i].val.command); + input->argv[i].type = command; + } + else if (c == bind && i == 2) + { + res = parse_terminal(str, &input->argv[i].val.terminal); + input->argv[i].type = terminal; + } + } + return (res); +} + +int construct_input(t_input *input, char **split_inp) +{ + size_t i; + t_input tmp; + + tmp.argc = split_length(split_inp) - 1; + if (!parse_command(split_inp[0], &tmp.command)) + return (0); + if (!has_correct_argc(tmp)) + return (0); + i = 0; + while (i < tmp.argc) + { + if (!parse_arg(&tmp, split_inp[i + 1], i)) + return (0); + ++i; + } + *input = tmp; + return (1); +} + +int get_input(t_input *input) +{ + int res; + char *str_inp; + char **split_inp; + + str_inp = get_next_line(0); + if (!str_inp) + { + input->command = exitsim; + input->argc = 0; + return (1); + } + if (str_inp[0] == '\n') + return (1); + if (str_inp[0] && str_inp[ft_strlen(str_inp) - 1] == '\n') + str_inp[ft_strlen(str_inp) - 1] = '\0'; + split_inp = ft_split(str_inp, ' '); + res = construct_input(input, split_inp); + if (!res) + { + command_not_found(str_inp); + } + free(str_inp); + free_split(split_inp); + return (res); +} + +int process_input(t_vec *nodes, t_vec *mosfets) +{ + int res; + static t_input input = {.command = help, .argc = 0}; + + ft_printf("FET_sim>"); + if (!get_input(&input)) + return (1); + res = 1; + if (input.command == next) + res = c_next(input, nodes, mosfets); + else if (input.command == draw) + res = c_draw(input, nodes, mosfets); + else if (input.command == setnode) + res = c_setnode(input, nodes); + else if (input.command == addnode) + res = c_addnode(input, nodes); + else if (input.command == addfet) + res = c_addfet(input, mosfets); + else if (input.command == bind) + res = c_bind(input, nodes, mosfets); + else if (input.command == help) + res = c_help(input); + else if (input.command == exitsim) + res = 0; + return (res); +} + +int main(__attribute__((unused)) int argc, char **argv) +{ + t_vec nodes; + t_vec mosfets; + + print_start(); + ft_vec_init(&nodes, sizeof(t_node)); + ft_vec_init(&mosfets, sizeof(t_mosfet)); + build_graph(argv[1], &nodes, &mosfets); + while (process_input(&nodes, &mosfets)) + { + continue ; + } + update_nodes(NULL); + ft_vec_free(&nodes, free_node); + ft_vec_free(&mosfets, NULL); + return (0); +} diff --git a/src/sim_main.c b/src/sim_main.c new file mode 100644 index 0000000..14cc9b5 --- /dev/null +++ b/src/sim_main.c @@ -0,0 +1,38 @@ +#include "FET_sim.h" +#include "libft.h" + +static void update_mosfet(t_mosfet *mosfet) +{ + t_state state; + + state = mosfet->gate->state; + if (mosfet->type == p && state == on) + mosfet->is_opened = 1; + else if (mosfet->type == n && state == off) + mosfet->is_opened = 1; + else + mosfet->is_opened = 0; + return ; +} + +static void update_mosfets(t_vec *mosfets) +{ + size_t i; + t_mosfet *mosfet; + + i = 0; + while (i < mosfets->size) + { + mosfet = ft_vec_access(mosfets, i); + update_mosfet(mosfet); + ++i; + } + return ; +} + +int sim_step(t_vec *nodes, t_vec *mosfets) +{ + update_nodes(nodes); + update_mosfets(mosfets); + return (1); +} diff --git a/src/sim_node.c b/src/sim_node.c new file mode 100644 index 0000000..eee368e --- /dev/null +++ b/src/sim_node.c @@ -0,0 +1,86 @@ +#include "FET_sim.h" +#include "libft.h" +#include + +static t_node *get_neighbour_node(const t_mosfet *mosfet, const t_node *start) +{ + if (mosfet->source == start) + return (mosfet->drain); + return (mosfet->source); +} + +static void find_connected(t_node *node, t_vec *connected_nodes) +{ + size_t i; + t_node *neigh_node; + t_mosfet *mosfet; + + if (node->checked) + return ; + node->checked = 1; + ft_vec_append(connected_nodes, &node); + i = 0; + while (i < node->connected.size) + { + mosfet = *(t_mosfet **)ft_vec_access(&node->connected, i); + if (mosfet->is_opened) + { + neigh_node = get_neighbour_node(mosfet, node); + find_connected(neigh_node, connected_nodes); + } + ++i; + } + return ; +} + +static void reset_nodes(t_vec *nodes) +{ + size_t i; + t_node *node; + + i = 0; + while (i < nodes->size) + { + node = ft_vec_access(nodes, i); + node->checked = 0; + ++i; + } + return ; +} + +// passing NULL signals update_nodes should clean connected_nodes +// and should be called before end +// +// I don't know how irresponsible it is to let OS clear those things +// so I provide this mechanism. It may be removed in the future if +// it seems to be a reasonable decision. + +void update_nodes(t_vec *nodes) +{ + size_t i; + t_state state; + t_node *cur_node; + static t_vec connected_nodes = VEC_INIT(sizeof(t_node *)); + + if (!nodes) + { + free(connected_nodes.vec); + return ; + } + reset_nodes(nodes); + i = 0; + while (i < nodes->size) + { + cur_node = ft_vec_access(nodes, i); + if (!cur_node->checked) + { + find_connected(cur_node, &connected_nodes); + state = resolve_state(&connected_nodes); + apply_state(reduce_state(state), &connected_nodes); + ft_vec_forget_range(&connected_nodes, connected_nodes.size, 0); + } + ++i; + } + ft_vec_free(&connected_nodes, NULL); + return ; +} diff --git a/src/sim_state.c b/src/sim_state.c new file mode 100644 index 0000000..a9effb7 --- /dev/null +++ b/src/sim_state.c @@ -0,0 +1,86 @@ +#include "FET_sim.h" +#include "libft.h" + +// Monospace table of state resolution +// s2 \ s1 | short | off | on | pull_d | pull_u | float | unknown +// --------|-------|-------|-------|--------|--------|--------|--------- +// short | short | short | short | short | short | short | short +// --------|-------|-------|-------|--------|--------|--------|--------- +// off | short | off | short | off | off | off | off +// --------|-------|-------|-------|--------|--------|--------|--------- +// on | short | short | on | on | on | on | on +// --------|-------|-------|-------|--------|--------|--------|--------- +// pull_d | short | off | on | pull_d | pull_d | pull_d | pull_d +// --------|-------|-------|-------|--------|--------|--------|--------- +// pull_u | short | off | on | pull_d | pull_u | pull_u | pull_u +// --------|-------|-------|-------|--------|--------|--------|--------- +// float | short | off | on | pull_d | pull_u | float | float +// --------|-------|-------|-------|--------|--------|--------|--------- +// unknown | short | off | on | pull_d | pull_u | float | unknown +// +// It may be possible to construct the enum e_state in such a way that +// this function is easy arithmetics. + +t_state simple_resolve_state(t_state s1, t_state s2) +{ + if (s1 == s2) + return (s1); + if (s1 == zkrat || s2 == zkrat) + return (zkrat); + if ((s1 == off && s2 == on) || (s1 == on && s2 == off)) + return (zkrat); + if (s1 == on || s2 == on) + return (on); + if (s1 == off || s2 == off) + return (off); + if (s1 == pull_down || s2 == pull_down) + return (pull_down); + if (s1 == pull_up || s2 == pull_up) + return (pull_up); + if (s1 == floating || s2 == floating) + return (floating); + return (unknown); +} + +t_state resolve_state(t_vec *connected_nodes) +{ + size_t i; + t_state state; + t_node *node; + + i = 0; + state = unknown; + while (i < connected_nodes->size) + { + node = *(t_node **)ft_vec_access(connected_nodes, i); + state = simple_resolve_state(state, node->set_state); + ++i; + } + return (state); +} + +void apply_state(t_state state, t_vec *connected_nodes) +{ + size_t i; + t_node *node; + + i = 0; + while (i < connected_nodes->size) + { + node = *(t_node **)ft_vec_access(connected_nodes, i); + node->state = state; + ++i; + } + return ; +} + +t_state reduce_state(t_state state) +{ + if (state == pull_down) + return (off); + if (state == pull_up) + return (on); + if (state == unknown) + return (floating); + return (state); +} diff --git a/src/text.c b/src/text.c new file mode 100644 index 0000000..086351d --- /dev/null +++ b/src/text.c @@ -0,0 +1,124 @@ +#include "FET_sim.h" +#include "libft.h" + +static const char g_version_str[] = "0.0"; + +static const char g_next_help_str[] = "" + "next [STEPS]\n" + "Advances the simulation\n\n" + "STEPS\n" + "\tAdvances the simulation by STEPS number of steps.\n" + "\tDefaults to 1 when not included.\n\n"; + +static const char g_draw_help_str[] = "" + "draw [IND]\n" + "Draws the current state of the simulation.\n" + "IND\n" + "\tDraws the transistors with the index number IND.\n" + "\tDefaults to drawing every transistor.\n\n"; + +static const char g_setnode_help_str[] = "" + "setnode IND STATE\n" + "Sets the \"set_state\" of the node with index IND to state STATE.\n\n"; + +static const char g_addnode_help_str[] = "" + "addnode [STATE] [NUM]\n" + "Adds new nodes.\n" + "NUM\n" + "\tAdds NUM new nodes.\n" + "\tDefaults to 1.\n\n" + "STATE\n" + "\tSets \"set_state\" of new nodes to STATE.\n" + "\tDefaults to unknown state.\n\n"; + +static const char g_addfet_help_str[] = "" + "addfet TYPE [NUM]\n" + "Adds new transistors of type TYPE.\n" + "NUM\n" + "\tAdds NUM new transistors.\n" + "\tDefaults to 1.\n\n"; + +static const char g_bind_help_str[] = "" + "bind NODE FET TERMINAL\n" + "Binds node with index NODE to the TERMINAL of transitor indexed by FET.\n" + "Possible values for TERMINAL are gate, source and drain.\n\n"; + +static const char g_help_help_str[] = "" + "help [COMMAND]\n" + "Prints a simple explanation.\n" + "COMMAND\n" + "\tPrints explanation of COMMAND.\n" + "\tWhen no COMMAND is provided, the general help with list of commands is shown.\n\n"; + +static const char g_help_exit_str[] = "" + "exit [...]\n" + "Exits FET_sim. One may also use ctrl-D.\n" + "[...]\n" + "\tAnything after the command is ignored.\n\n"; + +static const char g_general_help_str[] = "" + "This is a FET_sim - simulator of FET (Field Effect Transistor) logic.\n" + "Version number: %s" + "You can use the following commands:\n" + "next [STEPS] \t\t- advances the simulation\n" + "draw [IND] \t\t- draws the state of the simulation\n" + "setnode IND STATE \t- sets the \"set_state\" of the node indexed by IND to STATE\n" + "addnode [STATE] [NUM] \t- adds new nodes\n" + "addfet TYPE [NUM] \t- adds new FETs\n" + "bind NODE FET TERMINAL \t- binds node indexed by NODE to TERMINAL\n \ + \t\t\t of transistor indexed by FET\n" + "help [COMMAND] \t\t- shows this help or help for COMMAND\n" + "exit [...] \t\t- exits this program\n\n"; + +void print_help(t_command c) +{ + if (c == next) + ft_printf(g_next_help_str); + else if (c == draw) + ft_printf(g_draw_help_str); + else if (c == setnode) + ft_printf(g_setnode_help_str); + else if (c == addnode) + ft_printf(g_addnode_help_str); + else if (c == addfet) + ft_printf(g_addfet_help_str); + else if (c == bind) + ft_printf(g_bind_help_str); + else if (c == help) + ft_printf(g_help_help_str); + else if (c == exitsim) + ft_printf(g_help_exit_str); + else + ft_printf(g_general_help_str, g_version_str); + return ; +} + +void command_not_found(const char *input) +{ + ft_printf("The command \"%s\" is not a proper FET_sim command.\n", input); + return ; +} + +void print_start(void) +{ + ft_printf("FET_sim, version %s\n" + "FET_sim is a simulator of FET logic.\n" + "If you need some guidence, use the \"help\" command.\n", + g_version_str); + return ; +} + +void print_index_error(size_t index, size_t size) +{ + if (size > 0) + { + ft_printf("This action is invalid as given index %u " + "is larger then the highest index present %u.\n", + index, size - 1); + } + else + { + ft_printf("This action is invalid as there is no element yet.\n"); + } + return ; +} -- 2.30.2