renmaing directories to remain consistent

This commit is contained in:
shockrahwow
2019-09-24 11:34:35 -07:00
parent d9f98803d2
commit 2a5b249a5c
107 changed files with 695 additions and 0 deletions

BIN
337/img/fig0lec10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
337/img/fig1lec10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
337/img/fig2lec10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
337/img/not.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

16
337/lec/lec1.md Normal file
View File

@@ -0,0 +1,16 @@
# lec1
> What on earth?
The first lecture has bee 50% syllabus 25% videos, 25% simple terminology; expect nothing interesting for this section
## Performace Options
In general we have a few options to increase performace in software; pipelining, parallelism, prediction.
Parallelism/Pipelining
* I'll just assume you know what this entail; one does many things at once; the other is like queues for processessing.
* Prediction
Yes this means interpreting potential outcomes/inputs/outputs etc. __BRANCHING__. We try to predict potentiality and account for it ahead of time.

41
337/lec/lec10.md Normal file
View File

@@ -0,0 +1,41 @@
# lec11
At this point I'l mention that just reading isn't going to get you anywhere, you have to try things, and give it a real earnest attempt.
__ALU:__ Arithmetic Logic Unit
## Building a 1-bit ALU
![fig0](../img/alu.png)
First we'll create an example _ALU_ which implements choosing between an `and`, `or`, `xor`, or `add`.
Whether or not our amazing _ALU_ is useful doesn't matter so we'll go one function at a time(besides `and/or`).
First recognize that we need to choose between `and` or `or` against our two inputs A/B.
This means we have two inputs and/or, and we need to select between them.
_Try to do this on your own first!_
![fig1](../mg/fig1llec11.png)
Next we'll add on the `xor`.
AGAIN: try to do this on your own, the main hint I'll give here is: the current mux needs to be changed.
![fig2](../img/fig2lec11.png)
Finally we'll add the ability to add and subtract.
You may have also noted that we can subtract two things to see if they are the same dhowever, we can also `not` the result of the `xor` and get the same result.
![fig3](../img/fig3lec11.png)
At this point our _ALU_ can `and`, `or`, `xor`, and `add`/`sub`.
The mux will choose one which logic block to use; the carry-in line will tell the `add` logic block whether to add or subtract.
Finally the A-invert and B-invert line allow us to determine if we want to invert either A or B (inputs).
## N-bit ALU
For sanity we'll use the following block for our new ALU.
![fig4](../img/fig4lec11.png)
Note that we are chaining the carry-in's to the carry-out's just like a ripple adder.
also each ALU just works with `1` bit from our given 4-bit input.

108
337/lec/lec11.md Normal file
View File

@@ -0,0 +1,108 @@
# lec11
_diagrams references implied for now_
Sequential Logic: at this point we effectively are dealing with state(_state machines_). Simply put we have _memory_ now.
## State Tables
In Q~s~ is our _Current state_ while Q~s+1~ is the next state
![](../img/lec11fig1.png)
| A | Q~s~ | Q~s+1~ |
|---|---|---|
| 0 | 0 | 0|
| 0 | 1 | 0|
| 1 | 0 | 0|
| 1 | 1 | 1|
We can try the same thing with an `or` gate:
![](../img/lec11fig2.png)
Keeping in mind that our effective input here is only `A`.
## Latches
Namely we are going to look at set-reset latches.
They should be able to do two things:
* store a state
* change state upon appropriately changed signals.
![](../img/lec11fig3.png)
Note that the above state machine the two rows show up as illogical; because both don't make sense in that context.
The actualy gate implementation of the above would look like the above.
![](../img/lec11fig4.png)
The same can also be done with `nor` gates making the whole operation much more efficient on transistor usage.
The figure below is a more common implementation of a _Set-Reset Latch_.
![](../img/lec11fig5.png)
> Interesting but what is it used for?
Setting a value or reseting a value to 0.
That's all there is to it; either want to _set_ our ouput, or we want to reset it to zero.
This is the first step in creating a device which can _actually_ store information to be used later on, in other words, memory!
First we'll clean up our input: we are allowed to set _and_ reset which conceptually doesn't really make any sense since you should only be able to do one at a time.
To stop this input from even being accepted we'll used _one_ input which splits into both `nor` gates [D].
![](../img/lec11parsedinputlatch.png)
Next we want to decide _when_ to store the data because then we would even more control over our future _memory_.
To do this we'll need some signal to dictate when we should pass our desdired data to our output(_which could be to a memory bank_).
Our inputs now have `D` for the data we have now, and newly `C` for control(ling) if we want to store our data or not[1=yes 0=no].
![](../img/lec11controlledlatch.png)
At this point this is what we call a _D-latch_
### D Latches
We saw earlier that we can now store data based on some control.
Let's imagine that this control will regularly pulse between 0 and 1... similar to a _clock_.
This means that if D wants to spas out of control we don't really care because we're going to allow `D`'s value through our controlled latch __only__ when `C` is high.
This is all a _D-latch_ really is.
It is just a mechanism to "read" a signal into some output signal _whenever we want to_.
Even though the signals will keep flowing the output will be under our control, it just so happens that we are using a clock to control it out of convinience.
## Clocking & Frequency
The period of the square wave in this case can be used to find the frequency.
We simple note that `1/T = F`.
This frequency is measured in cycles/second or _hertz_.
![](../img/lec11squareWave.png)
### Setup time & Hold time
Setup time would be some aount of time after the previous point where we wait for the combinational logic to perpetuate its results into memory.
A short period of time in the valley would be setup time
Hold time is the time that we wait before we start feeding input into our combinational logic(unit).
Say we wanted to start our combinational logic at the beginning of one of our plateaus.
### Flip-Flop & Edge Triggering
Referring back to the square wave let's say we want to grab the value of `D` when the control signal rises high, but _only_ when it rises.
To do this we'll use the folowing structure:
![](../img/lec11flipflop.png)
Grabbing the value of `D` when the clock signal falls low is just as easy however the answer will not be shown here.
I suggest trying to find the answer yourself then looking up what such a logic diagram would look like.
For pedantic sake here are the simplified diagrams of the above.
_Only because they are so common._
![](../img/lec11flipflopsimp.png)

