11-26-2017, 04:32 PM
NOTE: an error has been found in this thread, please see note at end, it's important. This same correction notice will be present in Part 9 in case you miss it
Ok, so it's been a while since I've done a tutorial, and I really wanted to get into the cool stuff of this one, so here we go.
First of all, we'll be using Code:Blocks, since I'm assuming most of you are on Windows, those of you who aren't, impress me by making a nice Makefile project :smile:
Let's get our project set up:
We're going to go ahead and click new project down there from our list
At this point, a dialog should appear, and we're going to create a new console application (meaning this will not have a GUI), and click OK
Now, we can select that this will be a C project, we won't need any sort of object orientation so we'll stick with strict C where things are easier
Go ahead and fill out the project path settings like mine
and go through the rest of the dialog
Now, we should have a new project with nothing in it, but we don't because this is a windows editor and they think we all need to start with a hello world program..
Modify it to look like this
Go ahead and add a new header file "instruction.h" to the project, this is what we'll be doing today
In this file, let's lay out the skeleton for our instruction processing
Now, this is where your knowledge of C is going to be really important, there are two ways to do this from here out. We can do it the rookie way and have a bunch of processing functions, or we can do it so that it's native to our application (using unions and bit fields). We'll be doing the second one.
If your knowledge of C is rusty, now would be the time to go read up on the following
Ok, now that you've done that, let's use comments to explain what we're doing here. We're going to leave endianness out of the mix until the very end, but keep it in mind.
I'm using the same diagram from
In this structure, I've used comments to describe how many bits each field takes up, and what goes in them. Now I'm going to go ahead and replace all those comments with bit fields. I'll have to come back to 2 of them
Ok, my revised code looks like this. I've left the comments in place for now
Notice how I just have a bunch of question marks for operand2? Yeah, that's where things get a little tricky. Operand2 actually has 2 different forms. Let's take a look
Ok, so for those, let's go ahead and make a new set of structures for each. Here's my comment code for those
Ok, so let's go through and fill those two out, just so we have them
Cool, but we still have a problem. We can't add these two structs to our instruction_data struct, because it would make it 12 bits too big. What can we do? Unions
So, you should be familiar with them by now, but here's a basic description of what they do. Unions work like structures, with one key difference. Member variables in a structure make the whole structure larger, while members in a union don't change its size at all. All members in a union share the same memory space, meaning if you change the values in one member, you change the values in all members. This is useful when you only ever need to store data in one of the members, like we do in this case. We will never need both the register and the immediate structure, and we know which one we need based on the imm bit in our instruction_data structure.
Let's go ahead and make that union. While we're at it, we can go ahead and take our planning comments out.
The updated code looks like this:
I want to point out before we go any further, that I didn't use a bit field for imm in instruction_data_operand2_immedate. Before you all ask why, it's because it's an 8-bit field, and uint8_t is "unsigned 8-bit integer". A bit field would be fine here, but it would be set to 0x8, which is already how big the base type is. If you're OCD about it all, feel free to add it to your code
Now, we can go ahead and add our union to the instruction_data struct. We won't use a bit field here, because our union is exactly the right size already. Sorry to all you OCD fellas, this one won't line up either.
I'm also going to remove the planning comments.
With all that done, our entire instruction_data structure and all its dependencies are complete. Here is the full code for all of it:
Ok, at this point, I think you've all got the hang of it, so I'm not going to hold your hand through writing the instruction_transfer and instruction_branch structures. I've included my code in a spoiler below for you to check your work.
instruction_transfer
instruction_branch
Ok, so at this point, all we have left to do is finish our instruction union. As you suspected, this will be easy since our union is going to be made up of all 32-bit structures, we don't need to do bit fields or any of that sort of thing.
Here's the code
Alright, I apologize that this thread has run so long, but I'm happy we got through the tough stuff
Please stop at this point, until you have completed writing your instruction_transfer and instruction_branch structures. The remainder of this thread does not place those in spoilers
Ok, well since we got all the code hammered out, let's do a little refactoring. At this point, your entire instruction.h file should look like this:
I want to refactor it all so that it properly fits the ARM spec. This pretty much just means changing the names of the elements to either their bit codes or their proper register notation.
At the end of that refactor, using the following register definitions
Rn = source register
Rd = destination register
Rm = 2nd register
My code looks like this
Now, I think this header file is a bit too long for my comfort, and for reference (63 lines of struct defs), so I want to split this apart into 4 files:
instruction.h
instruction_data.h
instruction_transfer.h
instruction_branch.h
Awesome! We've now taken the first 5 parts and made them into the foundation for our very first assembler! Let's go ahead and add our include to main.c just to wrap this up.
One final note, if you try to build this right now, you will get an error like this
Do not worry, you didn't accidentally wipe it or something, it's just not set up properly.
Open the build settings
go into Search directories for the whole project
Click add, then make sure it points at your project (this path will be different for all users)
Now go ahead and click OK, save the project, then build it again
EDIT: I've restructured this project so it's a little more organized. I moved the instruction_x.h files to a folder called instruction and renamed them to just x.h.
This only effects instruction.h. Here's updated code for that file:
and a screenshot of the project again:
Congrats! You've made it to the end of part 6! Things should start coming together in your mind about what's going to happen next.
PLEASE write replies to this thread! Comment on what you liked or didn't like. Ask questions. Suggest what we could do to make it better. Just have a conversation! I hate seeing these threads go stale.
Also, don't forget about the webpage that holds organized links to all of these. It's linked in my signature, but you can visit it by going to
UPDATE:
I realized that I made a mistake in
[/hide]
[/hide]
Ok, so it's been a while since I've done a tutorial, and I really wanted to get into the cool stuff of this one, so here we go.
First of all, we'll be using Code:Blocks, since I'm assuming most of you are on Windows, those of you who aren't, impress me by making a nice Makefile project :smile:
Let's get our project set up:
We're going to go ahead and click new project down there from our list
At this point, a dialog should appear, and we're going to create a new console application (meaning this will not have a GUI), and click OK
Now, we can select that this will be a C project, we won't need any sort of object orientation so we'll stick with strict C where things are easier
Go ahead and fill out the project path settings like mine
and go through the rest of the dialog
Now, we should have a new project with nothing in it, but we don't because this is a windows editor and they think we all need to start with a hello world program..
Modify it to look like this
Go ahead and add a new header file "instruction.h" to the project, this is what we'll be doing today
In this file, let's lay out the skeleton for our instruction processing
Hidden Content
Now, this is where your knowledge of C is going to be really important, there are two ways to do this from here out. We can do it the rookie way and have a bunch of processing functions, or we can do it so that it's native to our application (using unions and bit fields). We'll be doing the second one.
If your knowledge of C is rusty, now would be the time to go read up on the following
- Structures
- Unions
- Bit Fields
- Endianness
Ok, now that you've done that, let's use comments to explain what we're doing here. We're going to leave endianness out of the mix until the very end, but keep it in mind.
I'm using the same diagram from
[To see links please register here]
to make this comment, so you may want to pull that up and refresh yourself.Hidden Content
In this structure, I've used comments to describe how many bits each field takes up, and what goes in them. Now I'm going to go ahead and replace all those comments with bit fields. I'll have to come back to 2 of them
Ok, my revised code looks like this. I've left the comments in place for now
Hidden Content
Notice how I just have a bunch of question marks for operand2? Yeah, that's where things get a little tricky. Operand2 actually has 2 different forms. Let's take a look
Ok, so for those, let's go ahead and make a new set of structures for each. Here's my comment code for those
Hidden Content
Ok, so let's go through and fill those two out, just so we have them
Hidden Content
Cool, but we still have a problem. We can't add these two structs to our instruction_data struct, because it would make it 12 bits too big. What can we do? Unions
So, you should be familiar with them by now, but here's a basic description of what they do. Unions work like structures, with one key difference. Member variables in a structure make the whole structure larger, while members in a union don't change its size at all. All members in a union share the same memory space, meaning if you change the values in one member, you change the values in all members. This is useful when you only ever need to store data in one of the members, like we do in this case. We will never need both the register and the immediate structure, and we know which one we need based on the imm bit in our instruction_data structure.
Let's go ahead and make that union. While we're at it, we can go ahead and take our planning comments out.
The updated code looks like this:
Hidden Content
I want to point out before we go any further, that I didn't use a bit field for imm in instruction_data_operand2_immedate. Before you all ask why, it's because it's an 8-bit field, and uint8_t is "unsigned 8-bit integer". A bit field would be fine here, but it would be set to 0x8, which is already how big the base type is. If you're OCD about it all, feel free to add it to your code
Now, we can go ahead and add our union to the instruction_data struct. We won't use a bit field here, because our union is exactly the right size already. Sorry to all you OCD fellas, this one won't line up either.
I'm also going to remove the planning comments.
With all that done, our entire instruction_data structure and all its dependencies are complete. Here is the full code for all of it:
Hidden Content
Ok, at this point, I think you've all got the hang of it, so I'm not going to hold your hand through writing the instruction_transfer and instruction_branch structures. I've included my code in a spoiler below for you to check your work.
instruction_transfer
Hidden Content
instruction_branch
Hidden Content
Ok, so at this point, all we have left to do is finish our instruction union. As you suspected, this will be easy since our union is going to be made up of all 32-bit structures, we don't need to do bit fields or any of that sort of thing.
Here's the code
Hidden Content
Alright, I apologize that this thread has run so long, but I'm happy we got through the tough stuff
Please stop at this point, until you have completed writing your instruction_transfer and instruction_branch structures. The remainder of this thread does not place those in spoilers
Ok, well since we got all the code hammered out, let's do a little refactoring. At this point, your entire instruction.h file should look like this:
Hidden Content
I want to refactor it all so that it properly fits the ARM spec. This pretty much just means changing the names of the elements to either their bit codes or their proper register notation.
At the end of that refactor, using the following register definitions
Rn = source register
Rd = destination register
Rm = 2nd register
My code looks like this
Hidden Content
Now, I think this header file is a bit too long for my comfort, and for reference (63 lines of struct defs), so I want to split this apart into 4 files:
- instruction.h
- instruction_data.h
- instruction_transfer.h
- instruction_branch.h
instruction.h
Hidden Content
instruction_data.h
Hidden Content
instruction_transfer.h
Hidden Content
instruction_branch.h
Hidden Content
Awesome! We've now taken the first 5 parts and made them into the foundation for our very first assembler! Let's go ahead and add our include to main.c just to wrap this up.
Hidden Content
One final note, if you try to build this right now, you will get an error like this
Do not worry, you didn't accidentally wipe it or something, it's just not set up properly.
Open the build settings
go into Search directories for the whole project
Click add, then make sure it points at your project (this path will be different for all users)
Now go ahead and click OK, save the project, then build it again
EDIT: I've restructured this project so it's a little more organized. I moved the instruction_x.h files to a folder called instruction and renamed them to just x.h.
This only effects instruction.h. Here's updated code for that file:
Hidden Content
and a screenshot of the project again:
Congrats! You've made it to the end of part 6! Things should start coming together in your mind about what's going to happen next.
PLEASE write replies to this thread! Comment on what you liked or didn't like. Ask questions. Suggest what we could do to make it better. Just have a conversation! I hate seeing these threads go stale.
Also, don't forget about the webpage that holds organized links to all of these. It's linked in my signature, but you can visit it by going to
[To see links please register here]
as well!UPDATE:
I realized that I made a mistake in
[To see links please register here]
, dealing with the structure for handling Operand2 when using a register. Rather than explain all of the changes, I'll simply paste the new contents of instruction/data.h below. I'll also be pasting this same block in part 6 (if I can still edit it).Hidden Content
[/hide]
[/hide]