This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
notes:comporg:spring2024:projects:dapx [2024/03/14 03:46] – [referencing relative to SP/BP] rspringe | notes:comporg:spring2024:projects:dapx [2024/03/24 23:43] – [Debug Registers] wgates1 | ||
---|---|---|---|
Line 5: | Line 5: | ||
====PUSH==== | ====PUSH==== | ||
- | In assembly language, " | + | In assembly language, " |
+ | |||
+ | NOTE: a **CALL** is basically a combined **PUSH** and **JMP**. The current address of the instruction being processed is what is pushed onto the stack before redirecting execution there. This is how the computer knows how to get back here when we ultimately **RET**urn from a called | ||
+ | |||
+ | Make sure not to push too many values to the stack, as this can cause a **STACK OVERFLOW**, which is when the values in the stack start overlapping with the program data. This can cause errors as the program tries to read the now corrupted data. | ||
+ | |||
+ | Similarly, make sure all stack transactions are balanced: ie for every PUSH there is an eventual encountered POP. POPping more than PUSHing can result in a **STACK UNDERFLOW**. | ||
====POP==== | ====POP==== | ||
- | On the other hand, "pop" is the inverse operation, retrieving a value from the stack. It usually | + | On the other hand, "***POP**" is the inverse operation: retrieving a value (the one most recently **PUSH**ed) |
====referencing relative to SP/BP==== | ====referencing relative to SP/BP==== | ||
Line 56: | Line 62: | ||
ret | ret | ||
</ | </ | ||
+ | |||
+ | =====Preserving our Textures===== | ||
+ | When making our debug function, we want it to strictly print out text and nothing else, if it were to do anything else than print out the text this can be perceived as an error and something that needs to be fixed. In order to preserve our texture we need to push it onto the stack before we execute the debug and pop it off the stack after debug has finished its run. | ||
+ | <code asm> | ||
+ | in R0, GPU_SelectedTexture | ||
+ | Push R0 | ||
+ | in R0, GPU_SelectedRegion | ||
+ | PUSH R0 | ||
+ | POP R0 | ||
+ | out GPU_SelectedRegion, | ||
+ | POP R0 | ||
+ | out GPU_SelectedTexture, | ||
+ | </ | ||
+ | Remember Pop in the reverse order of what you pushed and to push with a register you have already pushed to the stack in order to preserve that register as well. In this example you should push R0, and after the last out POP R0, to fully preserve the texture/ | ||
+ | |||
+ | Now that you have preserved the registers and textures you are free to change them as you please. Remember that the BIOS texture that you need to use to print out the ascii text for all your outputs is -1. | ||
+ | |||
+ | <code asm> | ||
+ | out GPU_SelectedTexture, | ||
+ | </ | ||
+ | |||
+ | And now that you are preserving your textures, it will go back to whatever you had before calling _debug. This can be extremely helpful if you are only using one texture for the whole game. | ||
=====bitwise operations===== | =====bitwise operations===== | ||
Line 140: | Line 168: | ||
You will want to use a register to shift (see the bitwise example in the public directory). The shift is used to keep track of the number of bits to shift the mask when extracting each nibble from the value when converting the variable to hexadecimal. It ensures that the correct number of bits are extracted from the variable during each iteration of the loop subroutine used for conversion. The 28th bit is the most significant nibble. To go to the next nibble, shift right 4 (shift left -4). | You will want to use a register to shift (see the bitwise example in the public directory). The shift is used to keep track of the number of bits to shift the mask when extracting each nibble from the value when converting the variable to hexadecimal. It ensures that the correct number of bits are extracted from the variable during each iteration of the loop subroutine used for conversion. The 28th bit is the most significant nibble. To go to the next nibble, shift right 4 (shift left -4). | ||
+ | |||
+ | To extract the digits of a two-digit number (e.g.,10, 11, 12, etc.), you can use division by 10 to find the quotient (tens digit) and modulus operation to find the remainder (ones digit). | ||
=====pseudocode===== | =====pseudocode===== | ||
Line 163: | Line 193: | ||
%include " | %include " | ||
</ | </ | ||
- | at the very end of your code. | + | at the very end of your code. THIS IS VERY IMPORTANT. If you include debug.s at the top of your code, the hexadecimal values may print but the remainder of the program in which you called __debug may not function as expected. |
=====debug function===== | =====debug function===== | ||
Line 170: | Line 200: | ||
<code text> | <code text> | ||
- | ASCII code for 0 --> 48 | + | ASCII code for 0 --> |
ASCII code for x --> 120 | ASCII code for x --> 120 | ||
+ | ASCII code for [ --> 92 | ||
+ | ASCII code for ] --> 93 | ||
+ | ASCII code for : --> 58 | ||
</ | </ | ||
Line 219: | Line 252: | ||
shl R4, -4 | shl R4, -4 | ||
</ | </ | ||
- | ====To | + | ====To |
Since we are working in hex and we need to convert to ascii we would usually add 48 to our value to get it's ascii equivalent, but that is with decimal, hex is slightly different. In hex, the values we know in decimal as 10-15 are now A-F. | Since we are working in hex and we need to convert to ascii we would usually add 48 to our value to get it's ascii equivalent, but that is with decimal, hex is slightly different. In hex, the values we know in decimal as 10-15 are now A-F. | ||
Line 225: | Line 258: | ||
* Otherwise, if the value is < 10, then we add 48 like we normally would. | * Otherwise, if the value is < 10, then we add 48 like we normally would. | ||
* And then just repeat what we did before but change your Shift and Mask values as need be. | * And then just repeat what we did before but change your Shift and Mask values as need be. | ||
- | =====debugmemory function====== | ||
+ | Why +7? Take a look at the arrangement of values in the ASCII table: | ||
+ | |||
+ | ^ symbol | ||
+ | | ’0’ | ||
+ | | ’1’ | ||
+ | | ’2’ | ||
+ | | ’3’ | ||
+ | | ’4’ | ||
+ | | ’5’ | ||
+ | | ’6’ | ||
+ | | ’7’ | ||
+ | | ’8’ | ||
+ | | ’9’ | ||
+ | | ’: | ||
+ | | ’; | ||
+ | | ’< | ||
+ | | ’=’ | ||
+ | | ’> | ||
+ | | ’? | ||
+ | | ’@’ | ||
+ | | ’A’ | ||
+ | | ’B’ | ||
+ | |||
+ | Notice how 0xA in hex (decimal 10), when we add 48/0x30 to it, would be 48+10=58 / 0x30+0xA = 0x3A, the ’:’. But if we add an additional 7 to it (58+7=65; 0x3A+7=0x41) we arrive at the desired ’A’. | ||
+ | ======debugmemory function======= | ||
+ | |||
+ | NOTE: One of the requirements is to call _debug to display information while using debugmemory in the same debug.s file. The setup will be somewhat similar to _debug. | ||
+ | |||
+ | Even though we are calling _debug you'll still want to push everything at the start and pop everything at the end of _debugmemory. | ||
+ | |||
+ | Here are some tips (feel free to edit with more information): | ||
+ | |||
+ | * First you will want to set up. This would include doing the same setup for _debug but you are manually setting the X and Y values (0,0 is recommended) and will be using [BP+ some value] to get your two parameters. | ||
+ | * Then you'll want to create a loop. | ||
+ | * You'll want a way to know when parameter one igt parameter two. | ||
+ | * Keep in mind _debug works with calling stuff from the stack so you might have to update the stack like you would when calling it from your game. | ||
+ | * Don't forget to update your X, Y, and parameter one! | ||
+ | |||
+ | ===Displaying=== | ||
+ | When considering the output we see the following: | ||
+ | <code text> | ||
+ | [0x200001A6]: | ||
+ | </ | ||
+ | |||
+ | We see a hex value in brackets, which is the memory address, and the hex value that is not in brackets which is the value stored at that given memory address. | ||
+ | |||
+ | In dap0 we could get the value given some register but how do we get the memory address? Well, you can actually use your debug.s function! To display the memory address simply copy (or do something similar) to the following example: | ||
+ | |||
+ | <code asm> | ||
+ | ; Push the parameters for the _debug subroutine to display memory | ||
+ | push R1 ; Memory address | ||
+ | push R3 ; X coordinate | ||
+ | push R4 ; Y coordinate | ||
+ | |||
+ | ; Call _debug to display the memory address | ||
+ | call _debug | ||
+ | |||
+ | pop R4 ; Y coordinate | ||
+ | pop R3 ; X coordinate | ||
+ | pop R6 ; Memory address | ||
+ | </ | ||
+ | |||
+ | The only thing you need to note is how we push the register and take a mental note of how we did it. Lets not display the value at that given memory address: | ||
+ | |||
+ | <code asm> | ||
+ | ; Push the parameters for the _debug subroutine to display value at memory address | ||
+ | mov R6, [R1] ; Putting value in R6 | ||
+ | push R6 ; Value | ||
+ | push R5 ; X coordinate | ||
+ | push R4 ; Y coordinate | ||
+ | call _debug | ||
+ | |||
+ | pop R4 ; Y coordinate | ||
+ | pop R5 ; X coordinate | ||
+ | pop R6 ; value | ||
+ | </ | ||
+ | |||
+ | Notice how in displaying the value at a given memory address we put brackets around the register and then move that into another register (R6 in this case) and then push R6 instead of the original R1. | ||
+ | ======debugregister function====== | ||
=====dapX imagery===== | =====dapX imagery===== | ||
Line 270: | Line 381: | ||
*ior - " | *ior - " | ||
+ | |||
+ | |||
+ | ======Debug Registers====== | ||
+ | |||
+ | ===Printing out R:=== | ||
+ | To print the registers you have to figure out how to print out the R, the :, and the number that goes along with it. In this it is important to note that the ascii value for R is 82, and the ascii value for : is 58. Thus printing these out sequentially will look something like this. Remember to have your texture set to -1 so the text shows up. | ||
+ | |||
+ | <code asm> | ||
+ | mov R0, 82 ; printing R | ||
+ | out GPU_SelectedRegion, | ||
+ | out GPU_DrawingPointX, | ||
+ | out GPU_DrawingPointY, | ||
+ | out GPU_Command, | ||
+ | iadd R1, 10 | ||
+ | | ||
+ | ;Print out the number here | ||
+ | | ||
+ | mov R0, 58 ; printing : | ||
+ | out GPU_SelectedRegion, | ||
+ | out GPU_DrawingPointX, | ||
+ | out GPU_DrawingPointY, | ||
+ | out GPU_Command, | ||
+ | </ | ||
+ | |||
+ | To print out the number in the middle, we first need to check if the number is greater than 10. If it is then we print out a 1 then subtract 10 from it, this is so we can do a ascii shift with the second number that changes it to the number we want to print. | ||
+ | |||
+ | <code asm> | ||
+ | ;R5 holds the value we want to print. | ||
+ | mov R1, R5 | ||
+ | mov R2, R5 | ||
+ | ige R2, 10 | ||
+ | jf R2, _less_than_10 | ||
+ | |||
+ | ;printing out a 1 | ||
+ | mov R0, 49 | ||
+ | out GPU_SelectedRegion, | ||
+ | out GPU_DrawingPointX, | ||
+ | out GPU_DrawingPointY, | ||
+ | out GPU_Command, | ||
+ | iadd R3, 10 | ||
+ | |||
+ | isub R1, 10 ;we subtract 10 as 1 has already been printed | ||
+ | |||
+ | _less_than_10: | ||
+ | iadd R1, 48 ;ascii shift by 48 to print out the number | ||
+ | out GPU_SelectedRegion, | ||
+ | out GPU_DrawingPointX, | ||
+ | out GPU_DrawingPointY, | ||
+ | out GPU_Command, | ||
+ | </ | ||
+ | |||
+ | The last step is to put both of these together in a loop, remember to change the X/Y at the end of the loop. | ||
+ | |||
+ | ===Printing registers=== | ||
+ | ===Calling debugregs=== | ||
+ | As we have worked on these dap projects, the process of calling such debug subroutines has become simpler. With dap0, we had to have the following in our program: | ||
+ | <code asm> | ||
+ | | ||
+ | push TMP | ||
+ | | ||
+ | push TMP | ||
+ | | ||
+ | push TMP | ||
+ | | ||
+ | </ | ||
+ | Then later after the hlt, you'll always have the %include " | ||
+ | |||
+ | Concerning dap2, we have drastically simplified the process of debugging. All that is need is just one line, Not accounting for the include line. Put the following to use your debug registers subroutine: | ||
+ | |||
+ | <code asm> | ||
+ | call _debugregs | ||
+ | </ |