Lab 6 - git and ToyASM
Wouldn’t it be great if we did not need to write binary to program our machines? In class, we will soon be discussing x86-64 assembly, which is a more readable representation very close to the binary machine code, allowing us to program our computers (and the portal) more directly. In this lab, we will consider a simpler version of assembly language that directly maps to the Toy ISA we have been programming in over the past few weeks.
But before we get to that, we’ll cover some basics of git version control.
Lab Goals
After this lab, you should:
- Know git basics such as init, clone, add, push, fetch, and pull
- Understand general format of assembly (similar to AT&T syntax of x86-64)
- Understand how ToyASM maps to our Toy ISA
- Be able to write code using assembly
Getting Started
In this lab, we will begin using the CS portal to write and run our code. Please refer to Lab 1 for details on getting connected.
ssh mst3k@portal.cs.virginia.edu
git
We’ll use git in this class, and many other classes that follow. Git is a versatile tool that does many useful things; among them are
- It stores all versions of your files so you can recover from mistakes
- It lets you move files between machines easily
- It lets multiple people collaborate on a project with minimal coordination
- It lets you set up “hooks” to automatically run when things change
Broad overview
- Several computers will be involved
- Each will have a complete copy of the history of every file
- On a single computer,
- Each file has two places it is stored: the working directory (which is where you’ll work on it) and a hidden git-managed copy (which is where git will track versions, communicate with other machines etc)
- When you edit a file, git considers it either “untracked” or “modified”
- an “untracked” file has no copy in the git-managed space
- a “modified” file has been changed from the last git-managed version
- “adding” a file tells git to care about your changes to it (i.e., you’re “staging” the file for commit).
- “committing” a file tells git top update the git-manages copy to match your version. You can only commit added (i.e., staged) files.
- Working between computers,
- you can “push”, saying “remote computer, you should know about what I’ve done lately.”
- you can “pull”, saying “remote computer, what have you done lately?”
- In general you have to both pull and push if you want your copy and the remote copy to become the same.
Creating a project
For this class, you should only need to create a server-side repository once or twice. We’ll start by creating a place to store our repositories, then initialize our first server-side repository to hold code for labs.
Location for repos
Create a place to store your server-side repos:
mkdir repos
Our first server-side repo
Now, cd into that directory and create your first server-side repository. In general, once we create these, we will not interact with them; they will store our code in an organization scheme that git understands but is not human readable.
cd repos
mkdir cso1-code.git
cd cso1-code.git
git init --bare
If this was successful, you will see the following notice about an empty repository being created:
Initialized empty Git repository in /u/mst3k/repos/cso1-code.git/
Working copy on portal
Now we are ready to check out a working copy of this repository so that we can actually begin coding! Return to your home directory before continuing: cd ~
.
To check out a working copy of a git repository, we “clone” the repository. The general format of this command is git clone REPOSITORY-LOCATION
, where the location is either a URL (such as GitHub), an SSH server and path, or a full path to a git repository. Let’s clone the server-side repository we created a few moments ago (replace mst3k with your computing id):
git clone /u/mst3k/repos/cso1-code.git
Once you issue the command, git should confirm that it cloned the repository into a new directory, cso1-code
.
cd into your working copy.
Using git
We expect the most common case will be you’ve created or modified a file on the portal and want to get a local version on your laptop to submit to Gradescope. Let’s go through this step by step, assuming you start on the portal in the working directory of your git repository.
git pull
Before we make any changes to local files, let’s have git check to see if some other computer (such as our laptop) has also made changes that you’ll need to merge. We don’t expect that to happen very often this semester, but you should get into the practice of always git pull
before git push
.
git add file1 file2 ...
Tell git
which files you want to commit into the version history. Any changes to these files will be “staged” for commit so that the current state of the files can be saved into the version control system. Adding and then committing files often will help ensure that we can always revert to an older version if something goes wrong. It is also a convenient way to sync our files to another client, i.e., our laptops.
If you want everything in the current directory to be added, you can use git add .
.
git commit -m "I changed a few files"
Tell git
to update it’s internal copy of the files you’ve added and label this change “I changed a few files”. Using good descriptive labels becomes more important as project teams grow, so you should be more specific here. For example, “Added the instructions that save the PC for the jump instead of hard coding the memory address.”
You can add and commit in one step if you have only modified (not added) files by using git commit -a -m "fixed typos"
git push
Ask git to send your changes to the main repository on the remote server.
Your Laptop’s Local Copy
We also want a local working copy on our laptops. This will allow us to git pull
the changes we made on the CS portal to our laptop and then upload them to Gradescope. In order to clone (i.e., set up a local working repository based on the server’s version) to your laptop, you’ll need to use the full address of the server.
You may need to install git to continue. If you have a Mac or Linux machine, you likely already have git installed. Windows users will need to install git. Use the following links to install it if you do not already have it.
Windows: git for Windows
For Windows, it may be easiest to use the Standalone Installer or the winget tool.Mac: git for Mac
For Mac, git may be provided with your Xcode install, or you can install it with homebrew.
Once git is installed, from your local Powershell or Terminal, run the following command.
To get to your local Powershell you can run ‘exit’ or you can open a new Terminal.
git config --global init.defaultBranch main
If you do not run this command, there may be issues with pushing/pulling from the repository.
Now you can cd
into the directory you want your local copy to reside, and enter the following git command:
git clone mst3k@portal.cs.virginia.edu:repos/cso1-code.git
Once your laptop has cloned the git repository, you should now see a cso1-code
directory/folder with the same contents as your working directory on the portal nodes. You can follow the same steps locally to edit files and then sync them to the server.
In general, when using git to manage your source code, it’s helpful to follow these steps:
git pull
- get any changes from the server- Edit the files
git add ...
- stage the changes you made to your files so that they can be committed to the version historygit commit -m "your message"
- commit the changes to your local repository (not on the server yet). It may be helpful to do steps 2-4 as you’re editing, in case you decide you want to roll back some changes if something breaks.git push
- push the committed changes to the server
After editing your files on the portal, you can issue a git pull
command from your laptop’s working copy to get the newest files from the server.
Additional Tutorials
There are several tutorials you may find useful. Don’t feel that you have to do all of these (unless you want to and/or you need to still learn it), but doing at least one all the way through may help you feel more confident. You should probably do them on your own time, though, not during lab time.
- https://git-scm.com/docs/gittutorial
- https://try.github.io/
- https://learngitbranching.js.org/
- https://rogerdudler.github.io/git-guide/
- https://guides.github.com/introduction/flow/
- https://guides.github.com/activities/hello-world/
Toy Assembly
We will define a new language, ToyASM, that will make it easier to program our Toy ISA. It supports all of our icodes and operations from Lab 5, but with more human readable code than the bits we have been writing so far.
Each line in our code will consist of a single instruction with an operation and one or two operands, as follows:
operation source, destination
Definitions
Labels
When writing our ToyASM code, we may want to “remember” a location in our code so that we can jump to it later; i.e., to support loops and if statements. If a line in our code consists of only lower-case characters (a
through z
) followed by a colon, such as:
mylabel:
then this defines a label in our code. The assembler will remember the address of the next instruction in the code and replace the label with the correct memory address when producing the machine code.
Operations
Our Toy ISA has 14 total operations based on our 8 icode values and additional operations from icodes 5 and 6. We can represent all of those instructions using the following operations:
mov
- Move/copy a value from one place to another. We can move from register to register (icode 0), memory at a register value to a register (icode 3), a register value to memory at a register’s value (icode 4), an immediate address to a register (icode 6.0), and memory at a given immediate address to a register (icode 6.3).
add
- Add a value from one place to a register’s value. We can add a register value to another register’s value (icode 1), or add an immediate value to a register’s value (icode 6.1).
and
- Bitwise and a value from one place to a register’s value. We can and a register value to another register’s value (icode 2), or add an immediate value to a register’s value (icode 6.2).
neg
- Negate a register’s value based on two’s complement (icode 5.1); updates the given register’s value.
not
- Bitwise not of a register’s value (icode 5.0); updates the given register’s value.
lnot
- Logical not of a register’s value (icode 5.2); updates the given register’s value.
jump
- Compares the value in the first operand register to 0. If it is less than or equal to 0, then jump to the location (address) stored in the second operand register (icode 7).
movpc
- Save the current
pc
value into the operand register (icode 5.3). halt
- A special instruction for our machines that will produce an instruction with reserved bit = 1, so that the code can be run on our simulators.
Operands
Our operands may take on multiple forms:
- Registers
- Registers are denoted using the
%
. For example, to write “register 2”, we would write%r2
. - Literals
- Literal values (immediates in our Toy ISA) are specified using a
$
. That is, to write the hex value0x53
in our assembly language, we would write$0x53
. - Memory Accesses
- Our operand may be a value from memory instead of a value from a register or an immediate. Parentheses are used for a memory access as an operand; for example, to read memory at the address stored in register 1, we would write
(%r1)
.If we want to read from memory at an immediate (i.e., icode 6.3), we would write that value directly in the parentheses without the
$
used for normal literals. For example, to read the value at memory location0x74
into register r0, we would write:mov (0x74), %r0
- Labels
- Since we are no longer writing bytes, jumping to a particular location in our code becomes tricky. Therefore, we can move a “label” into a register. Due to the limitations of our ToyISA, a label may only be moved into a register in the following way:
mov mylabel, %r1
Note: when assembled, the binary generated from this instruction will move the address of the instruction following the
mylabel:
into register 1.
Example Instructions
Consider the following example instructions. For each instruction below, we display a python/Java-like syntax, the binary and hex from our Toy ISA, and the ToyASM assembly instruction.
Code | Toy ISA Binary | Toy ISA Hex | ToyASM |
---|---|---|---|
r0 = r1 | 0000 0001 | 01 | mov %r1, %r0 |
r3 = 0x42 | 0110 1100 0100 0010 | 6C 42 | mov $0x42, %r3 |
r2 += r1 | 0001 1001 | 19 | add %r1, %r2 |
r0 += 0x9A | 0110 0001 1001 1010 | 61 9A | add $0x9a, %r0 |
r3 = M[r2] | 0011 1110 | 3E | mov (%r2), %r3 |
M[r1] = r0 | 0100 0100 | 44 | mov %r0, (%r1) |
Example Programs
Here are a few example programs in code, hex (binary), and ToyASM to compare. As we begin moving towards x86-64 assembly over the next week, it will be helpful to see how assembly compares with the underlying binary instructions.
Subtraction
Compute 0x42 - 0x15. This can be achieved in the following python-like pseudocode:
x = 0x42
y = 0x15
z = x - y
Compare that with our Toy ISA and ToyASM instructions:
Code | Hex | ToyASM |
---|---|---|
|
|
|
Modulo
Compute 0x94 % 0x21. This can be achieved in the following python-like pseudocode:
x = 0x94
y = 0x21
while (x > 0)
x -= y
x += y
return x
Compare that with our Toy ISA and ToyASM instructions. Note that we must first modify our loop slightly to the following pseudocode:
x = 0x94
y = 0x21
x = -x
while (x <= 0)
x += y
x = -x
x += y
return x
Code | Hex | ToyASM |
---|---|---|
|
|
|
Assembling to Binary
We have provided an assembler to assemble (compile) our ToyASM to Toy ISA binary code. You can run this directly on portal using the following command:
/p/cso1/toyassemble my_asm_file.tasm
When run, our assembler prints out the corresponding hex digits for our binary program. You may then copy/paste this code into our online simulator or save it as a text file to use with your simulator from lab 4.
Your Task
In this lab, we will ask you to:
- Create a git repository (
repos/cso1-code.git
) and local working copy (cso1-code
) on the portal, following the instructions in the git section above. - In your local working copy, write a multiply program (
multiply.tasm
in our ToyASM that calculates \(\lvert x \times y \rvert\) (that is, the absolute value ofx * y
) and stores the final result in register 0.- It may help to start out similarly to how we began homework 1; for example, we could start by loading two immediate values into registers 2 and 3, then calculating r0 = r2 * r3.
mov 0x10, %r2 mov 0x03, %r3
- If the product is greater than 255, compute it modulo 256. Your code should also be able to handle edge cases like
0 * 0
. - Note how different and more (or less) readable your code is in assembly than your modulo code from homework 3 (and our examples above).
- How does the assembled binary compare with the binary you wrote in Lab 5?
- It may help to start out similarly to how we began homework 1; for example, we could start by loading two immediate values into registers 2 and 3, then calculating r0 = r2 * r3.
- Assemble your code with our assembler into Toy ISA binary (hex) and try it out on the online simulator.
- Commit your file to git (
git add
,git commit -m "..."
) and push it to the server (git push
). - Clone your repository to your local laptop and ensure that you can pull from the server (
git pull
). - Submit your
multiply.tasm
to Gradescope.
Note: Like in Homework 3, we will directory modify your code so that the second (0x01) and fourth (0x03) bytes are the input values. This means your first (0x00) and third (0x02) bytes (instructions) should be very specific operations. Note that the autograder assembles your code, then modifies the ISA.
Check-off with a TA
Upload the following to gradescope:
- Your Toy Assembly code
multiply.tasm
To check-off this lab, show a TA
- Run
git log
in yourcso1-code
directory on the portal to show that you have changed files - Run
git log
in yourcso1-code
directory on your laptop - Once you submitted your files check in with a TA so that they can give you attendence credit.