Hello, if you have any need, please feel free to consult us, this is my wechat: wx91due
Assembly Project: Dr. Mario
1 Getting Started
For this project, you will be using MIPS assembly to implement a version of the popular retro game Dr.Mario.
Since we do not have access to a physical computer that uses MIPS processors, you will be creating and simulating your game using Saturn or MARS (or any other development tools that we provide). MARS and Saturn not only simulate the main processor but also a Bitmap Display and Keyboard input. If you have not already downloaded one of these simulators, see the Assembly Language Simulators page on Quercus and watch the recordings on Quercus that introduce MARS and assembly programming.
Read Section 2 to familiarize yourself with the game. Read Section 3 to familiarize yourself with the technical details of assembly and the simulators before getting started. Once you are ready to start, download the starter files and read Section 4 to see what is expected of you and when. In addition to the example code discussed in Section 3, we provide a file DrMario.asm with the beginnings of a game loop. It is this file that you will fill in to complete your assembly program.
1.1 Quick start: Saturn & MARS
2. Saturn is a similar IDE that was developed by Taylor Whatley, a former student and current TA of the course. As far as the project is concerned, it has all the features and capabilities of MARS, while also fixing all the bugs that MARS was known for. We are continuing to work on it and add new features, so please give us feedback on behaviours you notice or features that you’d want.
The download links for both of these IDEs can be found on Quercus.
1. Within Saturn or MARS, open the starter file DrMario.asm. You can do this by dragging DrMario.asm into the Saturn window.
a) Configure the Bitmap Display. Remember to configure the base address.b) To send your keystrokes to your MIPS window, click the bitmap window on the left. Your keystrokes will be sent to your MIPS assembly app as long as this window is in focus.
3. Click the green “Play” button on the top right corner to assemble and run your app. Check for any errors in the Console tab.
4. While the Bitmap Display is selected on Bitmap tab, enter characters like a, d, q.
2a. Configure the Bitmap Display. Remember to configure the base address.2b. Click Connect to MIPS, but don’t close the window.
3a. Click Connect to MIPS, but don’t close the window.
Note: Regardless of whether you use MARS or Saturn, you will need to add code so that your program responds to these keyboard inputs.
2 Dr. Mario: The Game
Dr. Mario is a falling block tile-matching video game. In the game, Mario is a doctor who tosses medical capsules into a medicine bottle, which serves as a vertical playing field (similar to Tetris).
Each capsule is made of two halves, where each half is coloured red, blue or yellow. The field is populated by viruses that are also coloured red, yellow or blue. These viruses remain in their initial positions until they are removed.
Like Tetris, the player can manipulate each capsule as it falls vertically from the top of the playing field, moving it left or right, rotating it 90 degrees clockwise or counter-clockwise, or dropping it down.
When four matching colors of capsule halves and viruses align vertically or horizontally in a row, they disappear. Any remaining capsule halves or whole capsules that are unsupported will fall to the bottom of the playing field or until they hit another supported object. Any new four-in-a-row alignments formed will also disappear.
Figure 2.1: Dr. Mario on Nintendo (1990)
If you haven’t seen or played this game before, you can try an online version of Dr. Mario here: https://www.retrogames.onl/2017/05/dr-mario-nes.html.
2.1 Game Controls
- The a key moves the capsule to the left.
- The d key moves the capsule to the right.
- The w key rotates the capsule by 90 degrees (usually clockwise).
- The s key moves the capsule toward the bottom of the playing field (either one line at a time or all at once, that’s your choice).
You may need additional keys for other operations, such as starting the game, quitting the game, pausing the game, resetting the game, etc. For the technical background on checking keyboard input, see Section 3.1.
2.2 The Capsules
As seen in Figure 2.1, each capsule is made of two halves, and each half can have one of three different colours (red, yellow and blue), resulting in six different combinations of colours.
Figure 2.2: Dr. Mario Capsules
For the technical background on drawing blocks, see Section 3.2.
2.3 The Viruses
Figure 2.3: Dr. Mario Viruses
2.4 Collision Detection
You’ll also need a way to detect if the current capsule collides with anything when the player tries to move it left or right. If there is a horizontal collision, the player’s capsule won’t move in that direction, but it also doesn’t get fixed in place. The player can still move the piece after horizontal collisions with other objects.
Storing the playing field and checking for collisions can be implemented in multiple ways. You can store a representation of the playing field as a grid of occupied or unoccupied spaced and then have a function that draws the game from this stored representation. Or just store the raw pixels and alter that as the game is played. Either way, you’ll want a function that checks for collisions with neighbouring spaces, both horizontally and vertically.
2.5 Eliminating Capsules and Viruses
In the arcade game, once all the viruses have been eliminated, the level is considered to be complete and the next level starts. For this project, you do not have to implement a next level for Milestones 1-3 (doing so is a feature for Milestones 4 or 5).
2.6 Game Over
3 Technical Background
Both Keyboard Input and Displaying Pixels use a concept called Memory Mapped I/O. This means that we can communicate with these peripherals as if they were in memory. Each peripheral (e.g., keyboard, bitmap display) has a corresponding memory address. Loading from, or storing to, that memory address (and nearby addresses) allows you to interface with the peripheral.
3.1 Keyboard Input
From your main development window, Press Ctrl + T (or Cmd + T on macOS) to open the terminal. Navigate to the Bitmap tab, which will display the bitmap window and settings. To send your keystrokes to your MIPS window, click on the bitmap window on the left. Your keystrokes will be sent to your MIPS assembly app as long as this window is in focus.
3.1.2 MARS keyboard input
If you are using MARS, you will need to use the Keyboard and Display MMIO Simulator to support keyboard input. You can find it under the Tools menu in MARS. Once the window is open (Figure 3.1), you must also click Connect to MIPS. For step-by-step instructions on how to set up MARS, see Section 1.1.
When a key is pressed, the processor will tell you by setting a location in memory (0xffff0000) to a value of 1. This means that your program won’t know that a key has been pressed until you check the contents of that memory address for a new keystroke event (an act known as polling). If that memory address has a value of 1, then a key has been pressed since the last time you checked. The ASCII-encoded value of the key that was pressed is found in the next word in memory (0xffff0004). Listing 3.1 shows an excerpt of how this works in MIPS.
3.2 Displaying Pixels
If you are using Saturn, you can view the Bitmap Display by pressing Ctrl + T (or Cmd + T on macOS) to open the terminal. Navigate to the Bitmap tab and configure the Bitmap Display to the dimensions you want for your game. Remember to configure the base address.
When you run your game, clicking on the bitmap window on the left will allow you to send keystroke inputs to your MIPS window.
If you are using MARS, use the Bitmap Display in MARS to simulate the output of a display (i.e., screen, monitor). You can find it under the Tools menu in MARS. A bitmap display can be configured in many different ways (Figure 3.2); make sure you configure the display properly before running your program. Once the display is configured, you must also click Connect to MIPS. For step-by-step instructions on how to setup MARS, see Section 1.1.
The game will appear on the Bitmap Display in MARS. The display, visually, is a 2D array of “units”, where each unit corresponds to a block of pixels. Here is how you can configure the display:
- The Unit Width in Pixels and Unit Height in Pixels is like a zoom factor. The values indicate how many pixels on the bitmap display are used to represent a single unit. For example, if you use 8 for both the width and height, then a single unit on the display would appear as an 8x8 box of a single colour on the display window.
- The Display Width in Pixels and Display Height in Pixels specified the width and height of the bitmap display. The dimensions of computer screens can vary, so once you specify the dimensions you would like to use, your code will calculate the positions of the units to draw based on those dimensions. For example, if your display width is 512 pixels and your unit width is 8 pixels, then your display is 64 units wide.
- The Base address for display indicates the location in memory that is used to display pixels on the screen.
Regardless of the IDE you choose, tou need to set the base address of display to memory location 0x10008000. This is because the bitmap display window checks this location (and subsequent locations) in memory to know what pixels your code has asked it to display. If this is left as another value (i.e. the default in MARS is the ”static data” location), the bitmap display will look for pixel values in the wrong section of memory, which may cause unexpected behaviour.
Memory is one-dimensional, but the screen is two-dimensional. Starting from the base address of the display, units are stored in a pattern called row major order :
- If you write a colour value in memory at the base address, a unit of that colour will appear in the top left corner of the Bitmap Display window.
- Writing a colour value to [the base address + 4] will draw a unit of that colour one unit to the right of the first one.
- Once you run out of unit locations in the first row, the next unit value will be written into the first column of the next row, and so on.
Each pixel uses a 4-byte colour value, similar to the encoding used for pixels in Lab 7. In this case, the first byte is not used. But the next 8 bits store the red component, the 8 bits after that store the green component and the final 8 bits store the blue component (remember: 1 byte = 8 bits). For example, 0x000000 is black, 0xff0000 is red and 0x00ff00 is green.
1. Calculate the colour code you want using the combination of red, green and blue components2. Calculate the pixel location based on the display’s width and height3. Finally, store that colour value at the correct memory address
3.3 System Calls
The sleep operation suspends the program for a given number of milliseconds. To invoke this operation, the value 32 is placed in $v0 and the number of milliseconds to wait is placed in $a0. The listing below tells the processor to wait for 1 second before proceeding to the next line:
To terminate a program gracefully, you do not need any arguments. The value to be placed in $v0 is
l i $v0 , 10 # t e rmi n a t e the program g r a c e f u l l y
There is also a system call for producing random numbers. To generate a random number, you can either place 41 or 42 in $v0. In both cases, the argument $a0 is used to indicate a random number generator ID (assuming you only use one random number generator, you can always use 0 here). When $v0 is 41, the system call produces a random integer. But when $v0 is 42, the system call produces a random integer up to a maximum value (exclusive). That maximum value must be provided in $a1. The listing below demonstrates how to generate a random number between 0 and 15:
For those familiar with Java, both Saturn and MARS fulfill these system calls by using Java.util.Random. If you want deterministic random values, you will need to use another system call to set the seed of your random number generator. Refer to the MIPS System Calls reference (link on Quercus in the Project module).
4 Deliverables and Demonstrations
You may work in pairs on the project, or you can choose to work on your own. If you wish to work in pairs, your partner does not have to be the same partner you had for the labs. However, we ask that your partner be from the same lab day as you, to maintain the student/TA ratio.
You demonstrate your project twice:
1. The first project demonstration is in Week 11, where you are meant to demo Milestone 3. Failing to demonstrate Milestone 1 will result in a penalty of 20% of your overall project mark (meaning you can get a maximum of 12/15 on the project).2. The second demonstration is in Week 12, where you demonstrate the finished project.3. In both cases, you submit your files on Quercus before 6pm on the day of your lab session (just like in labs). Everybody needs to submit their files individually, even if you’re working in pairs.
• Deliverable 1: Due on Quercus before 6pm on Monday March 24 (L0101) or Wednesday March 26 (L0201)• Demonstration 1: During the lab session you are enrolled in (March 24 or 26), 6pm-9pm• Deliverable 2: Due on Quercus before 6pm on Monday March 31 (L5101) or Wednesday April 2 (L0201)• Demonstration 2: During the lab session you are enrolled in (March 31 or April 2), 6pm-9pm
CAUTION
You must upload every required file for your deliverable submission to be complete. If you have questions about the submission process, please ask ahead of time. The required files for each deliverable are:
- Your project report: project_report.tex, project_report.pdf (as generated from the tex file)
- Your assembly code: DrMario.asm
1. Milestone 1: Draw the scene (static; nothing moves yet) (e.g., as shown in Figure 4.1)2. Milestone 2: Implement movement and other controls3. Milestone 3: Collision detection4. Milestone 4: Game features5. Milestone 5: More game features
Each milestone is worth 3 marks, for a total of 9 marks for Demonstration 1 (assuming you complete Milestone 3) and 15 marks for the Final Demonstration (based on how much of Milestones 1-5 you complete, more details below). In Demonstration 1, the expectation is that you demonstrate a project that has reached Milestone 3. In the final demonstration, the expectation is that you demonstrate a project that has reached at least Milestone 4.
Milestones that have not been reached by the final demonstration receive a 0. A milestone has been reached when the code for that milestone is working correctly and the implementation is non-trivial. For example, implementing Milestone 3 with single-colour capsules would trivialize the rotation task. So it is possible to only receive part marks for a milestone, if the TA deems the task too easy.
4.1 Preparing for Demonstration 1
a) Draw the medicine bottle representing the playing field.b) Draw the first two-halved capsule (at the initial location) with random colors (3 overall colors to choose from).
a) Move the capsule in response to the W, A, S and D keys (to make the capsule move left and right, rotate and drop).b) Re-paint the screen regularly to reflect the current layout of the pieces (60 times per second is the recommended frequency).c) Allow the player to press a key (e.g. ‘q’) to quit the game.
a) When a capsule moves into the left or right side wall of the medicine bottle, keep it in the same location.b) If the capsule that the player is controlling lands on top of another capsule, virus or the bottom of the playing area, do the following:
- Leave that capsule in its current location and generate a new capsule at the top of the playing area for the player to control.
- Remove any lines of four blocks of the same colour from the playing area, dropping any unsupported capsules in the process. If this results in another row of four blocks of the same colour, repeat this step until no rows of four remain.
- If the bottle entrance is blocked, end the game.
- Decide on how you will configure your bitmap display (i.e. the width and height in pixels). Include your configuration in the preamble of DrMario.asm. Remember to also include your name(s) and student number(s).
- Decide on what will be stored in memory, and how this data will be laid out. Grid diagrams (i.e. using graph paper) are particularly useful when planning the elements of Milestone 1. Include this plan in your report, and submit it on Quercus.
- Translate any sprites or pixel grids from your plan into the .data section of your DrMario.asm program. Assemble your program in Saturn or MARS and inspect memory to ensure it matches your plan. Submit a screenshot (or multiple screenshots) of memory demonstrating that it has been laid out according to your plan.
- Draw the scene (Milestone 1). Think carefully about functions that will help you accomplish this, and how they should be designed based on the variables you have in memory. Include a screenshot of this static scene in your report. Upload DrMario.asm to Quercus so that you have a snapshot of your progress so far.
- Implement movement and other controls (Milestone 2). Upload DrMario.asm to Quercus so that you have a snapshot of your progress so far.
- Decide on what should happen when the tetromino collides with an object.
- Implement collision detection (Milestone 3).
4.2 Preparing for the Final Demonstration
a) 5 easy featuresb) 3 easy features and 1 hard featurec) 1 easy feature and 2 hard featuresd) 3 hard features
a) 8 easy featuresb) 6 easy features and 1 hard featurec) 4 easy features and 2 hard featuresd) 2 easy feature and 3 hard featurese) 4 (or more) hard features
1. Save a working copy of your game (in case adding a new feature breaks something).2. Implement an additional easy or hard feature to your game.3. Repeat the previous step until you have achieved your goal for Milestone 4 and/or 5.4. Update your Demonstration 1 report based on any changes made.5. Include a section in your report titled “How to Play”. Include instructions for players based on the controls your game supports.
Easy Features
Hard Features
4.3 Advice
How long a program sleeps depends on the program, but even the fastest games only update their display 60 times per second. Any faster and the human eye cannot register the updates. So yes, even processors need their sleep.
Make sure to choose your display size and frame rate pragmatically. Simulated MIPS processors are not typically very fast. If you have too many pixels on the display and too high a frame rate, the processor will have trouble keeping up with the computation.
If you want to have a large display and fancy graphics in your game, you might consider optimizing your way of repainting the screen so that it does incremental updates instead of redrawing the whole screen. However, that may be quite a challenge.
Here are some general assembly programming tips:
Here are some tips that are specific to the Dr. Mario game: