Start this project for simulating FET based logic
authorLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Sat, 13 Jan 2024 10:55:36 +0000 (11:55 +0100)
committerLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Sat, 13 Jan 2024 10:55:36 +0000 (11:55 +0100)
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 [new file with mode: 0644]
.gitmodules [new file with mode: 0644]
Libft [new submodule]
Makefile [new file with mode: 0644]
main.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..b4d162e
--- /dev/null
@@ -0,0 +1,3 @@
+FET_sim
+*.[oa]
+*.swp
diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..626d139
--- /dev/null
@@ -0,0 +1,3 @@
+[submodule "Libft"]
+       path = Libft
+       url = git://ljiriste.work/Libft
diff --git a/Libft b/Libft
new file mode 160000 (submodule)
index 0000000..2447a14
--- /dev/null
+++ b/Libft
@@ -0,0 +1 @@
+Subproject commit 2447a14f38be8e2de8f3984dc708800b36f36c98
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
index 0000000..aea46bb
--- /dev/null
+++ b/main.c
@@ -0,0 +1,378 @@
+
+#include "libft.h"
+#include <stdlib.h>
+
+// 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);
+}