Migrating notes from Notion - Initial stage

This commit is contained in:
2025-02-14 16:56:31 +00:00
parent 8e3b07730b
commit 2c6d0e104d
167 changed files with 39800 additions and 1 deletions

View File

@@ -0,0 +1,165 @@
---
Status: Ready
Created by: Trude EH
tags:
- computer-science
- notes
author: TrudeEH
draft: false
searchHidden: false
showToc: true
title: CPU Architecture
---
## Components
### Registers
We can combine registers to reduce the amount of wires needed.
![[image8.png]]
Using a data bus (wiring at the top) and a binary decoder, we can select which register to read/write to.
### Memory
![[image9.png]]
## Assembly
Assembly is a human-friendly representation of code: binary values that a computer can understand.
![[image10.png]]
An assembler converts ASM instructions into machine code, which is given to the CPU as input.
### Arithmetic Operations
For example, a simple computer architecture could use `00` to represent arithmetic operations.
![[image11.png]]
To decide which type of operation to execute (subtraction, multiplication, addition, etc), the 3rd and 4th bits could be used.
![[image12.png]]
Using a [[binary-operations/index]], we can build an inefficient, but simple circuit to do this.
![[image13.png]]
This type of circuit is an Arithmetic Logic Unit (ALU).
### Memory Operations
Of course, assembly can also provide instructions to store or load values.
![[image14.png]]
#### Load
```Assembly
LOAD R2 1000 ;Load into register 2 the value in the memory address 1000
```
![[image15.png]]
#### Store
```Assembly
STORE R1 0110 ;Store the value in register 1 into the 0110 memory address
```
![[image16.png]]
#### Select Which Instruction to Execute (first 2 bits)
To decide which operation to execute, a binary decoder can be used.
![[image17.png]]
For memory operations, the 3rd and 4th bits are used to select which register to use.
![[image18.png]]
The last 4 bits represent the memory address to read/write to.
![[image19.png]]
### Instruction Register
For the instruction to be given, it is stored in a special register: An Instruction Register.
![[image20.png]]
### Optimization
We can use a single Binary Decoder instead of two, to achieve the same result. (Optimization on the right pane)
![[image21.png]]
Different architectures can have the exact same functionality, while being implemented differently, or even having different instructions. This is why code that is compiled for Intel x64 is not compatible with ARM or RISC-V.
## Control Unit
We can finally add the ALU (Arithmetic Logic Unit) we built before into the new circuit, like so:
![[image22.png]]
The gray trapezoids are multiplexers:
![[image23.png]]
The output value is then stored in a temporary register, before replacing the first operand register's value.
The component we just built to control the `ALU` is part of a `Control Unit`. The full `control unit` is very complex, as it needs to handle every possible instruction. (So far, we have seen how to implement the `ALU` and `RAM`.)
![[image24.png]]
Each register in the `CU` has a specific purpose, unlike `RAM`, which can be used to store any values.
![[image25.png]]
To read the first instruction, the `CU` will **fetch** data from the first address in memory.
![[image26.png]]
After **fetching**, the `CU` will **decode** the instruction: interpret the bit sequence in the `instruction register`, to send the necessary signals to the components that will **execute** the instruction. We can finally load instructions into the instruction register.
![[image27.png]]
Then, the `CU` increments 1 byte, to point the `address register` to the next instruction. (Modern architectures increment different values, as the instruction set is more complex)
If the instruction is an arithmetic operation, the steps are similar. The ALU stores the output in a temporary register, which overwrites the register 0 with the result. The result can then be stored in `RAM`.
![[image28.png]]
## Load a Program Into Memory
So far, we can store instructions in memory, but it is also necessary to store values, besides from the instructions themselves.
For example:
![[image29.png]]
This program uses 2 numeric values. The first 2 instructions load these values into the registers, and then, these values are added together and stored in another memory address. The final instruction, `HALT`, marks the end of the program, to make sure the `CU` does not attempt to read the number 20 as an instruction.
If the program is extended, all memory addresses must be altered. To fix this issue, we can instead store values at the end of the memory stack.
![[image30.png]]
## Conditions and Loops
To create a loop, we can simply jump to a smaller address in memory.
![[image31.png]]
Internally, the `JMP` command overwrites the Address Register, making it so that the next CPU **cycle** *fetches* the chosen memory address, instead of the next one.
![[image32.png]]
### Flags
Sometimes, we might want to loop only if a certain condition is met.
For context, imagine subtracting a number from itself. In this case, the ALU will provide some extra information, using 1 bit registers called `flags`.
![[image33.png]]
| | | |
|---|---|---|
|0|**O**verflow|When a number is too large to fit in the output register.|
|1|**Z**ero|When the result is zero.|
|0|**N**egative|When a number is negative.|
This additional information can be used to make decisions, and make **conditional jumps** possible.
| | | |
|---|---|---|
|`JMP_OFW XXXX`|Jump Overflow|Overwrites the `Address Register` with the value `XXXX` if the `O_FLAG` is **ON**. If the flag is **OFF**, the `Address Register`'s value is incremented by **1**.|
|`JMP_ZRO XXXX`|Jump Zero|Overwrites the `Address Register` with the value `XXXX` if the `Z_FLAG` is **ON**. If the flag is **OFF**, the `Address Register`'s value is incremented by **1**.|
|`JMP_NEG XXXX`|Jump Negative|Overwrites the `Address Register` with the value `XXXX` if the `N_FLAG` is **ON**. If the flag is **OFF**, the `Address Register`'s value is incremented by **1**.|
|`JMP_ABV XXXX`|Jump Above|Overwrites the `Address Register` with the value `XXXX` if **neither** the `Z_FLAG` nor `N_FLAG` are **ON**. If either is **ON,** the `Address Register`'s value is incremented by **1**.|
Comparing two numbers is the same as subtracting them.
$$a - 5 = b$$
| | | |
|---|---|---|
|**b** is negative|**b** is zero|**b** is positive|
|then|then|then|
|a < 5|a == 5|a > 5|
For example:
![[image34.png]]
An `IF` statement works in the exact same way, but without the need to loop:
![[image35.png]]
Note: These instructions are not from any real architecture. These are examples for this simple, custom architecture.
## Clock
The final piece of the puzzle is the clock. A clock can give us time before a circuit loops.
![[image36.png]]
This is necessary, because energy travels extremely quickly, and so, all memory would be reset before we could even use the stored values. Each clock tick corresponds to an action the `CU` performs (fetch, decode and execute).
A `Data FLIP-FLOP`, for example, uses the clock to store data, acting as the manual `RESET` input.
![[image37.png]]
This circuit can be used to build a single bit register.
![[image38.png]]
To generate a clock pulse, we can use a circuit similar to this one:
![[image39.png]]