5
337/lec/lec12.md Normal file
View File

@@ -0,0 +1,5 @@
# lec12
## Registers

36
337/lec/lec13.md Normal file
View File

@@ -0,0 +1,36 @@
# lec13
Let's break down what most/any program must have(executable):
> Data
We need a place to put variables and maybe some compile time constants so when we compile our program we can place those things here.
> Code
This section will contain all of our running code(_duh it's in the name_). If you write any functions, loops etc they will live here.
> Stack
This area is used heavily for functions.
Any time we call a function we push a return address onto our stack for instance so that we know where to go back to when that function ends.
## Little Endian & Big Endian
Let's say we have the number `5431`.
Since the 5 is the _largest_ number here we'll say this number is in _big endian_ format but if we wrote backwards... we have `1345` we would say it's stored as _little endian_ because 1 is the _smallest_ number but its at the front.
For hex we do something very similar: take `0x45FA` as big endian.
Converting `0x45FA` to little endian we get `0xFA45`
> ??Wait that does seem right!?!
Here's the one caveat: _bytes aren't affected by little or big endianess_.
So just leave the bytes alone and reverse them from there.
## Significance of this
The reason why we care is because if you're going to be writing assembly code then you must understand these things to successfully create anything with assembly.
Even so this will give a deeper understanding of what goes on when something happens in your code.

65
337/lec/lec14.md Normal file
View File

@@ -0,0 +1,65 @@
# lec14
Just like any other binary, those written for MIPS must follow a specific structure for any level of compatibility.
In the case of MIPS, binaries have a few _sections_ which allow us to cleanly organize our files.
_Note that for the rest of this course I'll be discussing the [ELF file format](https://en.wikipedia.org/wiki/Executable_and\_Linkable\_Format), although most of this information is conceptually the same across most other [binary file formats](https://en.wikipedia.org/wiki/Binary_file).
## From Disk to Memory
### Binaries on disk will have the following structure
* Header
* Think of this like the metadata for the whole file
* Keep in mind however that every section also has its own respective header that let's the O.S. loader know what is going on.
* Data section
* Here you'll find any compile time constants and compile time variables held in this section
* Text Section
* This is where the _code_ actually live on disk. Any functions, loops, etc that gets compiled from something like C++ or C will be written to this part of the file.
### Binaries in memory
Once the binary is passed through the system loader the operating system will be able to determine that we may need a stack for the newly loaded code.
I say "may need" because not all binaries require its own stack.
A shared object file might not need its own stack because it will only be used as kind of _extension_ by some executable binary.
At this point any previous structure from disk is preserved as one might expect.
Once the file is loaded into memory however, the system loader must then also allocate some space of memory for our heap and stack; finally our program is in memory and we can begin execution(right?).
## DataTypes
Truth be told there are no _types_ in mips or really any assembly language, instead we determine _types_ by their size in bytes.
In the case of MIPS we have the following types
| Type | Size |
| --- | --- |
| byte | 1 |
| half-word | 2 |
| word | 4 |
| dword | 8 |
Likewise we also have _registers_, which are similar to global
## Actually writing mips now
Just like any other sensible architecture we have the ability in MIPS to use system calls to let us do things like writing to stdout or reading from stdin.
If you're writing mips code in mars there's a useful list of syscalls [here]().
For now let's translate some code to disect the different parts of MIPS.
```
int main(void) {
write("hello", 5, 1);
return 0;
}
```
If you compile this you'll have 1 compile time constant which contains `hello` but in hex followed by 1 byte of `0x00`.
We also have some code, in this case we want to write something to stdout, then we want to exit the program safely.
From the top we have a need for some data:
```
.data
.text
```

3
337/lec/lec15.md Normal file
View File

@@ -0,0 +1,3 @@
# lec15
If we want to write our functions in MIPS then we need some way of not just returning from a _sub-routine_ but also pushing arguments to each function call.

15
337/lec/lec16.md Normal file
View File

@@ -0,0 +1,15 @@
# lec16
_recall this is mips centric_
## Overflow
Dealing with signed values
## Carry
Dealing with unsigned values
## floats
using the IEEE-754 format

29
337/lec/lec17.md Normal file
View File

@@ -0,0 +1,29 @@
# floating point
mips uses ieee754
## parts of floats
1. Sign bit
2. Exponent
3. Mantissa
_32-bit floats btw_
## Sign
bruh
## exponent
This is coming from scientific notation so we have `2.0E3`
This means our 8 bit exponent is `0000 0011` + `0111 1111`
## Mantissa
let's roll with `2.0E3`
Mantiss of 2.0 = 0 <- 23 times
We have 23 `0`'s because the decimal portion of our number `2.0E3` is 0.

4
337/lec/lec18.md Normal file
View File

@@ -0,0 +1,4 @@
# lec18
At this point its all reference sheets
_except its mips so only pdf's are available_

3
337/lec/lec19.md Normal file
View File

@@ -0,0 +1,3 @@
# lec19

64
337/lec/lec2.md Normal file
View File

@@ -0,0 +1,64 @@
# lec2
## Binary Bits & Bytes
> Binary Notation 0b...
Typically we see `0b` but sometimes like in many x86 assemblers we'll see `...b` to denote some bit string.
Most typically we deal with binary(when we do) in nibbles or 4 _bit_ chunks which then grouped into 2 groups of 4 to build up a byte.
Ex:`0101 1100` is a basic random byte.
For most sane solutions this is essentially the only way we __ever__ deal with binary.
## Two's Complement - aka Negate
To find the Negation of any bit-string:
1. Flip all bits in the bit-string
2. Add 1 to the bitstring
### Signedness
> Why?
Because this matters for dealing with `signed` and `unsigned` values. _No it doesn't mean positive and negative numbers._
Say we have 4 bytes to mess with. This means we have a range of 0000 to 1111. If we wanted pureley positive numbers in this range we could have 0000 to 1111... or 0 to 15.
If we needed negative represenation however, we have to sacrifice some of our range.
Our new unsigned range is 0-7. We say it's unsigned because the first bit here is 0.
If it were 1 we would have a _signed_ number.
## Intro to hex
> Hex Notation 0x...
x86 assemblersi(masm) will typically accept `...h`
More convinient than binary for obvious reasons; namely it doesn't look like spaghetti on the screen.
Our 4-bit range from earlier {0000-1111} now becomes {00-ff}.
More pedantically our new hex range is 0x00 to 0xff.
> Binary mapped
It happens that 1 nibble makes up 0x00 to 0xFF.
So for now just get used to converting {0000-1111} to one of it's respective values in hex and evetually it should be second nature.
Then just move on to using hex(like immediately after these lessons).
Even the most obfuscated binary files out there don't resort to architectural obfuscation; until they do.
> Ascii in Hex Dumps
Kind of a side note but most ascii text is from 0x21 to 0x66ish[citation needed]
## 32 v 64 bit
For those with a 32 bit background know that these notes deal with 64-bit architecutres mostly. So some quick terminology which might randomly throw you off anyway.
> double-byte/ half-word
The latter is dumb but soemtimes used so wtever.
> word = 4 bytes
Etc onward with doubles, quads...

34
337/lec/lec3.md Normal file
View File

@@ -0,0 +1,34 @@
# lec3
## One's & Two's Complement
_Previous lecture went over signedness of numbers so this section won't as much_.
First we'll deal with flipping bits: this is where you may hear the term _1's complement_.
While not very useful on it's own for most purposes it does help get closer to creating a seperation between _positive_ and _negative_ numbers.
The only other step after flipping all the bits is just adding 1.
`1001 1110` becomes `0110 0010`.
> shouldn't that last 2 bits be 01?
Close, the reason why we have `b10` is because if we: `b01 + b1` the `1` will carry over to the next bit.
The actual term for this is just __negate__; the other way around is essentially cannon fodder.
>Ok, but what does that look like _assembly_ the thing I came here to learn.
Most assemblers accept something like `neg targetValue` however you can also use an _exclusive or_[`xor targetValue, 0xFF`]. Keep in mind that the immediate value should be sign-extended to reflect the proper targetValue size.
Two's complement proccess:
1. Flips bits
2. Add 1
## Sign Flag
Set whenever we produce (any) number where the leading bit is set(1).
Regardless if we're dealing with signed or unsigned data.
If we mess with some data but the sign bit remains the same then our sign flag just stays in its current value.

39
337/lec/lec4.md Normal file
View File

@@ -0,0 +1,39 @@
# lec4
## Binary Addition
Let's say we want to add the binary numbers `0b0011` and `0b1001`.
To do this we have to consider what happens when we do `1+1`.
If we only have 1 bit of space to work with then our answer is just `0`.
In normal terms if we only have digit of space to work with 5+5 is also 0 but with a carry of 1.
Same deal in binary: `1+1=0 {Carry=1}`.
So now we have:
```
11 <-- Carry row
0011 +
1001
----
1100 <-- Final answer
```
## Binary Subtraction
Taking the problem `0011-1001` what we're actually going to do is find the 2's complement of the second number.
This will be the negative version of that number which means its equivalent to saying `0011+(-1001)`.
So now we have basic addition but our `1001` becomes `0111`.
```
111 <-- carry bits
0011 +
0111
----
1010 <-- Final answer
```
Regardless of what happens we will always produce one special number alongside our result: _the carry bit_.
This is just the bit that carries out from the computation.
In both of our examples that bit would have been 0 but sometimes you'll notice that the carry is 1.
Both scenarios are valid depending on what data your adding/subtracting.

1
337/lec/lec5.md Normal file
View File

@@ -0,0 +1 @@
# lec5

27
337/lec/lec6.md Normal file
View File

@@ -0,0 +1,27 @@
# lec6
> diagrams needed for this section
## Transistors
Two types of transistors will be discussed here: `NPN` and `PNP`.
Both types however, do share some properties here by referred to as the following:
* E = Emitter
* B = Base
* C = Collector
### NPN
![](../img/lec6npn.png)
Current will __not__ flow across collector through base into emitter if do nothing.
When we apply a current to the base then current flows through the transistor.
### PNP
![](../img/lec6pnp.png)
Current will flow across emitter through base into collector if we don't do anything.
When we apply a current to the base then current flow stops.

12
337/lec/lec7.md Normal file
View File

@@ -0,0 +1,12 @@
# lec7
> this section also needs diagrams to make any sense
Now we'll take about different gates.
## OR
## AND
## XOR
## NOT
## Resistor Bands

118
337/lec/lec8.md Normal file
View File

@@ -0,0 +1,118 @@
# lec9
This lecture has a corresponding activity found in `lab/` it is called `combinational-logic.md`.
It is more useful to practice combinational logic as opposed to read about it so the sub section here will be minimal in information.
It's recommended that you try as many of the problems in the activity until you understand the concept, _don't bother doing them all_.
## Combinational Logic
### OR
`a+b` is equivalent to saying `a` or `b`.
### AND
`ab` is equivalent to saying `a` and `b`.
Note that this syntax is simlar to multiplication so `a*b` is equivalent to the above.
### NOT
`!a` is equivalent to saying not `a`.
We can also denote it with a bar over the expression we want to _not_.
![Figure-Not](../img/not.png)
### Big AND
Behavior is the same as an `and` but instead of two inputs we can have many more inputs.
It will only ever return a 1 if all inputs are 1.
### Big OR
Again we are mimicing the behvior of the normal or gate but this time we can have multiple inputs as opposed to just two.
If only one of the many inputs is 1 then we return a 1 for the output of the Big OR.
## Decoders
Here we'll learn by doing
```
Selector = 2 Bits
Output = 4 Bits
```
As a challenge you can try using the combinational logic gates from above to try and tackle this yourself
|s1 |s2 |o3 |o2 |o1 |o0 |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 1 |
| 0 | 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 0 | 1 | 0 | 0 |
| 1 | 1 | 1 | 0 | 0 | 0 |
## Multiplexor
Typically we'll refer to multiplexors by their size.
> what does it do?
It takes a signal as `2^n` inputs and out puts out `n` signals as output.
Example: We have a selector(s0), two inputs[in0 & in1], and one output `out`.
The selector will select an input and we will generate some output in `out`.
|s0 | i1 | i0 | out|
|---|---|---|---|
|0 | 0 | 0 | 0|
|0 | 0 | 1 | 1|
|0 | 1 | 0 | 0|
|0 | 1 | 1 | 1|
|1 | 0 | 0 | 0|
|1 | 0 | 1 | 0|
|1 | 1 | 0 | 1|
|1 | 1 | 1 | 1|
This ultimately lets us pick data out of memory given some address.
## Half Adder
For now we'll take two inputs and get 1 output, with a carry-output.
Let's add 2 bits
|a |b |out|
|---|---|---|
|0 |0 |0 |
|0 |1 |1 |
|1 |0 |1 |
|1 |1 |0 |
What about the carry bit however? What would _it_ look like given the preivous operations?
|a |b |carryout|
|---|---|---|
|0 |0 |0 |
|0 |1 |0 |
|1 |0 |0 |
|1 |1 |1 |
Before what this implies note that the result of the carryout resembles
## Full Adder
Two inputs, One output, One carry-out, One carry-in
Here we'll add up `a & b`(inputs) and `c` carry-in
|c|a|b |output|
|---|---|---|---|
|0|0|0 |0|
|0|0|1 |1|
|0|1|0 |1|
|0|1|1 |0|
|1|0|0 |1|
|1|0|1 |0|
|1|1|0 |0|
|1|1|1 |1|

49
337/lec/lec9.md Normal file
View File

@@ -0,0 +1,49 @@
# lec10
## Half-adder
This will be the building block for adding bit-strings together later on however, for now we are going to just add two singular bits.
To accomplish this we'll build a half adder.
This means our logic circuit must adhere to the following logic table.
If both inputs are 0 then our result is 0 and we don't have to carry anything out.
If only one input A/B is 1 then our result will clearly be 1 and our carry will be 0.
Finally if both inputs are 0 then since we can't fit 2 in a single bit it means we have to carry-out a 1, and our result will be 0.
With all of this in mind we have a table to guide how we will implement our logic circuit.
I __highly__ suggest that you try to build a logic circuit on your own first as most of the content is best learned through practice.
| A | B | Carry-out | Result |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 0 |
![fig0](../img/fig0lec10.png)
## Full Adder
If we only want to add single-bit's then a half-adder works fine but if we want to add multiple bits say `1011 + 0010` then we need to consider that we will likely have to chain these together.
The full-adder has 1 main difference from the half-adder, it has 3 inputs, 2 main inputs and 1 input for the carry bit.
The carry bit will propagate along the operation now if we chain these together, _just like real addition!_
![fig1](../img/fig1lec10.png)
With this we can start chaining together multiple Full-adders we can start adding multiple bits at the same time since the carry now propagates along the chain.
## Ripple Adders
An N-bit adder is really just made up of Full adders chained together.
Each adder is chained to the next by the carry-out line which then acts as the next adder's carry-in line.
If we have say a 4-bit ripple adder, then each bit in the bit strings will go to a different adder.
For now the initial carry in bit will be fed a 0 everytime.
![fig2](../img/fig2lec10.png)
Here we see that our 4-bit input A & B have the values `1111` & `0000` respectively.
The 0th bit goes to Adder0, the 1th goes to Adder1, and so on.
You should have also noticed that each one also takes a carry-in, which for now is 0 but it does mean we have to let the comutation happen one adder at a time.
None of the sequential adders can do anything if the previous have done anything yet either.
At the end of it all we get some bit results, and a carry-out.
We can then simply reassemble the results back into one bit-string to assemble our final result.

14
337/readme.md Normal file
View File

@@ -0,0 +1,14 @@
bruh
get a mips vm and start messing with it
because otherwise we're not going to get anywhere useful never
# Subject - Computer Architecture & Assembly with MIPS
Material on the hardware side of this course covers everything from transistors up to logic gates.
Assembly is among the second half of this course(_ymmv_) if the course is flip-flopped for you.
## In progress Citations
Ascii section in [lec2](lec2.md) is off by a few bytes
lec5 is empty for some reason