mirror of
https://github.com/soconnor0919/eceg431.git
synced 2025-12-11 06:34:43 -05:00
add project reflections
This commit is contained in:
1
reflections/projects/1.txt
Normal file
1
reflections/projects/1.txt
Normal file
@@ -0,0 +1 @@
|
||||
This project was somewhat easy, but it took a significant amount of time to bring back the concepts. It connected a ton to my discrete math and computer systems (in CS) course, and applied those concepts into creating fundamental logic gates, and extending them into (de)multiplexers and more gates. Setting up the environment was simple for me as well- I'm very comfortable in the terminal, and have configured editors for any possible file I could encounter already.
|
||||
5
reflections/projects/10.txt
Normal file
5
reflections/projects/10.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Project 10 was a nice shift from the low-level system building I'd been doing- finally working with language structure and grammar. The modular design philosophy I'd been using since Project 6 carried over well. The JackTokenizer and CompilationEngine split followed the same Parser/CodeWriter pattern from my VM translator, just dealing with a much richer set of tokens and grammar rules. Building the tokenizer was actually straightforward- it's essentially just string parsing that I've done plenty of times before. The comment handling was trickier than expected though, with multi-line comments that span across lines requiring state tracking between advance() calls.
|
||||
|
||||
The compilation engine was where my algorithm/programming language design and computer systems (in CS, 306) courses finally clicked into place. Recursive descent parsing is just grammar rules implemented as methods that call each other- it was elegant, but only once I saw it. Each production rule maps directly to a method, and the recursive calls naturally build the parse tree (which I just so happen to be doing in CS 308, programming language design!). The XML output requirement was actually great for debugging since I could visually inspect the parse tree structure in a browser and catch parsing errors immediately. I hit some tricky edge cases with expression parsing- operator precedence, unary operators, and making sure the tokenizer advanced at exactly the right moments for complex constructs like array access and method calls.
|
||||
|
||||
What really struck me was how this project revealed the hidden complexity of syntax analysis- something I'd always taken for granted as a programmer. Seeing how a parser actually breaks down source code according to grammar rules, handles precedence, and builds a structured representation gave me new appreciation for what happens before compilation even starts. Again, a great compliment to 308, as I'm learning the theory there and putting it into practice here.
|
||||
1
reflections/projects/2.txt
Normal file
1
reflections/projects/2.txt
Normal file
@@ -0,0 +1 @@
|
||||
Now we're starting to ramp up, and this is beginning to cause some internal conflict. Coming from computer science, and with my experience on low-power systems, I find optimization to be really important. Yet, in the ALU, I found it easiest to compute multiple values and then decide which one to keep, because you can't "build" a circuit after something is computed, rather, you have to prepare for all outcomes. Although the logic here seems Turing complete (without full analysis), it's a bit of a learning curve for me to think physically and not in terms of software.
|
||||
1
reflections/projects/3.txt
Normal file
1
reflections/projects/3.txt
Normal file
@@ -0,0 +1 @@
|
||||
This project felt more aligned with the information from CSCI 306: using program counters, storing information in registers, using low/high bits to find what to address. Learning what the DFF did took a bit of reading and re-reading- still fuzzy on that, but the videos helped. The program counter was a bit confusing, as I tried to build it without a register first; once I figured out I needed to store the counter I went back to the register. The RAM was straightforward- just scaled, and I needed to split the address to propagate downwards and find which bank(s) to reference.
|
||||
1
reflections/projects/4.txt
Normal file
1
reflections/projects/4.txt
Normal file
@@ -0,0 +1 @@
|
||||
This project was definitely the most difficult yet, but made sense after a while. I started with laying out the actions of what's going on functionally, turned that into pseudocode comments. Most of my time then turned into translating RISC-V style pseudocode into functional code, and debugging. Assembly makes sense, but only after a while. Documentation is kinda all over the place.
|
||||
17
reflections/projects/5.txt
Normal file
17
reflections/projects/5.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
I say this each time, but this one was definitely the hardest so far. Glad to be done with HDL. The Computer was easiest- just combining three parts. Memory was simple enough once I laid it out, using the textbook to figure out offsets and partitions. I'm not a fan of bit splitting (referencing like it's an array), but it's good enough to work. Partly why I'm glad to move on.
|
||||
|
||||
That being said, the CPU was difficult.
|
||||
*extra lines for dramatic effect*
|
||||
|
||||
Decoding instruction type? fine.
|
||||
Computing jump type? fine, eventually.
|
||||
Updating the program counter? fine. easy, even.
|
||||
Connecting outputs? didn't know I could just reroute outputs- until I looked at my old code and realized I doubled it anyways. Bit of an airhead moment from me, I just forced it with an or. Worked, but at what cost? (I know the cost. two or's. that's literally the cost.) ¯\_(ツ)_/¯
|
||||
|
||||
ALU op? Lots of variables. But I made the ALU before- it's just plugging it in correctly.
|
||||
|
||||
The problem was taking the instruction and turning it into something the ALU could handle. Even though I had the instruction breakdown, and the connections, I just repeatedly hit my head against a wall. It really took a lot of trial and error, but I had the majority of this all done in the first two days, and spent the rest of the time on fixing this. Eventually, I just kinda fixed it by accident? (In the words of Ned Ladd: There are three steps to solving a problem. Write down what you know, Think really hard, Write down the answer. You're at step 2.)
|
||||
|
||||
In actuality, I drew out diagrams, connected the bit segments to where they needed to go, unraveled the mess of drawings I did create over and over, until I actually figured it out. Then it worked. But that isn't as fun of a response.
|
||||
|
||||
Thank you for coming to my ted talk.
|
||||
8
reflections/projects/6.txt
Normal file
8
reflections/projects/6.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Combining a reflection of 5.5 and 6 here...
|
||||
|
||||
I began the bunny/hare project recalling how to program with Python. I looked back at my CSCI 204 labs to find how I had worked with file I/O, and copied functions from that to start. I prefer to work in heavily object oriented, strongly typed languages with less room for experimentation, so going back to Python feels very odd. Once I got file I/O and lists working, the program was fairly straightforward.
|
||||
|
||||
Moving onto the assembler, I heavily utilized the template. I broke the program up into three classes: A parser, which reads the assembly commands and breaks them up into components; a symbol table, which acted as a lookup table for predefined symbols (registers, screen, keyboard etc), and a "code" class, which translates the mnemonics into their respective binary representations. Once those helpers were done, I began on the assembler. I store all the assembly that's generated into a list, which is later written to a file. Not the best implementation- more file writes would be safer, but this works for now, and lets me iterate.
|
||||
I check for more commands, iterate through the commands, find their type, then either look it up or convert to binary (this is simplified, but gets the gist). once all commands are processed, I write the list to the file.
|
||||
|
||||
That's it! This took a bit of time, I optimized my classes a bit out of preference, but it works!
|
||||
3
reflections/projects/7.txt
Normal file
3
reflections/projects/7.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Functionally, my code for Project 7 (VM to ASM) is the same as Project 6 (ASM to Hack), at least in the beginning. I wrote the program to be very class-heavy, object oriented and well structured- allowing me to bring over the Parser class. The Parser class takes all commands into a list, and allows for iteration through the list. It allows for the command type to be identified and arguments to be separated. The CodeWriter class then writes the assembly commands as strings- they’re parsed by the parser, fed into the translator which then writes the correct sequence of commands into assembly (usually more than one per vm line). The translator creates an instance of parser and code writer, and combines their functionality to write the assembly to a file. Finally, the main function handles the aggregation of it all- taking in a file, verifying arguments, parsing directory contents etc.
|
||||
|
||||
My process throughout this was iterative- I used my base from project 6 as a good start. Although it didn’t necessarily build off of the prior project, the process was similar. I started porting the parser, mapping the commands to a lookup list. Then the CodeWriter, which actually converted the commands to their symbols. The CodeWriter took the most time- as I needed to fill in the gaps with pushing and popping from the correct places. The translator just connected the two, so that was easy. Along the way I brought over my main function, changed it to handle directories and updated its usage.
|
||||
5
reflections/projects/8.txt
Normal file
5
reflections/projects/8.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Building the VM translator for Project 8 felt like a natural evolution from Project 7, much like how Project 7 built conceptually on Project 6's foundation. The modular design I started in the assembler, with clean separation between Parser and CodeWriter classes, paid off. I extended the existing VM translator by just adding new command types to the parser and corresponding translation methods to the CodeWriter. The OOP structure made this expansion surprisingly straightforward and easy.
|
||||
|
||||
What struck me most was how this project revealed the hidden complexity of function calls- something I'd always taken for granted as a programmer. Seeing how the stack based calling convention actually works under the hood, with its intricate back and forth of saving state, repositioning pointers, and managing return addresses, gave me a new appreciation for what compilers do behind the scenes. It reminded me of CS 315 (operating system design). The recursive Fibonacci function was cool to see, as it showed parallels between the LIFO nature of the stack and the LIFO behavior of nested function calls- further explaining what I knew about recursion.
|
||||
|
||||
The most challenging piece was getting the function calling protocol exactly right. The sequence of operations for `call` and `return` commands required careful attention to detail, especially managing the temporary registers and ensuring the stack frame was constructed correctly.
|
||||
3
reflections/projects/9.txt
Normal file
3
reflections/projects/9.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Project 9 was a nice change of pace from the previous projects. Instead of implementing precise specifications like the assembler or VM translator, I got to be creative and build something interactive. The modular design approach I'd been using in Projects 6-8 carried over well - separate classes for Point, Food, Snake, and SnakeGame made the code clean and easy to debug. I hit several tricky issues though - the snake would leave white pixel artifacts when growing, food would sometimes spawn invisibly at screen edges, and hitting walls caused program crashes with "illegal rectangle coordinates" errors. Jack also doesn't have built-in random functions, so I had to find a random number generator online, as I didn't know where to start with making one myself. I found one using "Linear Congruential Generator" math that I didn't really understand, but it worked for spawning food in different locations. The modular design helped isolate these problems to specific classes rather than hunting through monolithic code.
|
||||
|
||||
The most rewarding part was seeing the entire stack work together. The Snake game runs on the CPU built in Project 5, uses the VM implemented in Projects 7-8, and gets compiled by the Jack compiler. Every keystroke travels through layers I actually understand now- from hardware input to game logic to screen output. The debugging was different too- instead of failed test cases, I had to diagnose visual glitches and gameplay behavior. Jack's limitations also forced some creative workarounds, like implementing a proper random number generator from scratch and handling the lack of color support by using outlined boxes for food instead of filled squares. It felt more like real software development with messier problems and less obvious solutions, but also more satisfying when everything finally worked smoothly.
|
||||
Reference in New Issue
Block a user