View File

@@ -0,0 +1,324 @@
---
Status: Ready
Created by: Trude EH
tags:
- notes
- programming
- web
author: TrudeEH
draft: false
searchHidden: false
showToc: true
title: Databases [SQL]
---
## Flat-File Databases
A "table" written into a single file. The most common file type for this purpose is `CSV`.
The `CSV` format reads each line as a row, and each comma-separated value as a column.
The first row on a `CSV` file is used to describe the data in each column. If a `,` is present on the dataset, surround that entry with `"` to 'escape' it.
These files can be read and written to using languages like [[c-language]] and [[python]].
## Relational Databases
Instead of using a single table, a relational database can store data in multiple tables, and then define relationships between them.
Each table must have one column with an unique key that identifies each row.
![[image94.png]]
### Relationships
#### One-to-one Relationship
In this example, `id` in `shows` corresponds to the `show_id` in the `ratings` table.
#### One-to-many Relationship
`shows` has a one-to-many relationship with `genres`, because a single show entry can have many genders.
#### Many-to-many Relationship
Both the `people` and `writers` table have a field shared with `stars`.
## SQL
`SQL` is a language designed specifically for interfacing with relational databases.
To use `SQL`, a database is needed, so, for this example, I will use `sqlite3`.
### Create a Database
```Shell
sqlite3 name.db # Create a db file and initialize it.
```
### `sqlite3` Commands
#### Import a `CSV` Table
```SQL
.mode csv
.import name.csv table_name
```
#### General Commands
```SQL
.schema -- Print all tables and fields (using the commands used for creation)
.schema table -- Show the command used for creating a table
.exit
```
### Base Syntax
```SQL
CREATE TABLE table (column type, ...); -- Create a new table
SELECT columns FROM table; -- Output/Print data
INSERT INTO table (column, ...) VALUES(value, ...); -- Add data
UPDATE table SET column = value WHERE condition; -- Update values
DELETE FROM table WHERE condition; -- Delete data
```
> [!important] In `SQL`, there is **NO WAY** to undo actions. Especially when writing or deleting from the database, do not type `;` unless you know exactly what you are doing!
#### Wildcard
```SQL
SELECT * FROM table; -- Outputs every column in the table (wildcard selector)
```
### Functions
#### Math Functions
- `AVG`
- `COUNT`
- `DISTINCT`
- `LOWER`
- `MAX`
- `MIN`
- `UPPER`
- `LOWER`
- `…`
```SQL
SELECT COUNT(*) FROM table; -- Counts the number of rows in a table
SELECT DISTINCT column from table; -- Show only the unique values in a column
SELECT COUNT(DISTINCT column) FROM table; -- Count the unique values in a column
```
#### Logic Functions
- `GROUP BY`
- `LIKE`
- `LIMIT`
- `ORDER BY`
- `WHERE`
- ``
```SQL
-- Count every instance of a value in a column
SELECT COUNT(*) FROM table WHERE column = 'string';
-- LIKE is used to select using formatting. '%' selects every character after)
SELECT * FROM favorites WHERE prog_language = 'C' AND problem LIKE "Hello, %"
-- Group all individual rows and display their count
SELECT prog_language, COUNT(*) FROM favorites GROUP BY prog_language;
-- Sort values by their count, ascending.
SELECT prog_language, COUNT(*) FROM favorites GROUP BY prog_language ORDER BY COUNT(*);
-- Sort values by their count, descending.
SELECT prog_language, COUNT(*) FROM favorites GROUP BY prog_language ORDER BY COUNT(*) DESC;
-- Limit the output to a single row (showing the most popular language, in this case)
SELECT prog_language, COUNT(*) FROM favorites GROUP BY prog_language ORDER BY COUNT(*) DESC LIMIT 1;
```
#### Operators
- `AND`
- `OR`
```SQL
-- Using the AND operator to select two values
SELECT * FROM table WHERE column1 = 'a' AND column2 = 'b';
-- AND and OR (' is escaped using '' (' twice))
SELECT * FROM table WHERE prog_language = 'C' AND (problem = 'Hello, World' OR problem = 'Hello, It''s Me');
```
#### Aliases
- `AS`
```SQL
-- The column COUNT(*) will be renamed to 'n'.
SELECT prog_language, COUNT(*) AS n FROM favorites GROUP BY prog_language ORDER BY n DESC;
```
#### Conditions
- `IS`
```SQL
-- Delete all values where timestamp1 is a NULL value.
DELETE FROM favorites WHERE timestamp1 IS NULL;
```
### Data Types
- `BLOB`
- `INTEGER`
- `NUMERIC`
- `REAL`
- `TEXT`
- `NULL`
- `NOT NULL`
- `UNIQUE`
- `PRIMARY KEY`
- `FOREIGN KEY`
### Relationships
- `IN`
- `JOIN`
#### One-to-one
```SQL
-- 'shows' table
CREATE TABLE shows (
id INTEGER,
title TEXT NOT NULL,
year NUMERIC,
episodes INTEGER,
PRIMARY KEY(id)
);
-- Table connected with a one-to-one relationship with the 'shows' table
CREATE TABLE ratings (
show_id INTEGER NOT NULL,
rating REAL NOT NULL,
votes INTEGER NOT NULL,
FOREIGN KEY(show_id) REFERENCES shows(id)
);
-- Lists 'show_id', but not the actual names of each show.
SELECT show_id FROM ratings WHERE rating >= 6.0 LIMIT 10;
-- Executes the nested query first, then shows the entries selected on 'shows'
SELECT * FROM shows WHERE id IN
(SELECT show_id FROM ratings WHERE rating >= 6.0)
LIMIT 10;
-- Join both tables
SELECT title, rating FROM shows JOIN
ratings ON shows.id = ratings.show_id WHERE rating >= 6.0
LIMIT 10;
```
#### One-to-many
- `ON`
```SQL
CREATE TABLE genres (
show_id INTEGER NOT NULL,
genre TEXT NOT NULL,
FOREIGN KEY(show_id) REFERENCES shows(id)
);
-- Search for all genres for a show
SELECT genre FROM genres WHERE show_id =
(SELECT id FROM shows WHERE title = 'TitleOfShow');
-- Join tables, to show title alongside genres of a show
SELECT title, genre FROM shows JOIN genres ON shows.id =
genres.show_id WHERE id =
(SELECT id FROM shows WHERE title = 'TitleOfShow');
```
#### Many-to-many
![[image95.png]]
```SQL
-- Select every person who starred in a show
SELECT name FROM people WHERE id IN
(SELECT person_id FROM stars WHERE show_id =
(SELECT id FROM shows WHERE title = 'Some Name'));
-- Joined table with the show name and stars
SELECT title FROM shows JOIN people.name WHERE id IN
(SELECT person_id FROM stars WHERE show_id =
(SELECT id FROM shows WHERE title = 'Some Name'));
-- Another way to join tables
SELECT title FROM shows, stars, people
WHERE shows.id = stars.show_id
AND people.id = stars.person_id
AND name = 'Name';
```
### Indexes
Load an index of the database into RAM to optimize searches.
The underneath algorithm is a `B-Tree`, which takes up more space in memory and slightly slows write speed on the database.
```SQL
CREATE INDEX name ON table (column, ...);
.timer ON -- sqlite3 command to show how long operations take to complete
SELECT * FROM shows WHERE title = 'Name'; -- 0.043s
CREATE INDEX title_index ON shows(title); -- Index title on shows
SELECT * FROM shows WHERE title = 'Name'; -- 0.001s
SELECT name FROM people WHERE id IN
(SELECT person_id FROM stars WHERE show_id =
(SELECT id FROM shows WHERE title = 'Some Name')); -- 0.215s
CREATE INDEX name_index ON people(name);
CREATE INDEX person_index ON stars(person_id);
SELECT name FROM people WHERE id IN
(SELECT person_id FROM stars WHERE show_id =
(SELECT id FROM shows WHERE title = 'Some Name')); -- 0.001s
```
### Race Conditions
When `SQL` is integrated with languages such as `Python`, for example, or is being accessed by multiple instances, race conditions may arise.
For example, consider the following code:
```Python
...
rows = db.execute("SELECT likes FROM posts WHERE id = ?", id);
likes = rows[0]["likes"]
db.execute("UPDATE posts SET likes = ? WHERE id = ?", likes + 1, id);
```
If this code is executed twice at the same time, instead of adding 2 likes to the database, only one will be added, because the program would read the database in the same state, and then add +1 like to that same, previous state.
`SQL` provides solutions to this in the form of **transactions**:
- `BEGIN TRANSACTION`
- `COMMIT`
- `ROLLBACK`
On `Python`, a solution could be:
```Python
db.execute("BEGIN TRANSACTION")
rows = db.execute("SELECT likes FROM posts WHERE id = ?", id);
likes = rows[0]["likes"]
db.execute("UPDATE posts SET likes = ? WHERE id = ?", likes + 1, id);
db.execute("COMMIT")
```
Where the database would be "locked" while the program ran.
### `SQL` Injection Attacks
If a program asks for user input, and that input is then passed over to the database, the user could write special `SQL` syntax to break the query.
For example:
If a program takes an email address as input, some user could type: `email@example.com'--`, which marks a comment.
If the query was similar to the following:
```Python
rows = db.execute(f"SELECT * FROM users WHERE email = '{email}' AND password = {psk}")
```
Replacing values…
```Python
rows = db.execute(f"SELEC * FROM users WHERE email = 'email@example.com'--' AND password = 'password123'")
```
Which would result in the user being able to log in without needing a password.
The solution to this is to use a library which uses placeholders to insert data in queries.
```Python
rows = db.execute("SELECT * FROM users WHERE email = ? AND password = ?", email, psk)
```

