From 3535c42fd8707295d7685217765152095afd5433 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Luk=C3=A1=C5=A1=20Ji=C5=99i=C5=A1t=C4=9B?= Date: Sat, 13 Jan 2024 11:55:36 +0100 Subject: [PATCH] Start this project for simulating FET based logic Add a small project capable(?) of simulating FET logic. Implement basic structs and logic for the simulation. Implement depicting of the simulation state. Add submodule Libft for use in place of (most of) standard library. - I develop this project for other reasons. - This is an added challenge for learning's sake. Add basics of project management (Makefile, .gitignore). --- .gitignore | 3 + .gitmodules | 3 + Libft | 1 + Makefile | 45 +++++++ main.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 430 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 160000 Libft create mode 100644 Makefile create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b4d162e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +FET_sim +*.[oa] +*.swp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..626d139 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Libft"] + path = Libft + url = git://ljiriste.work/Libft diff --git a/Libft b/Libft new file mode 160000 index 0000000..2447a14 --- /dev/null +++ b/Libft @@ -0,0 +1 @@ +Subproject commit 2447a14f38be8e2de8f3984dc708800b36f36c98 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dbc9185 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +CC := gcc +CFLAGS = -std=c99 -Wall -Wextra -Werror -Wpedantic + +RM := rm -f + +SUBPROJECTS := Libft + +INCDIR := . +INCDIR += $(addsuffix /inc, $(SUBPROJECTS)); +INCLUDE := $(addprefix -I, $(INCDIR)) + +SOURCES := main.c +OBJECTS := $(SOURCES:.c=.o) + +NAME := FET_sim + +all : $(NAME) + +debug : CFLAGS += -g +debug : $(NAME) + +$(NAME) : $(OBJECTS) Libft/libft.a + $(CC) $(CFLAGS) -o $@ $^ + +Libft/libft.a : | Libft/Makefile +ifneq (,$(findstring debug, $(MAKECMDGOALS))) + $(MAKE) -C Libft debug +else + $(MAKE) -C Libft +endif + +%.o : %.c + $(CC) $(CFLAGS) -o $@ -c $< $(INCLUDE) + +%/Makefile : + git submodule update --init $($@%/Makefile=%) + +clean : + $(RM) $(OBJECTS) + +fclean : clean + $(RM) $(NAME) + +re : fclean + $(MAKE) all diff --git a/main.c b/main.c new file mode 100644 index 0000000..aea46bb --- /dev/null +++ b/main.c @@ -0,0 +1,378 @@ + +#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); +} -- 2.30.2