View File

@@ -0,0 +1,18 @@
---
Status: Planned
Created by: Trude EH
tags:
- notes
- tools
author: TrudeEH
draft: false
searchHidden: false
showToc: true
title: Debug/Repair Tools
---
Scrcpy
scrcpy —otg
scrcpy
ADB
adb kill-server

View File

@@ -0,0 +1,70 @@
---
Status: Ready
Created by: Trude EH
tags:
- notes
- programming
author: TrudeEH
draft: false
searchHidden: false
showToc: true
title: Debugging [GDB]
---
## GDB Debugging
### Compile with Debug Information
To allow `gdb` access to the source code (Provides debug symbols - Do not share publicly as it contains the source code).
```Shell
gcc -g <file>
```
### Look for / Fix Bugs
First, initialize `gdb` with the executable to debug.
```Shell
gdb ./<executable> --tui
```
After `gdb` is ready, we can use the following commands:
|Command|Description|
|---|---|
|`lay next`|Switch to the next layout (Enables TUI mode if disabled - Allows for reading the code while debugging both in `C` and `ASM`).|
|`ref`|Refresh (if a program prints to the terminal, it can break `gdb`'s interface).`|
|`q`|Quit `gdb`.|
|||
|`b main`|Add a breakpoint at the main function.|
|`b`|Place a breakpoint at the current line.|
|`b <N>`|Place a breakpoint at line `N`.|
|`b +<N>`|Place a breakpoint N lines down.|
|`b <fn>`|Place a breakpoint at `fn` function.|
|`d`|Delete all breakpoints.|
|`d <N>`|Delete breakpoint number `N`.|
|`clear <fn>`|Clear the breakpoint set to `fn` function.|
|||
|`n`|Execute up to the next line in `C`. If a function call is found, execute the function completely.|
|`s`|Execute up to the next line in `C`. (Jump over)|
|`s <N>`|Run `N` lines.|
|`u`|Same as `n`, but if in a loop, execute until the loop exits.|
|`nexti`|Execute up to the next instruction (line in `ASM`).|
|`r`|Run the program until a breakpoint or error is reached.|
|`c`|Continue running the program until a breakpoint or error is reached.|
|||
|`x/i $pc`|Examine the previous instruction (View memory).|
|`info registers`|Read the CPU registers used by the program.|
|`bt`|See the call stack up to the current line. (How we got here, so to speak)|
|`print sizeof(<variable>)`|Check the size of a struct/variable/pointer.|
|`p <var>`|Print variable `var` value.|
|`info break`|List breakpoints.|
## Check for Memory Leaks
Use `valgrind` to check for lost memory.
```Shell
valgrind --leak-check=full ./<executable>
```

View File

@@ -0,0 +1,109 @@
---
Status: Ready
Created by: Trude EH
tags:
- electronics
- notes
author: TrudeEH
draft: false
searchHidden: false
showToc: true
title: Diodes
---
A diode allows current to only flow in one direction in a circuit.
## Schematic
```Plain
Anode (+) --|>|-- Cathode (-)
```
## Examples
```Plain
[Conventional Current (+) -> (-)]
(+)------|>|------(-) Current can flow - The diode is now a conductor.
(+)------|<|------(-) Current can't flow - The diode is now an insulator.
```
## Use Cases
- Protect a circuit (if a battery is connected incorrectly, for example)
- Convert AC to DC current
Fun fact: An LED, for example, is a Light-Emitting Diode.
## How a Diode Works
### Conductors and Insulators
An atom contains the following elements:
- Nucleus (Protons - Neutrons)
- Orbital Shells (Holds the electrons, which orbit around the nucleus)
- Conduction band
The electrons closest to the nucleus hold the most energy.
The outermost shell is the valence shell. A conductor has 1-3 electrons in the valence shell.
If an electron reaches the conduction band, it can break free and move to another atom.
An insulator, however, has a conduction band that is far from the valence shell, making it difficult for an electron to escape.
For example, for copper (a great conductor), the valence shell and conduction band overlap, so it's very easy for an electron to jump between atoms.
Semiconductors have a conduction band close to the valence shell, but have one extra electron in it, making it an insulator. However, given some external energy, some electrons will gain enough energy to reach the conduction band and become free.
### P-Type and N-Type Doping
Silicon is a good semiconductor, having 4 electrons in its valence shell. When close to other `Si` atoms, they share 4 electrons with their neighbors, thus, having 8, each, and becoming stable.
```Plain
Silicon:
Si Si Si Si Si Si Si Si Si Si Si
Si Si Si Si Si Si Si Si Si Si Si
Si Si Si Si Si Si Si Si Si Si Si
Si Si Si Si Si Si Si Si Si Si Si
Si Si Si Si Si Si Si Si Si Si Si
Si Si Si Si Si Si Si Si Si Si Si
```
#### N-Type
Some Phosphorus is added to the Silicon. ==`p`== has one extra electron in its valence shell.
These electrons are not needed, and so, they flow freely from atom to atom.
```Plain
Si Si p Si Si Si Si Si Si Si p
p Si Si Si Si p Si Si Si Si Si
Si Si Si p Si Si Si Si p Si Si
Si p Si Si p Si Si Si Si Si Si
Si Si Si Si Si Si p Si Si p Si
Si p Si Si Si Si Si Si p Si Si
```
#### P-Type
Some Aluminum is added to the Silicon. `Al` is missing one electron, so it can't provide its 4 neighbors with an electron to share.
```Plain
Si Si Al Si Si Si Si Si Si Si Al
Al Si Si Si Si Al Si Si Si Si Si
Si Si Si Al Si Si Si Si Al Si Si
Si Al Si Si Al Si Si Si Si Si Si
Si Si Si Si Si Si Al Si Si Al Si
Si Al Si Si Si Si Si Si Al Si Si
```
### Combining both Types
When an N-Type is combined with a P-Type, some electrons from the N-Type side will move over to the P-Type side and occupy the missing electrons there. This creates a barrier between both types, creating an electric field that prevents more electrons from switching sides.
#### Forward Bias
If energy is provided to the Cathode, the electrons flow, as the voltage is superior to the barrier's.
```Plain
(-)-----[P|N]-----(+)
```
#### Reverse Bias
If energy is provided to the Anode, the electrons can't flow, as the barrier expands.
```Plain
(-)--[P] [N]--(+)
```

View File

@@ -0,0 +1,13 @@
---
Status: Planned
Created by: Trude EH
tags:
- notes
- programming
- web
author: TrudeEH
draft: false
searchHidden: false
showToc: true
title: JavaScript
---

View File

@@ -0,0 +1,199 @@
---
Status: In progress
Created by: Trude EH
tags:
- computer-science
- notes
- os
author: TrudeEH
draft: false
searchHidden: false
showToc: true
title: Linux Architecture
---
## Kernel
Linux is a kernel: the core of an operative system. OSes that use the Linux kernel are called Linux Distros (Distributions).
A Kernel does the following:
- Executes first when the computer boots up and has full access to the hardware.
- Implements drivers to control peripherals, network devices and other resources.
- Runs other programs (userland software) and allows them to communicate with each other and with the hardware.
### Syscalls
To "ask" the kernel to perform a hardware task, or to access the file system or other resources, a program executes a syscall.
For example (x64 assembly):
```Assembly
// sys_write (Print to stdout)
mov rax, 1
mov rdi, 1
lea rsi, [hello_world]
// Buffer length
mov rdx, 14
syscall
```
This snippet implements a syscall that prints text to `stdout`, usually a terminal window.
### Processes
A program is an executable containing machine code. When a computer executes a program, it is first loaded into memory.
![[image5.png]]
A program loaded in memory is a process.
> [!important] Note: For interpreted languages, the interpreter creates a process that executes the code directly.
### Modules
## Devices
### Device Drivers
Once a new device is plugged in, it attempts to call the Kernel, which identifies that device. The Kernel then loads the appropriate driver. Drivers are Kernel Modules used to interact with hardware. Once the required module is loaded, the Kernel calls the `udevadm` program, that creates a device file in the `/dev` directory.
Whenever there is a read/write operation to that device, the Kernel intercepts the request and calls the driver function instead, which implements that operation, and this is why a driver must implement all possible file operations.
Not all devices control hardware. For example, `/dev/random` generates a random number.
In the Linux Kernel, there are **Character Type Devices** and **Block Type Devices.**
A Character Device provides an endless stream or characters that can be read one at a time. This includes a keyboard and sensors, for example. Block Devices provide data as blocks of a defined size. These include disks and USB drives.
The only exceptions are Network Devices. Network data cannot be manipulated with file operations, so they are handled differently in the kernel.
### Network Devices
If a network card is plugged in, like any other device, it communicates with the Kernel, and the Kernel loads the appropriate Kernel Module that contains the driver. After that, the driver adds new entries to the Kernel's `NICs`, which are data structures stored in memory. The driver then creates configuration files in the `/sys/class/net/` directory. These are not device files, just configuration files. Different network cards can have multiple network interfaces, and even multiple ports to connect to an Ethernet cable, for example. Each interface gets its own folder, as they can have different configurations. Editing these files can change device configurations, but the only way to actually use these interfaces is by calling the Kernel directly. The Kernel can, in turn, create a virtual file in memory, which is then passed as an ID to the application. The application still receives it as a regular file ID (File Descriptor), like with any other device, but it works differently from the Kernel's perspective.
A GPU works similarly, and although the Kernel exposes these devices as files, they are not real files in the filesystem, as doing so would slow them down immensely.
### GPUs
At the startup time, a device file is generated for the GPU, like any other device.
When an application attempts to use the GPU, it first searches for a **Graphics API** to use with it. Examples include Vulkan, OpenGL and DirectX.
These APIs are code functions that forward the requests to a library such as `Mesa`.
`Mesa` then calls the Kernel's DRM (Direct Rendering Engine), which then calls the GPU driver to provide GPU capabilities.
The GPU still has a device file, which is used by the Kernel's DRM and Mesa, but most commands are delivered to the GPU driver directly.
## File Systems
> [!important] This section is heavily simplified and only covers `EXT2-4`.
### Concepts
- An `inode` provides the following information:
- Pointer to the file
- Creation date / Modified times
- Permissions
- A `directory (table)` contains the data before the current directory, the directory itself, and every file inside that directory.
- A `block` is the standard data unit for data in a hard drive. (Same size as memory pages. Ex `x86` CPU would use `4 KB` as the block size.)
### EXT2
Uses linked lists to store and lookup data, to keep the implementation of the filesystem itself as simple as possible. A simple filesystem makes it easier to repair (or skip) broken sectors on the hard drive.
#### Partition Layout
![[EXT2.png]]
### EXT3
#### Journal
`EXT3` implements a journal to act as a buffer after a crash. If any operation in the journal fails, because it was logged, the filesystem is able to recover and finish any pending operations quickly, and not lose data. `EXT2` had another issue, where if an opened directory were deleted, its `inode` wouldn't be deleted, leaving an orphaned, empty `inode` on the filesystem. If the program holding it was to be closed, the `inode` would be deleted, but in the event of a crash, the `inode` would be left in the filesystem, with no way to be freed.
#### HTrees
`EXT3` can also use a [[algorithms-and-data/index]] instead of a linked list to store directory entries, making lookup times much faster. To build the HTree, all filenames are hashed and ordered, making the implementation more complex. This feature is disabled by default.
#### Scalability
Before, only one core could write to the *superblock* at a time, but `EXT3` updates `inode` and `block` count at the *block group descrip_t_or* level. The superblock is only updated through a system call: `statfs()`, or if the filesystem is unmounted.
`EXT3` also removed *big kernel locks* (deprecated feature that added the ability to freeze the kernel), and `sleep_on()`, which was replaced with `wait_event()`, preventing infinite loops.
These patches improved multicore performance by over 10x.
#### Preallocation / Reservation
Writing two files simultaneously can create noncontinuous space.
![[image6.png]]
Because `EXT3` was designed to be used with HDDs, and separate portions of a file would slow down read speeds, `EXT3` implemented a preallocation/reservation system.
Inside the block bitmap, a few extra blocks were preallocated, storing both files in separate locations.
![[image7.png]]
Instead of `EXT2`, where errors were corrected directly in the hard drive, `EXT3` reserves space for each specific `inode` in memory. In the event of a crash, all data would be stored in memory, and thus, not corrupting the HDD itself.
#### Online Resizer
`EXT3` also implements a protocol to support `LVM`, which allows for many disks to be used as a single partition. The largest possible space `EXT3` supports without patches is 16 GB.
#### Partition Layout
![[EXT3.png]]
### EXT4
#### Larger FS
`EXT3` can only support up to 16 TB. This is why `EXT4` was created.
Instead of ==32 bits== capacity to count blocks, `EXT4` divides each entry in the block descriptor table in two parts: An upper, and a lower entry. This lower entry extends the upper one, and since each supports up to ==32 bits==, the total supported block count (in the block descriptor table) rises to ==64 bits== (16 TB → 1,000,000,000 TB).
#### Extents
Instead of using block mapping (the filesystem allocates blocks individually for each file), which can lead to fragmentation, `EXT4` uses **extents**, a range of contiguous blocks, allocated to each file.
This uses a 48 bit system, which limits the FS capacity to 1 EB (1,000,000 TB).
Each extent can point to 128 MB of data, or 1 block group.
#### Compatibility
The `EXT4` driver supports `EXT3` as well, and so, the Linux kernel only uses the `EXT2` and `EXT4` drivers. The `EXT3` driver was removed as the new one is more performant.
#### HTrees
HTrees are now enabled by default, allowing up to 10 million subdirectories. However, `EXT4` implements a Three Level HTree, which can be enabled using the `large_dir` flag, and extends this limit to 2 Billion subdirectories.
#### Fast FS Check
The `big_itable_unused` field was added to the block descriptor table, allowing for fast filesystem checks and error correction, as well as some other improvements.
#### Multiblock Allocation
Previously, each block needed one call to be allocated. `EXT4` added support for multi-block allocation, which means that only one call is needed to allocate multiple blocks.
#### Delayed Allocation
Every write command is delayed for as long as possible, making it so that changes can be made in memory before they affect (and possible fragment) the actual drive.
#### Persistent PreAllocaition
The FS can now be called to preallocate an empty extent, so, once that file is populated, it stays as a contiguous space.
#### Metadata Checksums
Metadata is checked often, which helps find any issues with the file system, as each data structure is now properly 'documented'.
#### Better Times
- A creation time was added;
- The time precision was increased to nanoseconds instead of only seconds;
- The maximum supported time was increased as well (the standard UNIX time can only go up to 2038).
#### Extended Attributes
The filesystem can also be customized with new entries at the end of each `inode`.
#### Quotas
`EXT4` also supports adding limits to the size of a file, or even multiple files spread across the filesystem.
#### Barriers
Some hard drives have caches, which impact the journal, sometimes causing it to be written after the cache, which would create conflicts. To fix this issue, `EXT4` creates a 'barrier', preventing the disk from writing data before the journal is written to the drive. This feature impacts performance, but is also very needed.
#### Flexible Block Groups
Groups blocks together, isolating chucks to write data on, which helps make data more contiguous.
#### Meta Block Groups
If the whole filesystem was only a single block group, it would max out at 256 TB of total data. Using meta block groups, this limit is increased to 32 bits of block group descriptor, which makes the **total capacity of the filesystem** ==**512 PB**==.
#### Partition Layout
[https://maplecircuit.dev/linux/fs/ext/ext4.html](https://maplecircuit.dev/linux/fs/ext/ext4.html)

View File

@@ -0,0 +1,125 @@
---
Status: Ready
Created by: Trude EH
tags:
- computer-science
- electronics
- notes
author: TrudeEH
draft: false
searchHidden: false
showToc: true
title: Logic Gates
---
## NOT
Invert the input.
![[image42.png]]
### Truth Table
|**Input**|**Output**|
|---|---|
|0|1|
|1|0|
## AND
Output `1` only when both inputs are `1`.
![[image43.png]]
### Truth Table
|A|**B**|**Output**|
|---|---|---|
|0|0|0|
|0|1|0|
|1|0|0|
|1|1|1|
## OR
Output `1` if at least one input is `1`.
![[image44.png]]
### Truth Table
|A|**B**|**Output**|
|---|---|---|
|0|0|0|
|0|1|1|
|1|0|1|
|1|1|1|
## NAND
An `AND` gate followed by a `NOT` gate.
![[image45.png]]
### Truth Table
|A|**B**|**Output**|
|---|---|---|
|0|0|1|
|0|1|1|
|1|0|1|
|1|1|0|
## NOR
An `OR` gate followed by a `NOT` gate.
![[image46.png]]
### Truth Table
|A|**B**|**Output**|
|---|---|---|
|0|0|1|
|0|1|0|
|1|0|0|
|1|1|0|
## XOR
Either input is `1`, exclusively.
![[image47.png]]
![[image48.png]]
### Truth Table
|A|**B**|**Output**|
|---|---|---|
|0|0|0|
|0|1|1|
|1|0|1|
|1|1|0|
## XNOR
Inverted `XOR`.
![[image49.png]]
### Truth Table
|A|**B**|**Output**|
|---|---|---|
|0|0|1|
|0|1|0|
|1|0|0|
|1|1|1|
## Implementation Examples
### NOT
![[image50.png]]
### AND
![[image51.png]]
![[image52.png]]
### OR
![[image53.png]]

View File

@@ -0,0 +1,72 @@
---
Status: Ready
Created by: Trude EH
tags:
- computer-science
- notes
author: TrudeEH
draft: false
searchHidden: false
showToc: true
title: Memory
---
## Remembering Data
An `OR` gate could be used to store a single bit.
![[image76.png]]
If the input `A` is changed to `1`, the `OR` gate will output `1`, and then receive it.
![[image77.png]]
Even after the input `A` is set to `0`, the output does not change. The `OR` gate "remembers" that, at one point in the past, the `A` input was set to `1`.
![[image78.png]]
The inverse can be done with an `AND` gate.
![[image79.png]]
To remember either a `1` or a `0`, we can do the following:
![[image80.png]]
AND-OR LATCH
The input `A` sets the output to `1`, and the input `B` sets the output to `0`. This circuit is able to store a bit of information, while powered on, even after both inputs are set to `0`.
A slightly more advanced and intuitive version can be built as follows:
![[image81.png]]
GATED LATCH
The input `A` is the value to store, and when `B` is set to `1`, the value is stored.
This is not the only way to store data using logic gates, but it is one of the simplest.
## Registers
A single bit isn't very useful, so we can use the previous circuit to create an 8bit register.
![[image82.png]]
## Binary Decoder
Select which circuit to activate, depending on the task at hand.
![[image83.png]]
## RAM
Registers don't scale well, however, as storing a large amount of data would require millions of wires.
We can organize latches in a matrix instead of a long, horizontal line.
![[image84.png]]
To access a specific latch, binary decoders can be used.
![[image85.png]]
This way, a single, short memory address can select any latch in the matrix.
### Reading and Writing to the Matrix
We can modify the latch to reduce the amount of wires needed.
![[image86.png]]
This new latch uses the same wire for both input and output.
![[image87.png]]
This circuit would store the same value on every latch, which isn't useful. With some modifications, however, we can use the memory address to select which latch to modify.
![[image88.png]]
![[image89.png]]
### Storing Bytes Instead of Bits
![[image90.png]]
In this example, we can provide 1 byte of information, a `write` or `read` signal, and a memory address. Since we are storing a full byte, the same memory address applies for all 8, single bit circuits.
This configuration is more commonly known as **RAM**.
To make it easier to understand, we can abstract these concepts further.
![[image91.png]]
The largest the Address Bus is, the more bits can be managed. This is why a 32bit CPU can't manage more than 4 GB of RAM.
![[image92.png]]
This kind of RAM is Static RAM (**S**RAM), which uses many transistors, making it faster, but more expensive to produce than **D**RAM.