├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── assets └── chip8_1.png ├── inc ├── chip8.h └── peripherals.h ├── roms ├── 15PUZZLE.ch8 ├── AIRPLANE.ch8 ├── BLINKY.ch8 ├── BLITZ.ch8 ├── BREAKOUT.ch8 ├── BRIX.ch8 ├── CAVE.ch8 ├── CONNECT4.ch8 ├── FIGURES.ch8 ├── FILTER.ch8 ├── GUESS.ch8 ├── HIDDEN.ch8 ├── HIDDEN.txt ├── INVADERS.ch8 ├── JOUST.txt ├── KALEID.ch8 ├── LANDING.ch8 ├── MAZE.ch8 ├── MERLIN.ch8 ├── MISSILE.ch8 ├── PADDLES.ch8 ├── PONG(1P).ch8 ├── PONG.ch8 ├── PONG2.ch8 ├── PUZZLE.ch8 ├── ROCKET.ch8 ├── SOCCER.ch8 ├── SOURCES │ ├── 15PUZZLE.SRC │ ├── BLINKY.SRC │ ├── BREAKOUT.SRC │ ├── BRIX.SRC │ ├── MAZE.SRC │ ├── PONG.SRC │ ├── PONG2.SRC │ ├── SYZYGY.SRC │ ├── UFO.SRC │ └── VBRIX.SRC ├── SPACEF.ch8 ├── SQUASH.ch8 ├── SYZYGY.ch8 ├── TANK.ch8 ├── TEST │ ├── C8PIC.ch8 │ ├── IBM.ch8 │ ├── Rocket2.ch8 │ ├── TAPEWORM.ch8 │ ├── TIMEBOMB.ch8 │ └── X-MIRROR.ch8 ├── TETRIS.ch8 ├── TICTAC.ch8 ├── TRON.ch8 ├── UFO.ch8 ├── VBRIX.ch8 ├── VERS.ch8 ├── WALL.ch8 └── WIPEOFF.ch8 ├── src ├── chip8.c ├── main.c └── peripherals.c └── test_emu.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | .vscode 54 | build -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Leonardo Folgoni 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | CFLAGS = -Iinc -I/usr/local/include -Wall -Wextra -pedantic -std=c99 3 | LDFLAGS = -L/usr/local/lib 4 | LIBS = -lm -lSDL2 5 | 6 | sources = src/main.c src/chip8.c src/peripherals.c 7 | objects = build/main.o build/chip8.o build/peripherals.o 8 | headers = inc/chip8.h inc/peripherals.h 9 | 10 | all: bin/emulator.out 11 | 12 | bin/emulator.out: $(objects) $(headers) 13 | @mkdir -p bin 14 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(objects) $(LIBS) 15 | 16 | build/%.o: src/%.c 17 | @mkdir -p build 18 | $(CC) -c $< $(CFLAGS) $(LDFLAGS) $(LIBS) -o$@ 19 | 20 | clean: 21 | rm -rf bin build 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CHIP-8 Emulator 2 | 3 | A simple emulator for the CHIP-8 interpreted programming language written in C (SDL for graphics). 4 | 5 | ## About 6 | 7 | This is a really basic emulator written for educational purposes, the code is meant to be readable and clear, with a lot of comments. I am a beginner in this field and this is my first attempt to emulators. I have implemented this project mainly by following the [Wikipedia page](https://en.wikipedia.org/wiki/CHIP-8) and [this](http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#0.1) awesome resource; I had no experience with SDL either so I have helped myself during that process with various resources online. **The most important part to me was understanding the architecture itself, not the graphics**. 8 | 9 | ## Requirements 10 | 11 | This project has been developed under a Linux system. 12 | 13 | - SDL library 14 | - C compiler 15 | 16 | ## Run 17 | 18 | `make` 19 | 20 | `./bin/emulator.out ` 21 | 22 | Or you could use the `test_emu` script I wrote to automate the process of testing the program. 23 | 24 | `./test_emu.sh` 25 | 26 | ## Quick Walkthrough 27 | 28 | By reading [here](http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#0.1): 29 | 30 | ``` 31 | Chip-8 is a simple, interpreted, programming language which was first used 32 | on some do-it-yourself computer systems in the late 1970s and early 1980s. 33 | The COSMAC VIP, DREAM 6800, and ETI 660 computers are a few examples. 34 | These computers typically were designed to use a television as a display 35 | had between 1 and 4K of RAM, and used a 16-key hexadecimal keypad for input. 36 | The interpreter took up only 512 bytes of memory, and programs, which were entered into the computer in hexadecimal, were even smaller 37 | ``` 38 | 39 | So this emulator replicates this behaviour by creating a virtual machine with the following specs: 40 | 41 | - 4096 Bytes of memory 42 | - 16 general 8-bit purpose registers 43 | - A special 16-bit register 44 | - ProgramCounter and StackPointer pseudo registers 45 | - The stack (array of 16 16-bit values) 46 | - The keypad (adapted to modern keyboards) 47 | - 64x32 pixels monochrome screen 48 | - Delay timer 49 | - Sound timer 50 | 51 | The emulator is then able to run `.ch8` games. Please note that I have written only the emulator itself, not the games (freely accessible on the Internet). 52 | 53 | The emulator logic consits of parsing and executing the instructions coming from those games. 54 | 55 | ![scr_1](./assets/chip8_1.png) 56 | 57 | The default mode is `debug` mode, which outputs a lot of stuff to the screen, if you want to disable it you have to set the `int DEBUG = 1;` variable to `0` in `chip8.c`. 58 | 59 | ## Improvements 60 | 61 | - Sound support 62 | - I was lazy and focused more on the interpreter so there's no sound here 63 | - Use [function pointers](http://www.multigesture.net/wp-content/uploads/mirror/zenogais/FunctionPointers.htm) instead of big switch statements. 64 | 65 | ## References 66 | 67 | - [Wikipedia](https://en.wikipedia.org/wiki/CHIP-8) 68 | - [Cowgod's Chip-8 Technical Reference v1.0](http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#0.1) 69 | 70 | Another good article 71 | 72 | - [How to write an emulator chip8 interpreter](http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/) 73 | 74 | Improvements 75 | 76 | - [Function pointers](http://www.multigesture.net/wp-content/uploads/mirror/zenogais/FunctionPointers.htm) 77 | -------------------------------------------------------------------------------- /assets/chip8_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/assets/chip8_1.png -------------------------------------------------------------------------------- /inc/chip8.h: -------------------------------------------------------------------------------- 1 | #ifndef CHIP8_H_ 2 | #define CHIP8_H_ 3 | 4 | extern unsigned char fontset[80]; 5 | extern unsigned char memory[4096]; 6 | extern unsigned char V[16]; 7 | extern unsigned short I; 8 | extern unsigned short pc; 9 | extern unsigned char sp; 10 | extern unsigned short stack[16]; 11 | extern unsigned char keypad[16]; 12 | extern unsigned char display[64 * 32]; 13 | extern unsigned char dt; 14 | extern unsigned char st; 15 | extern unsigned char draw_flag; 16 | extern unsigned char sound_flag; 17 | 18 | void init_cpu(void); 19 | int load_rom(char* filename); 20 | void emulate_cycle(void); 21 | 22 | #define error(...) fprintf(stderr, __VA_ARGS__) 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /inc/peripherals.h: -------------------------------------------------------------------------------- 1 | #ifndef CHIPEE_PERIPHERALS_H_ 2 | #define CHIPEE_PERIPHERALS_H_ 3 | 4 | void init_display(); 5 | void draw(unsigned char* display); 6 | void sdl_ehandler(unsigned char* keypad); 7 | void stop_display(); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /roms/15PUZZLE.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/15PUZZLE.ch8 -------------------------------------------------------------------------------- /roms/AIRPLANE.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/AIRPLANE.ch8 -------------------------------------------------------------------------------- /roms/BLINKY.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/BLINKY.ch8 -------------------------------------------------------------------------------- /roms/BLITZ.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/BLITZ.ch8 -------------------------------------------------------------------------------- /roms/BREAKOUT.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/BREAKOUT.ch8 -------------------------------------------------------------------------------- /roms/BRIX.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/BRIX.ch8 -------------------------------------------------------------------------------- /roms/CAVE.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/CAVE.ch8 -------------------------------------------------------------------------------- /roms/CONNECT4.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/CONNECT4.ch8 -------------------------------------------------------------------------------- /roms/FIGURES.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/FIGURES.ch8 -------------------------------------------------------------------------------- /roms/FILTER.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/FILTER.ch8 -------------------------------------------------------------------------------- /roms/GUESS.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/GUESS.ch8 -------------------------------------------------------------------------------- /roms/HIDDEN.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/HIDDEN.ch8 -------------------------------------------------------------------------------- /roms/HIDDEN.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------- 2 | HIDDEN! 3 | Copyright (1996) by David WINTER 4 | ---------------------------------------- 5 | 6 | 7 | HIDDEN is a "memory" game. It is very simple to play. 8 | 9 | The rules are as follow: your goal is to find all the identical cards 10 | in a minimum time. 11 | 12 | You are playing in a 4*4 card grid. You can see only two cards at the 13 | same time. Once this time passed, these two cards will remain shown 14 | if they are identical, otherwise they will be hidden again. 15 | 16 | When the game is finished, two scores are shown: 17 | SC is your score, corresponding to the number of tries 18 | HI is the best score (smallest number of tries made to finish) 19 | 20 | The keys are: 21 | 22 | [2] : More DOWN 23 | [4] : Move LEFT 24 | [5] : Show card 25 | [6] : Move RIGHT 26 | [8] : Move UP 27 | 28 | Enjoy !!! 29 | -------------------------------------------------------------------------------- /roms/INVADERS.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/INVADERS.ch8 -------------------------------------------------------------------------------- /roms/JOUST.txt: -------------------------------------------------------------------------------- 1 | Joust 1.0, a CHIP48 game by Zoom: 2 | 3 | Hoorah! Hoorah! Here it is, the latest CHIP48 game; my rendition 4 | of the arcade game Joust. Both ->ASC and UUENCODE versions are attached. 5 | 6 | You can get ASC-> (an HP48sx program by Bill Wickes) by anonymous ftp 7 | at seq.uncwil.edu (Wayne Scott's Mailserver archive, 8 | path: hp48/util/ascii.encode.Z (set ftp to binary, use UNCOMPRESS in UNIX). 9 | 10 | A PC based version of UUDECODE is available on the HPBBS in the 11 | user.programs conference. 12 | 13 | CHIP48v2.25 and documentation is available at seq.uncwil.edu 14 | path: hp48/chip8/chip-48.Z (binary) 15 | 16 | The Game: 17 | 18 | 1) Download the file and use ASC-> on the string. 19 | 2) The result of step 1 is taken as an argument by 20 | CHIP, this runs the game. 21 | 3) Check out the title screen then press 0 to play. 22 | 4) The keys are: 23 | 24 | 0 = Down 25 | 9 = Left 26 | / = Right 27 | 28 | 5) The blank dots in the bottom left corner indicate 29 | the number of players left, not including the current 30 | player. Sorry, no bonus guys. Maybe in the future. 31 | 32 | 6) At the score screen press 0 to replay, else press drop 33 | to exit to the stack. 34 | 35 | 36 | If you feel the game is slow, then wait until you get to level 7! 37 | The levels roll over at #Fh, I think. I haven't gotten that far! 38 | Therefore there maybe unseen bugs. 39 | 40 | The game is novel. I'm not sure of its lasting qualities. 41 | However, it was a good exercise in CHIP programming. Which 42 | reminds me: 43 | 44 | - I claim no rights, its just a game. Anyway, what could I do? 45 | Send the cops after you? On the other hand, please send me 46 | email for comments, questions, bugs. On bugs, try to give 47 | plenty of detail. Debugging these games is a nightmare, but 48 | its a challenge I enjoy (contradiction?). 49 | 50 | my email address: catto@ecn.purdue.edu 51 | 52 | You can post on comp.sys.handhelds, but I only view once or 53 | twice a week. 54 | 55 | CREDITS: 56 | 57 | 1) Andreas Gustafsson for his excellent interpreter, CHIP48v2.25. 58 | 2) Gilles Kohl for his AS48 CHIP assembler. 59 | 60 | I haven't tried to run Joust on SuperCHIP. If I have enough energy I 61 | will convert Joust to take advantage of the extended graphics. 62 | 63 | On Source Code: 64 | 65 | I will eventually post source code in AS48, soon if requested. I will 66 | archive it at seq.uncwil.edu and the HPBBS along with Joust. 67 | 68 | However, I am more interested in posting some CHIP48 programming notes 69 | to generate more interest in actually writing these games. This is the 70 | fifth game posted since CHIP's release, how many assemblers? Assemblers 71 | are great and Joust wouldn't have been possible without one, but I think 72 | people must have difficulty programming in CHIP48 (it wasn't a cinch for 73 | me). Sooooo, I will try to help with some programming notes. 74 | 75 | Enjoy! 76 | 77 | Zoom-> 78 | 79 | The real question: Should I by a Smith Corona card? 80 | 81 | 82 | Joust string: Bytes: 1426 83 | Checksum: #87F2h 84 | -------------------------------------------------------------------------------- /roms/KALEID.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/KALEID.ch8 -------------------------------------------------------------------------------- /roms/LANDING.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/LANDING.ch8 -------------------------------------------------------------------------------- /roms/MAZE.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/MAZE.ch8 -------------------------------------------------------------------------------- /roms/MERLIN.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/MERLIN.ch8 -------------------------------------------------------------------------------- /roms/MISSILE.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/MISSILE.ch8 -------------------------------------------------------------------------------- /roms/PADDLES.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/PADDLES.ch8 -------------------------------------------------------------------------------- /roms/PONG(1P).ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/PONG(1P).ch8 -------------------------------------------------------------------------------- /roms/PONG.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/PONG.ch8 -------------------------------------------------------------------------------- /roms/PONG2.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/PONG2.ch8 -------------------------------------------------------------------------------- /roms/PUZZLE.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/PUZZLE.ch8 -------------------------------------------------------------------------------- /roms/ROCKET.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/ROCKET.ch8 -------------------------------------------------------------------------------- /roms/SOCCER.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/SOCCER.ch8 -------------------------------------------------------------------------------- /roms/SOURCES/15PUZZLE.SRC: -------------------------------------------------------------------------------- 1 | ; From: SLSW2@cc.usu.edu (Roger Ivie) 2 | ; 3 | ; Here's PUZZLE.SRC, the infamous "15" puzzle for the calculator. I'm including 4 | ; it mainly as an example of how to use my CHIP8 macros. 5 | ; 6 | ; When running PUZZLE, the 4x4 keyboard area used by CHIP8 corresponds to the 7 | ; screen in the obvious manner. Simply press the key corresponding to the 8 | ; location that you want the hole to be moved and it will migrate there. The 9 | ; hole is moved up, down, left, then right until it winds up at the requested 10 | ; location. 11 | ; 12 | ; Once the program is started, pressing ENTER randomizes the board (the magic 13 | ; of self-modifying code). 14 | ; 15 | ; The program has absolutely no idea whether or not you've solved the puzzle, 16 | ; so it doesn't do anything special. 17 | ; 18 | ; Enjoy, 19 | ; 20 | ; Roger Ivie 21 | ; slsw2@cc.usu.edu 22 | ; 23 | ; PS: I'll post a binary as soon as I can get to my local Unix box again (the 24 | ; hardware hackers have taken over). 25 | 26 | 27 | ; Register usage: 28 | ; 29 | ; V0 - Used to grab things from memory 30 | ; V1 - Current piece to be displayed 31 | ; V2 - X coordinate where it is to be displayed 32 | ; V3 - Y coordinate where it is to be displayed 33 | ; V4 - General work; new hole position for swap_hole 34 | ; V5 - General work 35 | ; V6 - 36 | ; V7 - 37 | ; V8 - 38 | ; V9 - 39 | ; VA - 40 | ; VB - 41 | ; VC - Number of random moves to insert into the puzzle 42 | ; VD - Desired position of the hole 43 | ; VE - Current position of the hole 44 | ; VF - 45 | 46 | 47 | option binary 48 | align off 49 | 50 | CLS 51 | 52 | START: 53 | LD VC, 0 54 | SNE VC, 0 55 | DB #6E ; 6E0F -> VE = 15: number of moves to randomize 56 | START+1: 57 | DB #0F 58 | LD I, START+1 ; Plug the number of moves to randomize 59 | LD V0, 32 60 | LD [I], V0 61 | CLS ; Clear the screen 62 | 63 | LOOP: 64 | CALL GET_MOVE 65 | CALL MOVE_UP 66 | CALL MOVE_DOWN 67 | CALL MOVE_LEFT 68 | CALL MOVE_RIGHT 69 | JP LOOP 70 | 71 | ;------------------ 72 | 73 | XSTART EQU 23 ; Horizontal position of board 74 | YSTART EQU 4 ; Vertical position of board 75 | XOFF EQU 5 ; Horizontal offset to next piece 76 | YOFF EQU 6 ; Vertical offset to next piece 77 | 78 | DISPLAY: 79 | 80 | ; State 1: Initialize everything to be about the first piece on the board 81 | ; and go to state 2. 82 | 83 | DISPLAY_1: 84 | LD V1,0 85 | LD V2,XSTART 86 | LD V3,YSTART 87 | 88 | ; State 2: If all pieces have been displayed, exit. Otherwise, go to state 3. 89 | 90 | DISPLAY_2: 91 | SNE V1, #10 92 | RET 93 | 94 | ; State 3: Get the next piece to be displayed. If it's the hole (and therefore 95 | ; shouldn't be displayed), go to state 5. Otherwise go to state 4. 96 | 97 | DISPLAY_3: 98 | LD I,BOARD 99 | ADD I,V1 100 | LD V0,[I] 101 | SNE V0,0 102 | JP DISPLAY_5 103 | 104 | ; State 4: Display the current piece and go to state 5. 105 | 106 | DISPLAY_4: 107 | LD F, V0 108 | DRW V2,V3,5 109 | 110 | ; State 5: Advance the piece pointer and the horizontal position of the 111 | ; display to the next piece. If the new piece is the first in a new row, 112 | ; go to state 6. Otherwise go to state 2. 113 | 114 | DISPLAY_5: 115 | ADD V1,1 116 | ADD V2,XOFF 117 | LD V4,3 118 | AND V4,V1 119 | SE V4,0 120 | JP DISPLAY_2 121 | 122 | ; State 6: The piece is the first of a new row. Reinitialize the horizontal 123 | ; position to the first of the row and advance the vertical position to the 124 | ; next row. Go to state 2. 125 | 126 | DISPLAY_6: 127 | LD V2,XSTART ; Start at beginning of next row. 128 | ADD V3,YOFF 129 | JP DISPLAY_2 130 | 131 | ;------- 132 | 133 | MOVE_RIGHT: 134 | 135 | ; State 1: Check to see if the desired hole position and the current hole 136 | ; position are in the same column. If so, exit. Otherwise, go to state 2. 137 | 138 | MOVE_RIGHT_1: 139 | LD V4,3 ; Get horizontal position of hole 140 | AND V4,VE 141 | LD V5,3 ; Get horizontal position of new hole 142 | AND V5,VD 143 | SNE V4,V5 144 | RET 145 | 146 | ; State 2: If the hole cannot be moved any farther right, exit. Otherwise 147 | ; go to state 3. 148 | 149 | MOVE_RIGHT_2: 150 | SNE V4,3 151 | RET 152 | 153 | ; State 3: Move the hole right one position and go back to state 1. 154 | 155 | MOVE_RIGHT_3: 156 | LD V4,1 157 | ADD V4,VE 158 | CALL SWAP_HOLE 159 | JP MOVE_RIGHT_1 160 | 161 | ;------- 162 | 163 | MOVE_LEFT: 164 | 165 | ; State 1: Check to see if the desired hole position and the current hole 166 | ; position are in the same column. If so, exit. Otherwise, go to state 2. 167 | 168 | MOVE_LEFT_1: 169 | LD V4,3 ; Get horizontal position of hole 170 | AND V4,VE 171 | LD V5,3 ; Get horizontal position of new hole 172 | AND V5,VD 173 | SNE V4,V5 174 | RET 175 | 176 | ; State 2: If the hole cannot be moved any farther left, exit. Otherwise 177 | ; go to state 3. 178 | 179 | MOVE_LEFT_2: 180 | SNE V4,0 181 | RET 182 | 183 | ; State 3: Move the hole left one position and go back to state 1. 184 | 185 | MOVE_LEFT_3: 186 | LD V4, #FF ; 187 | ADD V4,VE 188 | CALL SWAP_HOLE 189 | JP MOVE_LEFT_1 190 | 191 | ;------- 192 | 193 | MOVE_UP: 194 | 195 | ; State 1: Check to see if the desired hole position and the current hole 196 | ; position are in the same row. If so, exit. Otherwise, go to state 2. 197 | 198 | MOVE_UP_1: 199 | LD V4, #0C ; Get vertical position of hole 200 | AND V4,VE 201 | LD V5, #0C ; Get vertical position of new hole 202 | AND V5,VD 203 | SNE V4,V5 204 | RET 205 | 206 | ; State 2: If the hole cannot be moved any farther up, exit. Otherwise 207 | ; go to state 3. 208 | 209 | MOVE_UP_2: 210 | SNE V4,0 211 | RET 212 | 213 | ; State 3: Move the hole up one position and go back to state 1. 214 | 215 | MOVE_UP_3: 216 | LD V4, #FC ; Up = left 4 217 | ADD V4,VE 218 | CALL SWAP_HOLE 219 | JP MOVE_UP_1 220 | 221 | ;------- 222 | 223 | MOVE_DOWN: 224 | 225 | ; State 1: Check to see if the desired hole position and the current hole 226 | ; position are in the same row. If so, exit. Otherwise, go to state 2. 227 | 228 | MOVE_DOWN_1: 229 | LD V4, #0C ; Get vertical position of hole 230 | AND V4,VE 231 | LD V5, #0C ; Get vertical position of new hole 232 | AND V5,VD 233 | SNE V4,V5 234 | RET 235 | 236 | ; State 2: If the hole cannot be moved any farther down, exit. Otherwise 237 | ; go to state 3. 238 | 239 | MOVE_DOWN_2: 240 | SNE V4, #0C 241 | RET 242 | 243 | ; State 3: Move the hole down one position and go back to state 1. 244 | 245 | MOVE_DOWN_3: 246 | LD V4,4 ; Down = right 4 247 | ADD V4,VE 248 | CALL SWAP_HOLE 249 | JP MOVE_DOWN_1 250 | 251 | ;------- 252 | 253 | SWAP_HOLE: 254 | LD I,BOARD ; Get the piece at the new hole position 255 | ADD I,V4 256 | LD V0,[I] 257 | LD I,BOARD ; Put it at the old hole position 258 | ADD I,VE 259 | LD [I],V0 260 | LD V0,0 ; Put a hole... 261 | LD I,BOARD ; ...at the new hole position 262 | ADD I,V4 263 | LD [I],V0 264 | LD VE,V4 ; Move the hole marker to the new position 265 | RET 266 | 267 | ;------- 268 | 269 | GET_MOVE: 270 | 271 | ; State 1: Check to see if there are any more random moves to select. If so, 272 | ; go to state 5. Otherwise go to state 2. 273 | GET_MOVE_1: 274 | SE VC,0 275 | JP GET_MOVE_5 276 | 277 | ; State 2: Prompt for and obtain a keystroke: display the board, wait for 278 | ; a keystroke, and then erase the board. Go to state 4. 279 | 280 | GET_MOVE_2: 281 | CALL DISPLAY 282 | CALL MYKEY 283 | CALL DISPLAY 284 | 285 | ; State 3: 286 | 287 | ; State 4: Translate the keystroke to the new hole position and exit. 288 | 289 | GET_MOVE_4: 290 | LD I,KEYTABLE 291 | ADD I,VD 292 | LD V0,[I] 293 | LD VD,V0 294 | RET 295 | 296 | ; State 5: Decrement the count of random moves remaining, select a random 297 | ; hole position, and exit. 298 | 299 | GET_MOVE_5: 300 | ADD VC, #FF ; 301 | RND VD, #0F 302 | RET 303 | 304 | ;------- 305 | 306 | MYKEY: 307 | 308 | ; State 1: Continuously scan the keyboard until a key is pressed. When a 309 | ; key is pressed, go to state 2. 310 | 311 | MYKEY_1: 312 | ADD VD,1 ; Advance to next key number. 313 | LD V0, #0F ; Make certain that it's not bigger than 0FH 314 | AND VD,V0 315 | SKP VD ; If this key is down, go to state 2. 316 | JP MYKEY_1 ; Otherwise stay in state 1. 317 | 318 | ; State 2: Wait for the key to be released. When it is, exit. 319 | 320 | MYKEY_2: 321 | SKNP VD 322 | JP MYKEY_2 323 | RET 324 | 325 | ;------- 326 | 327 | ; The puzzle board 328 | 329 | BOARD: 330 | DB 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 331 | 332 | ; Translation table from key number to hole position 333 | 334 | KEYTABLE: 335 | DB #0D, #00, #01, #02 336 | DB #04, #05, #06, #08 337 | DB #09, #0A, #0C, #0E 338 | DB #03, #07, #0B, #0F 339 | 340 | END 341 | -------------------------------------------------------------------------------- /roms/SOURCES/BLINKY.SRC: -------------------------------------------------------------------------------- 1 | ; (S)Chip-48 Blinky V2.00 by Christian Egeberg 7/11-'90 .. 18/8-'91 2 | ; EMail at egeberg@solan.unit.no 3 | ; 4 | ; Register usage: 5 | ; V0: Temporary data, may change during any call 6 | ; V1: Temporary data, may change during any call 7 | ; V2: Temporary data, may change during most calls 8 | ; V3: Temporary data, may change during most calls 9 | ; V4: Temporary data, may change during some calls 10 | ; V5: Temporary data, may change during some calls 11 | ; V6: Pill and score counter 12 | ; V7: Life and sprite direction register 13 | ; V8: Blinky X screen coordinate 14 | ; V9: Blinky Y screen coordinate 15 | ; VA: Packlett X screen coordinate 16 | ; VB: Packlett Y screen coordinate 17 | ; VC: Heward X screen coordinate 18 | ; VD: Heward Y screen coordinate 19 | ; VE: Temporary constant and flag storage 20 | ; VF: Flag register 21 | 22 | ; DEFINE/UNDEF SUPER in line below to toggle between versions 23 | 24 | OPTION BINARY ; Let's compile this for non-HP computers... 25 | ; OPTION HPASC 26 | 27 | IFDEF SUPER 28 | OPTION SCHIP10 29 | ELSE 30 | OPTION CHIP48 31 | ENDIF 32 | 33 | MASKNIBB = $1111 34 | MASKBYTE = $11111111 35 | 36 | DOWNKEY = #6 37 | RIGHTKEY = #8 38 | LEFTKEY = #7 39 | UPKEY = #3 40 | PRESSKEY = #F 41 | LEVELKEY = #1 42 | 43 | PILLNUM = 231 44 | SUPERNUM = 4 45 | 46 | PILLTIME = 5 47 | SUPERTIME = 255 48 | CLSWAIT = 63 49 | EYEWAIT = 3 50 | 51 | PILLADD = 1 52 | SUPERADD = 4 53 | HEWARDADD = 25 54 | PACKLETTADD = 50 55 | SCREENADD = 100 56 | 57 | MASKLIFE = $01000000 58 | MASKHUNT = $10000000 59 | MASKCODE = $11 60 | DOWNCODE = $11 61 | RIGHTCODE = $10 62 | LEFTCODE = $01 63 | UPCODE = $00 64 | 65 | BLINKYCODE = DOWNCODE 66 | PACKLETTCODE = LEFTCODE 67 | HEWARDCODE = RIGHTCODE 68 | STARTCODE = HEWARDCODE < 4 | PACKLETTCODE < 2 | BLINKYCODE 69 | 70 | STARTLEVEL = $101 71 | 72 | IFDEF SUPER 73 | 74 | SCREENHIGH = 64 75 | SCREENWIDE = 128 76 | SPRITEHIGH = 8 77 | SPRITEWIDE = 16 78 | SPRITEJUMP = 4 79 | 80 | BLINKYX = 52 81 | BLINKYY = 24 82 | PACKLETTX = 112 83 | PACKLETTY = 0 84 | HEWARDX = 4 85 | HEWARDY = 52 86 | 87 | GATELEFT = 0 88 | GATERIGHT = 116 89 | 90 | SCXPOS = 36 91 | SCYPOS = 32 92 | HIXPOS = 36 93 | HIYPOS = 20 94 | EYEX1 = 0 95 | EYEX2 = 96 96 | EYEY1 = 1 97 | EYEY2 = 45 98 | 99 | ELSE 100 | 101 | SCREENHIGH = 32 102 | SCREENWIDE = 64 103 | SPRITEHIGH = 4 104 | SPRITEWIDE = 8 105 | SPRITEJUMP = 2 106 | 107 | BLINKYX = 26 108 | BLINKYY = 12 109 | PACKLETTX = 56 110 | PACKLETTY = 0 111 | HEWARDX = 2 112 | HEWARDY = 26 113 | 114 | GATELEFT = 0 115 | GATERIGHT = 58 116 | 117 | SCXPOS = 17 118 | SCYPOS = 16 119 | HIXPOS = 17 120 | HIYPOS = 10 121 | EYEX1 = 0 122 | EYEX2 = 48 123 | EYEY1 = 0 124 | EYEY2 = 22 125 | 126 | ENDIF 127 | 128 | JP START 129 | 130 | COPYRIGHT: DA '2.00 C. Egeberg 18/8-''91' 131 | USED COPYRIGHT 132 | 133 | START: IFDEF SUPER 134 | HIGH 135 | ENDIF 136 | XOR V0, V0 137 | XOR V1, V1 138 | LD I, SCORE 139 | LD [I], V1 140 | LD V0, STARTLEVEL 141 | LD I, LEVEL 142 | LD [I], V0 143 | XOR V7, V7 144 | REINIT: XOR V6, V6 145 | CALL COPYMAZE 146 | CLS 147 | CALL DRAWMAZE 148 | RESTART: LD VE, MASKLIFE 149 | AND V7, VE 150 | LD VE, STARTCODE 151 | OR V7, VE 152 | LD V8, BLINKYX 153 | LD V9, BLINKYY 154 | LD VA, PACKLETTX 155 | LD VB, PACKLETTY 156 | LD VC, HEWARDX 157 | LD VD, HEWARDY 158 | CALL DRAWBLINKY 159 | LD I, GHOST 160 | DRW VA, VB, SPRITEHIGH 161 | DRW VC, VD, SPRITEHIGH 162 | GAMELOOP: CALL MOVEBLINKY 163 | SE VE, 0 164 | JP ENCOUNTER 165 | SPLITUP: LD I, LEVEL 166 | LD V0, [I] 167 | LD V5, V0 168 | RND V4, MASKBYTE 169 | AND V4, V5 170 | CALL MOVEPACKLETT 171 | RND V4, MASKBYTE 172 | AND V4, V5 173 | CALL MOVEHEWARD 174 | LD V0, LEVELKEY 175 | SKNP V0 176 | CALL NEXTLEVEL 177 | SE V6, PILLADD * PILLNUM + SUPERADD * SUPERNUM 178 | JP GAMELOOP 179 | LD VE, V6 180 | CALL ADDSCORE 181 | LD VE, SCREENADD 182 | CALL ADDSCORE 183 | CALL NEXTLEVEL 184 | JP REINIT 185 | ENCOUNTER: LD V0, DT 186 | SNE V0, 0 187 | JP GOTCHA 188 | LD V0, V8 189 | SHR V0 190 | IFDEF SUPER 191 | SHR V0 192 | ENDIF 193 | LD V1, VA 194 | SHR V1 195 | IFDEF SUPER 196 | SHR V1 197 | ENDIF 198 | SUB V0, V1 199 | SNE V0, 0 200 | JP HITPACKLETT1 201 | SNE V0, 1 202 | JP HITPACKLETT1 203 | SNE V0, -1 & MASKBYTE 204 | JP HITPACKLETT1 205 | JP OOPSHEWARD 206 | HITPACKLETT1: LD V0, V9 207 | SHR V0 208 | IFDEF SUPER 209 | SHR V0 210 | ENDIF 211 | LD V1, VB 212 | SHR V1 213 | IFDEF SUPER 214 | SHR V1 215 | ENDIF 216 | SUB V0, V1 217 | SNE V0, 0 218 | JP HITPACKLETT2 219 | SNE V0, 1 220 | JP HITPACKLETT2 221 | SNE V0, -1 & MASKBYTE 222 | JP HITPACKLETT2 223 | JP OOPSHEWARD 224 | HITPACKLETT2: LD I, GHOST 225 | DRW VA, VB, SPRITEHIGH 226 | LD VA, PACKLETTX 227 | LD VB, PACKLETTY 228 | DRW VA, VB, SPRITEHIGH 229 | LD VE, ~( MASKCODE < 2 ) & MASKBYTE 230 | AND V7, VE 231 | LD VE, PACKLETTCODE < 2 232 | OR V7, VE 233 | LD VE, PACKLETTADD 234 | CALL ADDSCORE 235 | OOPSHEWARD: LD V0, V8 236 | SHR V0 237 | IFDEF SUPER 238 | SHR V0 239 | ENDIF 240 | LD V1, VC 241 | SHR V1 242 | IFDEF SUPER 243 | SHR V1 244 | ENDIF 245 | SUB V0, V1 246 | SNE V0, 0 247 | JP HITHEWARD1 248 | SNE V0, 1 249 | JP HITHEWARD1 250 | SNE V0, -1 & MASKBYTE 251 | JP HITHEWARD1 252 | JP SPLITUP 253 | HITHEWARD1: LD V0, V9 254 | SHR V0 255 | IFDEF SUPER 256 | SHR V0 257 | ENDIF 258 | LD V1, VD 259 | SHR V1 260 | IFDEF SUPER 261 | SHR V1 262 | ENDIF 263 | SUB V0, V1 264 | SNE V0, 0 265 | JP HITHEWARD2 266 | SNE V0, 1 267 | JP HITHEWARD2 268 | SNE V0, -1 & MASKBYTE 269 | JP HITHEWARD2 270 | JP SPLITUP 271 | HITHEWARD2: LD I, GHOST 272 | DRW VC, VD, SPRITEHIGH 273 | LD VC, HEWARDX 274 | LD VD, HEWARDY 275 | DRW VC, VD, SPRITEHIGH 276 | LD VE, ~( MASKCODE < 4 ) & MASKBYTE 277 | AND V7, VE 278 | LD VE, HEWARDCODE < 4 279 | OR V7, VE 280 | LD VE, HEWARDADD 281 | CALL ADDSCORE 282 | JP SPLITUP 283 | GOTCHA: LD V0, CLSWAIT 284 | CALL WAITKEY 285 | CALL DRAWBLINKY 286 | LD I, GHOST 287 | DRW VA, VB, SPRITEHIGH 288 | DRW VC, VD, SPRITEHIGH 289 | LD VE, MASKLIFE 290 | XOR V7, VE 291 | LD V0, V7 292 | AND V0, VE 293 | SE V0, 0 294 | JP RESTART 295 | LD VE, V6 296 | CALL ADDSCORE 297 | CALL NEWHIGH 298 | CLS 299 | LD V6, HIXPOS 300 | LD V7, HIYPOS 301 | LD I, HIGHSCORE 302 | CALL PRINTDEC 303 | LD V6, SCXPOS 304 | LD V7, SCYPOS 305 | LD I, SCORE 306 | CALL PRINTDEC 307 | LD V4, EYEX1 308 | LD V5, EYEX1 + SPRITEWIDE 309 | LD V6, EYEY1 310 | LD V7, PRESSKEY 311 | EYEX1LOOP: LD I, EYELEFT 312 | IFDEF SUPER 313 | DRW V4, V6, 0 314 | ELSE 315 | DRW V4, V6, 9 316 | ENDIF 317 | LD I, EYERIGHT 318 | IFDEF SUPER 319 | DRW V5, V6, 0 320 | ELSE 321 | DRW V5, V6, 9 322 | ENDIF 323 | LD V0, EYEWAIT 324 | CALL WAITKEY 325 | SE VE, 0 326 | JP EYEPRESS 327 | LD I, EYELEFT 328 | IFDEF SUPER 329 | DRW V4, V6, 0 330 | ELSE 331 | DRW V4, V6, 9 332 | ENDIF 333 | LD I, EYERIGHT 334 | IFDEF SUPER 335 | DRW V5, V6, 0 336 | ELSE 337 | DRW V5, V6, 9 338 | ENDIF 339 | ADD V4, SPRITEJUMP 340 | ADD V5, SPRITEJUMP 341 | SE V4, EYEX2 342 | JP EYEX1LOOP 343 | EYEY1LOOP: LD I, EYELEFT 344 | IFDEF SUPER 345 | DRW V4, V6, 0 346 | ELSE 347 | DRW V4, V6, 9 348 | ENDIF 349 | LD I, EYERIGHT 350 | IFDEF SUPER 351 | DRW V5, V6, 0 352 | ELSE 353 | DRW V5, V6, 9 354 | ENDIF 355 | LD V0, EYEWAIT 356 | CALL WAITKEY 357 | SE VE, 0 358 | JP EYEPRESS 359 | LD I, EYELEFT 360 | IFDEF SUPER 361 | DRW V4, V6, 0 362 | ELSE 363 | DRW V4, V6, 9 364 | ENDIF 365 | LD I, EYERIGHT 366 | IFDEF SUPER 367 | DRW V5, V6, 0 368 | ELSE 369 | DRW V5, V6, 9 370 | ENDIF 371 | ADD V6, SPRITEJUMP 372 | SE V6, EYEY2 373 | JP EYEY1LOOP 374 | EYEX2LOOP: LD I, EYELEFT 375 | IFDEF SUPER 376 | DRW V4, V6, 0 377 | ELSE 378 | DRW V4, V6, 9 379 | ENDIF 380 | LD I, EYERIGHT 381 | IFDEF SUPER 382 | DRW V5, V6, 0 383 | ELSE 384 | DRW V5, V6, 9 385 | ENDIF 386 | LD V0, EYEWAIT 387 | CALL WAITKEY 388 | SE VE, 0 389 | JP EYEPRESS 390 | LD I, EYELEFT 391 | IFDEF SUPER 392 | DRW V4, V6, 0 393 | ELSE 394 | DRW V4, V6, 9 395 | ENDIF 396 | LD I, EYERIGHT 397 | IFDEF SUPER 398 | DRW V5, V6, 0 399 | ELSE 400 | DRW V5, V6, 9 401 | ENDIF 402 | ADD V4, -SPRITEJUMP & MASKBYTE 403 | ADD V5, -SPRITEJUMP & MASKBYTE 404 | SE V4, EYEX1 405 | JP EYEX2LOOP 406 | EYEY2LOOP: LD I, EYELEFT 407 | IFDEF SUPER 408 | DRW V4, V6, 0 409 | ELSE 410 | DRW V4, V6, 9 411 | ENDIF 412 | LD I, EYERIGHT 413 | IFDEF SUPER 414 | DRW V5, V6, 0 415 | ELSE 416 | DRW V5, V6, 9 417 | ENDIF 418 | LD V0, EYEWAIT 419 | CALL WAITKEY 420 | SE VE, 0 421 | JP EYEPRESS 422 | LD I, EYELEFT 423 | IFDEF SUPER 424 | DRW V4, V6, 0 425 | ELSE 426 | DRW V4, V6, 9 427 | ENDIF 428 | LD I, EYERIGHT 429 | IFDEF SUPER 430 | DRW V5, V6, 0 431 | ELSE 432 | DRW V5, V6, 9 433 | ENDIF 434 | ADD V6, -SPRITEJUMP & MASKBYTE 435 | SE V6, EYEY1 436 | JP EYEY2LOOP 437 | JP EYEX1LOOP 438 | EYEPRESS: LD I, EYERIGHT 439 | IFDEF SUPER 440 | DRW V5, V6, 0 441 | ELSE 442 | DRW V5, V6, 9 443 | ENDIF 444 | LD I, EYEBLINK 445 | IFDEF SUPER 446 | DRW V5, V6, 0 447 | ELSE 448 | DRW V5, V6, 9 449 | ENDIF 450 | JP START 451 | 452 | ; MOVEBLINKY 453 | ; ->: Nothing 454 | ; <-: VE: Collision flag 455 | ; <>: V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, VE, VF, I 456 | 457 | MOVEBLINKY: LD V3, V7 458 | LD VE, MASKCODE 459 | AND V3, VE 460 | LD V4, V8 461 | LD V5, V9 462 | LD VE, DOWNKEY 463 | SKNP VE 464 | JP BLINKYDOWN 465 | LD VE, UPKEY 466 | SKNP VE 467 | JP BLINKYUP 468 | LD VE, RIGHTKEY 469 | SKNP VE 470 | JP BLINKYRIGHT 471 | LD VE, LEFTKEY 472 | SKNP VE 473 | JP BLINKYLEFT 474 | NOKEY: SNE V3, DOWNCODE 475 | ADD V5, SPRITEJUMP 476 | SNE V3, UPCODE 477 | ADD V5, -SPRITEJUMP & MASKBYTE 478 | SNE V3, RIGHTCODE 479 | ADD V4, SPRITEJUMP 480 | SNE V3, LEFTCODE 481 | ADD V4, -SPRITEJUMP & MASKBYTE 482 | LD V0, V4 483 | LD V1, V5 484 | CALL SPRITMAZE 485 | LD V2, V0 486 | LD VE, GRAPHEDGE 487 | AND V0, VE 488 | DONEKEY: SE V0, 0 489 | JP STOPBLINKY 490 | LD VE, GRAPHSPEC 491 | LD V0, V2 492 | AND V2, VE 493 | SNE V2, PL 494 | JP EATPILL 495 | SNE V2, SP 496 | JP EATSUPER 497 | SNE V2, GW 498 | JP GATEWAY 499 | DONEEAT: CALL DRAWBLINKY 500 | LD VE, ~MASKCODE & MASKBYTE 501 | AND V7, VE 502 | OR V7, V3 503 | LD V8, V4 504 | LD V9, V5 505 | JP DRAWBLINKY 506 | BLINKYDOWN: LD V0, V4 507 | LD V1, V5 508 | ADD V1, SPRITEJUMP 509 | CALL SPRITMAZE 510 | LD V2, V0 511 | LD VE, GRAPHEDGE 512 | AND V0, VE 513 | SE V0, 0 514 | JP NOKEY 515 | LD V3, DOWNCODE 516 | ADD V5, SPRITEJUMP 517 | JP DONEKEY 518 | BLINKYUP: LD V0, V4 519 | LD V1, V5 520 | ADD V1, -SPRITEJUMP & MASKBYTE 521 | CALL SPRITMAZE 522 | LD V2, V0 523 | LD VE, GRAPHEDGE 524 | AND V0, VE 525 | SE V0, 0 526 | JP NOKEY 527 | LD V3, UPCODE 528 | ADD V5, -SPRITEJUMP & MASKBYTE 529 | JP DONEKEY 530 | BLINKYRIGHT: LD V0, V4 531 | LD V1, V5 532 | ADD V0, SPRITEJUMP 533 | CALL SPRITMAZE 534 | LD V2, V0 535 | LD VE, GRAPHEDGE 536 | AND V0, VE 537 | SE V0, 0 538 | JP NOKEY 539 | LD V3, RIGHTCODE 540 | ADD V4, SPRITEJUMP 541 | JP DONEKEY 542 | BLINKYLEFT: LD V0, V4 543 | LD V1, V5 544 | ADD V0, -SPRITEJUMP & MASKBYTE 545 | CALL SPRITMAZE 546 | LD V2, V0 547 | LD VE, GRAPHEDGE 548 | AND V0, VE 549 | SE V0, 0 550 | JP NOKEY 551 | LD V3, LEFTCODE 552 | ADD V4, -SPRITEJUMP & MASKBYTE 553 | JP DONEKEY 554 | STOPBLINKY: CALL DRAWBLINKY 555 | DRW V8, V9, SPRITEHIGH 556 | LD VE, VF 557 | RET 558 | EATPILL: LD VE, ~MASKNIBB & MASKBYTE 559 | AND V0, VE 560 | OR V0, V3 561 | LD [I], V0 562 | LD I, PILL 563 | DRW V4, V5, SPRITEHIGH 564 | ADD V6, PILLADD 565 | LD V1, PILLTIME 566 | LD V0, DT 567 | SNE V0, 0 568 | LD ST, V1 569 | JP DONEEAT 570 | EATSUPER: LD VE, ~MASKNIBB & MASKBYTE 571 | AND V0, VE 572 | OR V0, V3 573 | LD [I], V0 574 | LD I, SUPER 575 | DRW V4, V5, SPRITEHIGH 576 | ADD V6, SUPERADD 577 | LD V0, VA 578 | LD V1, VB 579 | CALL SPRITMAZE 580 | LD VE, ~MASKNIBB & MASKBYTE 581 | AND V0, VE 582 | SE V0, 0 583 | JP SKIPPACKLETT 584 | LD VE, MASKCODE < 2 585 | XOR V7, VE 586 | SKIPPACKLETT: LD V0, VC 587 | LD V1, VD 588 | CALL SPRITMAZE 589 | LD VE, ~MASKNIBB & MASKBYTE 590 | AND V0, VE 591 | SE V0, 0 592 | JP SKIPHEWARD 593 | LD VE, MASKCODE < 4 594 | XOR V7, VE 595 | SKIPHEWARD: LD V0, SUPERTIME 596 | LD ST, V0 597 | LD DT, V0 598 | JP DONEEAT 599 | GATEWAY: SNE V3, LEFTCODE 600 | LD V4, GATERIGHT 601 | SNE V3, RIGHTCODE 602 | LD V4, GATELEFT 603 | JP DONEEAT 604 | 605 | ; MOVEPACKLETT 606 | ; ->: V4: Force random move if nonzero value 607 | ; <-: Nothing 608 | ; <>: V0, V1, V2, V3, V7, VA, VB, VE, VF, I 609 | 610 | MOVEPACKLETT: LD V2, V7 611 | LD V3, V7 612 | LD VE, MASKCODE < 2 613 | AND V2, VE 614 | LD V0, VA 615 | LD V1, VB 616 | CALL SPRITMAZE 617 | LD I, GHOST 618 | LD VE, ~MASKNIBB & MASKBYTE 619 | AND V0, VE 620 | SE V0, 0 621 | JP LOOKPACKLETT 622 | TURNPACKLETT: DRW VA, VB, SPRITEHIGH 623 | SNE V2, DOWNCODE < 2 624 | ADD VB, SPRITEJUMP 625 | SNE V2, UPCODE < 2 626 | ADD VB, -SPRITEJUMP & MASKBYTE 627 | SNE V2, RIGHTCODE < 2 628 | ADD VA, SPRITEJUMP 629 | SNE V2, LEFTCODE < 2 630 | ADD VA, -SPRITEJUMP & MASKBYTE 631 | DRW VA, VB, SPRITEHIGH 632 | RET 633 | LOOKPACKLETT: LD VE, MASKHUNT 634 | LD V1, DT 635 | SE V1, 0 636 | JP RANDPACKLETT 637 | SE V4, 0 638 | JP RANDPACKLETT 639 | LD V1, V0 640 | SHL V3 641 | SE VF, 0 642 | JP HORISPACKLETT 643 | LD V3, V9 644 | SUB V3, VB 645 | SNE VF, 0 646 | JP PACKLETTLU 647 | SE V3, 0 648 | JP PACKLETTLD 649 | XOR V7, VE 650 | LD V3, V8 651 | SUB V3, VA 652 | SNE VF, 0 653 | JP PACKLETTLL 654 | SE V3, 0 655 | JP PACKLETTLR 656 | XOR V7, VE 657 | JP RANDPACKLETT 658 | HORISPACKLETT: LD V3, V8 659 | SUB V3, VA 660 | SNE VF, 0 661 | JP PACKLETTLL 662 | SE V3, 0 663 | JP PACKLETTLR 664 | XOR V7, VE 665 | LD V3, V9 666 | SUB V3, VB 667 | SNE VF, 0 668 | JP PACKLETTLU 669 | SE V3, 0 670 | JP PACKLETTLD 671 | XOR V7, VE 672 | JP RANDPACKLETT 673 | PACKLETTLD: LD V3, MD 674 | AND V1, V3 675 | SNE V1, 0 676 | JP RANDPACKLETT 677 | DRW VA, VB, SPRITEHIGH 678 | ADD VB, SPRITEJUMP 679 | DRW VA, VB, SPRITEHIGH 680 | LD VE, ~( MASKCODE < 2 ) & MASKBYTE 681 | AND V7, VE 682 | LD V2, DOWNCODE < 2 683 | OR V7, V2 684 | RET 685 | PACKLETTLU: LD V3, MU 686 | AND V1, V3 687 | SNE V1, 0 688 | JP RANDPACKLETT 689 | DRW VA, VB, SPRITEHIGH 690 | ADD VB, -SPRITEJUMP & MASKBYTE 691 | DRW VA, VB, SPRITEHIGH 692 | LD VE, ~( MASKCODE < 2 ) & MASKBYTE 693 | AND V7, VE 694 | LD V2, UPCODE < 2 695 | OR V7, V2 696 | RET 697 | PACKLETTLR: LD V3, MR 698 | AND V1, V3 699 | SNE V1, 0 700 | JP RANDPACKLETT 701 | DRW VA, VB, SPRITEHIGH 702 | ADD VA, SPRITEJUMP 703 | DRW VA, VB, SPRITEHIGH 704 | LD VE, ~( MASKCODE < 2 ) & MASKBYTE 705 | AND V7, VE 706 | LD V2, RIGHTCODE < 2 707 | OR V7, V2 708 | RET 709 | PACKLETTLL: LD V3, ML 710 | AND V1, V3 711 | SNE V1, 0 712 | JP RANDPACKLETT 713 | DRW VA, VB, SPRITEHIGH 714 | ADD VA, -SPRITEJUMP & MASKBYTE 715 | DRW VA, VB, SPRITEHIGH 716 | LD VE, ~( MASKCODE < 2 ) & MASKBYTE 717 | AND V7, VE 718 | LD V2, LEFTCODE < 2 719 | OR V7, V2 720 | RET 721 | RANDPACKLETT: RND V1, ~MASKNIBB & MASKBYTE 722 | AND V0, V1 723 | SE V0, 0 724 | JP SETPACKLETT 725 | PACKLETTERR: LD VE, MASKCODE < 2 726 | XOR V7, VE 727 | XOR V2, VE 728 | JP TURNPACKLETT 729 | SETPACKLETT: DRW VA, VB, SPRITEHIGH 730 | SHL V0 731 | SNE VF, 0 732 | JP PACKLETTRD 733 | LD V2, LEFTCODE < 2 734 | ADD VA, -SPRITEJUMP & MASKBYTE 735 | JP PACKLETTSET 736 | PACKLETTRD: SHL V0 737 | SNE VF, 0 738 | JP PACKLETTRR 739 | LD V2, DOWNCODE < 2 740 | ADD VB, SPRITEJUMP 741 | JP PACKLETTSET 742 | PACKLETTRR: SHL V0 743 | SNE VF, 0 744 | JP PACKLETTRU 745 | LD V2, RIGHTCODE < 2 746 | ADD VA, SPRITEJUMP 747 | JP PACKLETTSET 748 | PACKLETTRU: SHL V0 749 | SNE VF, 0 750 | JP PACKLETTERR 751 | LD V2, UPCODE < 2 752 | ADD VB, -SPRITEJUMP & MASKBYTE 753 | PACKLETTSET: DRW VA, VB, SPRITEHIGH 754 | LD VE, ~( MASKCODE < 2 ) & MASKBYTE 755 | AND V7, VE 756 | OR V7, V2 757 | RET 758 | 759 | ; MOVEHEWARD 760 | ; ->: V4: Force random move if nonzero value 761 | ; <-: Nothing 762 | ; <>: V0, V1, V2, V3, V7, VC, VD, VE, VF, I 763 | 764 | MOVEHEWARD: LD V2, V7 765 | LD V3, V7 766 | LD VE, MASKCODE < 4 767 | AND V2, VE 768 | LD V0, VC 769 | LD V1, VD 770 | CALL SPRITMAZE 771 | LD I, GHOST 772 | LD VE, ~MASKNIBB & MASKBYTE 773 | AND V0, VE 774 | SE V0, 0 775 | JP LOOKHEWARD 776 | TURNHEWARD: DRW VC, VD, SPRITEHIGH 777 | SNE V2, DOWNCODE < 4 778 | ADD VD, SPRITEJUMP 779 | SNE V2, UPCODE < 4 780 | ADD VD, -SPRITEJUMP & MASKBYTE 781 | SNE V2, RIGHTCODE < 4 782 | ADD VC, SPRITEJUMP 783 | SNE V2, LEFTCODE < 4 784 | ADD VC, -SPRITEJUMP & MASKBYTE 785 | DRW VC, VD, SPRITEHIGH 786 | RET 787 | LOOKHEWARD: LD VE, MASKHUNT 788 | LD V1, DT 789 | SE V1, 0 790 | JP RANDHEWARD 791 | SE V4, 0 792 | JP RANDHEWARD 793 | LD V1, V0 794 | SHL V3 795 | SNE VF, 0 796 | JP HORISHEWARD 797 | LD V3, V9 798 | SUB V3, VD 799 | SNE VF, 0 800 | JP HEWARDLU 801 | SE V3, 0 802 | JP HEWARDLD 803 | XOR V7, VE 804 | LD V3, V8 805 | SUB V3, VC 806 | SNE VF, 0 807 | JP HEWARDLL 808 | SE V3, 0 809 | JP HEWARDLR 810 | XOR V7, VE 811 | JP RANDHEWARD 812 | HORISHEWARD: LD V3, V8 813 | SUB V3, VC 814 | SNE VF, 0 815 | JP HEWARDLL 816 | SE V3, 0 817 | JP HEWARDLR 818 | XOR V7, VE 819 | LD V3, V9 820 | SUB V3, VD 821 | SNE VF, 0 822 | JP HEWARDLU 823 | SE V3, 0 824 | JP HEWARDLD 825 | XOR V7, VE 826 | JP RANDHEWARD 827 | HEWARDLD: LD V3, MD 828 | AND V1, V3 829 | SNE V1, 0 830 | JP RANDHEWARD 831 | DRW VC, VD, SPRITEHIGH 832 | ADD VD, SPRITEJUMP 833 | DRW VC, VD, SPRITEHIGH 834 | XOR V7, VE 835 | LD VE, ~( MASKCODE < 4 ) & MASKBYTE 836 | AND V7, VE 837 | LD V2, DOWNCODE < 4 838 | OR V7, V2 839 | RET 840 | HEWARDLU: LD V3, MU 841 | AND V1, V3 842 | SNE V1, 0 843 | JP RANDHEWARD 844 | DRW VC, VD, SPRITEHIGH 845 | ADD VD, -SPRITEJUMP & MASKBYTE 846 | DRW VC, VD, SPRITEHIGH 847 | XOR V7, VE 848 | LD VE, ~( MASKCODE < 4 ) & MASKBYTE 849 | AND V7, VE 850 | LD V2, UPCODE < 4 851 | OR V7, V2 852 | RET 853 | HEWARDLR: LD V3, MR 854 | AND V1, V3 855 | SNE V1, 0 856 | JP RANDHEWARD 857 | DRW VC, VD, SPRITEHIGH 858 | ADD VC, SPRITEJUMP 859 | DRW VC, VD, SPRITEHIGH 860 | XOR V7, VE 861 | LD VE, ~( MASKCODE < 4 ) & MASKBYTE 862 | AND V7, VE 863 | LD V2, RIGHTCODE < 4 864 | OR V7, V2 865 | RET 866 | HEWARDLL: LD V3, ML 867 | AND V1, V3 868 | SNE V1, 0 869 | JP RANDHEWARD 870 | DRW VC, VD, SPRITEHIGH 871 | ADD VC, -SPRITEJUMP & MASKBYTE 872 | DRW VC, VD, SPRITEHIGH 873 | XOR V7, VE 874 | LD VE, ~( MASKCODE < 4 ) & MASKBYTE 875 | AND V7, VE 876 | LD V2, LEFTCODE < 4 877 | OR V7, V2 878 | RET 879 | RANDHEWARD: RND V1, ~MASKNIBB & MASKBYTE 880 | AND V0, V1 881 | SE V0, 0 882 | JP SETHEWARD 883 | HEWARDERR: XOR V7, VE 884 | LD VE, MASKCODE < 4 885 | XOR V7, VE 886 | XOR V2, VE 887 | JP TURNHEWARD 888 | SETHEWARD: DRW VC, VD, SPRITEHIGH 889 | SHL V0 890 | SNE VF, 0 891 | JP HEWARDRD 892 | LD V2, LEFTCODE < 4 | MASKHUNT 893 | ADD VC, -SPRITEJUMP & MASKBYTE 894 | JP HEWARDSET 895 | HEWARDRD: SHL V0 896 | SNE VF, 0 897 | JP HEWARDRR 898 | LD V2, DOWNCODE < 4 899 | ADD VD, SPRITEJUMP 900 | JP HEWARDSET 901 | HEWARDRR: SHL V0 902 | SNE VF, 0 903 | JP HEWARDRU 904 | LD V2, RIGHTCODE < 4 | MASKHUNT 905 | ADD VC, SPRITEJUMP 906 | JP HEWARDSET 907 | HEWARDRU: SHL V0 908 | SNE VF, 0 909 | JP HEWARDERR 910 | LD V2, UPCODE < 4 911 | ADD VD, -SPRITEJUMP & MASKBYTE 912 | HEWARDSET: DRW VC, VD, SPRITEHIGH 913 | LD VE, ~( MASKCODE < 4 | MASKHUNT ) & MASKBYTE 914 | AND V7, VE 915 | OR V7, V2 916 | RET 917 | 918 | ; DRAWBLINKY 919 | ; -> V7: Sprite direction register 920 | ; -> V8: Blinky X screen coordinate 921 | ; -> V9: Blinky Y screen coordinate 922 | ; <- VE: Collision flag 923 | ; <- I: Blinky sprite pointer 924 | ; <> V0, V1, VE, VF, I 925 | 926 | DRAWBLINKY: LD V0, V7 927 | LD VE, MASKCODE 928 | AND V0, VE 929 | SHL V0 930 | LD V1, V8 931 | ADD V1, V9 932 | LD VE, SPRITEJUMP 933 | AND V1, VE 934 | SNE V1, 0 935 | ADD V0, 1 936 | SHL V0 937 | SHL V0 938 | IFDEF SUPER 939 | SHL V0 940 | ENDIF 941 | LD I, SPRITES 942 | ADD I, V0 943 | DRW V8, V9, SPRITEHIGH 944 | LD VE, VF 945 | RET 946 | 947 | ; COPYMAZE 948 | ; -> Nothing 949 | ; <- Nothing 950 | ; <> V0, V1, V2, V3, VE, VF, I 951 | 952 | COPYMAZE: LD VE, 0 953 | COPYLOOP: LD I, MAZE 954 | ADD I, VE 955 | ADD I, VE 956 | ADD I, VE 957 | ADD I, VE 958 | LD V3, [I] 959 | LD I, BUFFER 960 | ADD I, VE 961 | ADD I, VE 962 | ADD I, VE 963 | ADD I, VE 964 | LD [I], V3 965 | ADD VE, 1 966 | SE VE, MAZEEND - MAZE \ 4 967 | JP COPYLOOP 968 | RET 969 | 970 | ; DRAWMAZE 971 | ; -> Nothing 972 | ; <- Nothing 973 | ; <> V0, V1, V2, V3, VE, VF, I 974 | 975 | DRAWMAZE: XOR V2, V2 976 | XOR V3, V3 977 | LD VE, 15 978 | DRAWLOOP: LD V0, V2 979 | LD V1, V3 980 | CALL GRAPHMAZE 981 | AND V0, VE 982 | SHL V0 983 | IFDEF SUPER 984 | SHL V0 985 | ENDIF 986 | LD I, GRAPHS 987 | ADD I, V0 988 | DRW V2, V3, SPRITEJUMP 989 | ADD V2, SPRITEJUMP 990 | SE V2, SCREENWIDE 991 | JP DRAWLOOP 992 | XOR V2, V2 993 | ADD V3, SPRITEJUMP 994 | SNE V3, SCREENHIGH 995 | RET 996 | JP DRAWLOOP 997 | 998 | ; SPRITMAZE, GRAPHMAZE 999 | ; -> V0: X coordinate 1000 | ; -> V1: Y coordinate 1001 | ; <- V0: Maze data byte 1002 | ; <- I: Maze data pointer 1003 | ; <> V0, V1, VF, I 1004 | 1005 | SPRITMAZE: ADD V0, SPRITEJUMP 1006 | ADD V1, SPRITEJUMP 1007 | GRAPHMAZE: SHR V0 1008 | IFDEF SUPER 1009 | SHR V0 1010 | ENDIF 1011 | SHR V1 1012 | IFDEF SUPER 1013 | SHR V1 1014 | ENDIF 1015 | SHL V1 1016 | SHL V1 1017 | SHL V1 1018 | SHL V1 1019 | LD I, BUFFER 1020 | ADD I, V1 1021 | ADD I, V1 1022 | ADD I, V0 1023 | LD V0, [I] 1024 | RET 1025 | 1026 | ; NEXTLEVEL 1027 | ; -> Nothing 1028 | ; <- Nothing 1029 | ; <> V0, VF, I 1030 | 1031 | NEXTLEVEL: LD I, LEVEL 1032 | LD V0, [I] 1033 | SHR V0 1034 | LD [I], V0 1035 | LD V0, LEVELKEY 1036 | LOOPLEVEL: SKNP V0 1037 | JP LOOPLEVEL 1038 | RET 1039 | 1040 | ; PRINTDEC 1041 | ; -> V6: Print X coordinate 1042 | ; -> V7: Print Y coordinate 1043 | ; -> I: 16 bit value pointer 1044 | ; <- Nothing 1045 | ; <> V0, V1, V2, V3, V4, V5, V6, V7, VE, VF, I 1046 | 1047 | PRINTDEC: LD V1, [I] 1048 | LD VE, 1 1049 | XOR V4, V4 1050 | LD V2, V0 1051 | LD V3, V1 1052 | LOOPTENG: LD V5, 10000 % 256 1053 | SUB V3, V5 1054 | SNE VF, 0 1055 | SUB V2, VE 1056 | SNE VF, 0 1057 | JP SKIPTENG 1058 | LD V5, 10000 \ 256 1059 | SUB V2, V5 1060 | SNE VF, 0 1061 | JP SKIPTENG 1062 | LD V0, V2 1063 | LD V1, V3 1064 | ADD V4, VE 1065 | JP LOOPTENG 1066 | SKIPTENG: IFDEF SUPER 1067 | LD HF, V4 1068 | DRW V6, V7, 10 1069 | ELSE 1070 | LD F, V4 1071 | DRW V6, V7, 5 1072 | ENDIF 1073 | ADD V6, SPRITEWIDE - SPRITEJUMP 1074 | XOR V4, V4 1075 | LD V2, V0 1076 | LD V3, V1 1077 | LOOPTHOUS: LD V5, 1000 % 256 1078 | SUB V3, V5 1079 | SNE VF, 0 1080 | SUB V2, VE 1081 | SNE VF, 0 1082 | JP SKIPTHOUS 1083 | LD V5, 1000 \ 256 1084 | SUB V2, V5 1085 | SNE VF, 0 1086 | JP SKIPTHOUS 1087 | LD V0, V2 1088 | LD V1, V3 1089 | ADD V4, VE 1090 | JP LOOPTHOUS 1091 | SKIPTHOUS: IFDEF SUPER 1092 | LD HF, V4 1093 | DRW V6, V7, 10 1094 | ELSE 1095 | LD F, V4 1096 | DRW V6, V7, 5 1097 | ENDIF 1098 | ADD V6, SPRITEWIDE - SPRITEJUMP 1099 | XOR V4, V4 1100 | LD V2, V0 1101 | LD V3, V1 1102 | LOOPHUNDR: LD V5, 100 1103 | SUB V3, V5 1104 | SNE VF, 0 1105 | SUB V2, VE 1106 | SNE VF, 0 1107 | JP SKIPHUNDR 1108 | LD V0, V2 1109 | LD V1, V3 1110 | ADD V4, VE 1111 | JP LOOPHUNDR 1112 | SKIPHUNDR: IFDEF SUPER 1113 | LD HF, V4 1114 | DRW V6, V7, 10 1115 | ELSE 1116 | LD F, V4 1117 | DRW V6, V7, 5 1118 | ENDIF 1119 | ADD V6, SPRITEWIDE - SPRITEJUMP 1120 | XOR V4, V4 1121 | LD V2, V0 1122 | LD V3, V1 1123 | LOOPTEN: LD V5, 10 1124 | SUB V3, V5 1125 | SNE VF, 0 1126 | JP SKIPTEN 1127 | LD V1, V3 1128 | ADD V4, VE 1129 | JP LOOPTEN 1130 | SKIPTEN: IFDEF SUPER 1131 | LD HF, V4 1132 | DRW V6, V7, 10 1133 | ELSE 1134 | LD F, V4 1135 | DRW V6, V7, 5 1136 | ENDIF 1137 | ADD V6, SPRITEWIDE - SPRITEJUMP 1138 | IFDEF SUPER 1139 | LD HF, V1 1140 | DRW V6, V7, 10 1141 | ELSE 1142 | LD F, V1 1143 | DRW V6, V7, 5 1144 | ENDIF 1145 | RET 1146 | 1147 | ; ADDSCORE 1148 | ; -> VE: Score count to add 1149 | ; <- Nothing 1150 | ; <> V0, V1, VE, VF, I 1151 | 1152 | ADDSCORE: LD I, SCORE 1153 | LD V1, [I] 1154 | ADD V1, VE 1155 | SE VF, 0 1156 | ADD V0, 1 1157 | LD I, SCORE 1158 | LD [I], V1 1159 | RET 1160 | 1161 | ; NEWHIGH 1162 | ; -> Nothing 1163 | ; <- Nothing 1164 | ; <> V0, V1, V2, V3, VE, VF, I 1165 | 1166 | NEWHIGH: LD I, SCORE 1167 | LD V3, [I] 1168 | LD VE, V0 1169 | SUB VE, V2 1170 | SNE VF, 0 1171 | RET 1172 | SE VE, 0 1173 | JP STOREHIGH 1174 | LD VE, V1 1175 | SUB VE, V3 1176 | SNE VF, 0 1177 | RET 1178 | STOREHIGH: LD I, HIGHSCORE 1179 | LD [I], V1 1180 | RET 1181 | 1182 | ; WAITKEY 1183 | ; -> V0: Waitcount 1184 | ; <- VE: Keypressed 1185 | ; <> V0, V1, V2, V3, VE, VF 1186 | 1187 | WAITKEY: XOR VE, VE 1188 | LD V2, PRESSKEY 1189 | LD V3, -1 & MASKBYTE 1190 | LD V1, 16 1191 | LOOPKEY: SKNP V2 1192 | JP HITKEY 1193 | ADD V1, V3 1194 | SE V1, 0 1195 | JP LOOPKEY 1196 | LD V1, 16 1197 | ADD V0, V3 1198 | SE V0, 0 1199 | JP LOOPKEY 1200 | RET 1201 | HITKEY: LD VE, 1 1202 | RET 1203 | 1204 | SCORE DW 0 1205 | HIGHSCORE: DW 0 1206 | 1207 | LEVEL: DB STARTLEVEL 1208 | 1209 | ALIGN OFF 1210 | USED ON 1211 | 1212 | SPRITES = ? 1213 | 1214 | IFDEF SUPER 1215 | 1216 | UP: DB $........ 1217 | DB $..1...1. 1218 | DB $.11...11 1219 | DB $.11...11 1220 | DB $.111.111 1221 | DB $.1111111 1222 | DB $..11111. 1223 | DB $...111.. 1224 | 1225 | DB $........ 1226 | DB $...111.. 1227 | DB $...1111. 1228 | DB $.1.111.1 1229 | DB $.1.111.1 1230 | DB $.11.1111 1231 | DB $..11111. 1232 | DB $...111.. 1233 | 1234 | LEFT: DB $........ 1235 | DB $..1111.. 1236 | DB $.111111. 1237 | DB $....1111 1238 | DB $.....111 1239 | DB $....1111 1240 | DB $.111111. 1241 | DB $..1111.. 1242 | 1243 | DB $........ 1244 | DB $...111.. 1245 | DB $..1..11. 1246 | DB $.1111111 1247 | DB $.1111111 1248 | DB $.1111.11 1249 | DB $.....11. 1250 | DB $...111.. 1251 | 1252 | RIGHT: DB $........ 1253 | DB $...1111. 1254 | DB $..111111 1255 | DB $.1111... 1256 | DB $.111.... 1257 | DB $.1111... 1258 | DB $..111111 1259 | DB $...1111. 1260 | 1261 | DB $........ 1262 | DB $...111.. 1263 | DB $..11..1. 1264 | DB $.1111111 1265 | DB $.1111111 1266 | DB $.11.1111 1267 | DB $..11.... 1268 | DB $...111.. 1269 | 1270 | DOWN: DB $........ 1271 | DB $...111.. 1272 | DB $..11111. 1273 | DB $.1111111 1274 | DB $.111.111 1275 | DB $.11...11 1276 | DB $.11...11 1277 | DB $..1...1. 1278 | 1279 | DB $........ 1280 | DB $...111.. 1281 | DB $..11111. 1282 | DB $.11.1111 1283 | DB $.1.111.1 1284 | DB $.1.111.1 1285 | DB $...1111. 1286 | DB $...111.. 1287 | 1288 | GHOST: DB $........ 1289 | DB $...111.. 1290 | DB $..11111. 1291 | DB $.1..1..1 1292 | DB $.111.111 1293 | DB $.1111111 1294 | DB $.11...11 1295 | DB $.1111111 1296 | 1297 | PILL: DB $........ 1298 | DB $........ 1299 | DB $........ 1300 | DB $........ 1301 | DB $....1... 1302 | DB $........ 1303 | DB $........ 1304 | DB $........ 1305 | 1306 | SUPER: DB $........ 1307 | DB $........ 1308 | DB $........ 1309 | DB $........ 1310 | DB $....1... 1311 | DB $....1... 1312 | DB $........ 1313 | DB $........ 1314 | 1315 | ELSE 1316 | 1317 | UP: DB $........ 1318 | DB $.1.1.... 1319 | DB $.111.... 1320 | DB $..1..... 1321 | 1322 | DB $........ 1323 | DB $.1.1.... 1324 | DB $.111.... 1325 | DB $..1..... 1326 | 1327 | LEFT: DB $........ 1328 | DB $.11..... 1329 | DB $..11.... 1330 | DB $.11..... 1331 | 1332 | DB $........ 1333 | DB $.11..... 1334 | DB $..11.... 1335 | DB $.11..... 1336 | 1337 | RIGHT: DB $........ 1338 | DB $..11.... 1339 | DB $.11..... 1340 | DB $..11.... 1341 | 1342 | DB $........ 1343 | DB $..11.... 1344 | DB $.11..... 1345 | DB $..11.... 1346 | 1347 | DOWN: DB $........ 1348 | DB $..1..... 1349 | DB $.111.... 1350 | DB $.1.1.... 1351 | 1352 | DB $........ 1353 | DB $..1..... 1354 | DB $.111.... 1355 | DB $.1.1.... 1356 | 1357 | GHOST: DB $........ 1358 | DB $..1..... 1359 | DB $.111.... 1360 | DB $.111.... 1361 | 1362 | PILL: DB $........ 1363 | DB $........ 1364 | DB $..1..... 1365 | DB $........ 1366 | 1367 | SUPER: DB $........ 1368 | DB $........ 1369 | DB $........ 1370 | DB $........ 1371 | 1372 | ENDIF 1373 | 1374 | GRAPHS = ? 1375 | 1376 | ; $0000 Trail up 1377 | ; $0001 Trail left 1378 | ; $0010 Trail right 1379 | ; $0011 Trail down 1380 | ; $0100 Empty space 1381 | ; $0101 Ordinary pill 1382 | ; $0110 Super pill 1383 | ; $0111 Gateway 1384 | ; $1000 Horisontal egde 1385 | ; $1001 Invisible horisontal edge 1386 | ; $1010 Vertical edge 1387 | ; $1011 Invisible vertical edge 1388 | ; $1100 Upper left corner 1389 | ; $1101 Upper right corner 1390 | ; $1110 Lower left corner 1391 | ; $1111 Lower right corner 1392 | 1393 | GRAPHEDGE = $1000 1394 | GRAPHSPEC = $0111 1395 | ES = $0100 1396 | PL = $0101 1397 | SP = $0110 1398 | GW = $0111 1399 | LR = $1000 1400 | ILR = $1001 1401 | UD = $1010 1402 | IUD = $1011 1403 | UL = $1100 1404 | UR = $1101 1405 | DL = $1110 1406 | DR = $1111 1407 | MU = $00010000 1408 | MR = $00100000 1409 | MUR = $00110000 1410 | MD = $01000000 1411 | MDU = $01010000 1412 | MDR = $01100000 1413 | MDUR = $01110000 1414 | ML = $10000000 1415 | MUL = $10010000 1416 | MRL = $10100000 1417 | MURL = $10110000 1418 | MDL = $11000000 1419 | MDUL = $11010000 1420 | MDRL = $11100000 1421 | MDURL = $11110000 1422 | 1423 | IFDEF SUPER 1424 | 1425 | DB $........ 1426 | DB $........ 1427 | DB $........ 1428 | DB $........ 1429 | 1430 | DB $........ 1431 | DB $........ 1432 | DB $........ 1433 | DB $........ 1434 | 1435 | DB $........ 1436 | DB $........ 1437 | DB $........ 1438 | DB $........ 1439 | 1440 | DB $........ 1441 | DB $........ 1442 | DB $........ 1443 | DB $........ 1444 | 1445 | EMPTY: DB $........ 1446 | DB $........ 1447 | DB $........ 1448 | DB $........ 1449 | 1450 | PILLGR: DB $1....... 1451 | DB $........ 1452 | DB $........ 1453 | DB $........ 1454 | 1455 | SUPERGR: DB $1....... 1456 | DB $1....... 1457 | DB $........ 1458 | DB $........ 1459 | 1460 | GATEGR: DB $........ 1461 | DB $........ 1462 | DB $........ 1463 | DB $........ 1464 | 1465 | HORIS: DB $1111.... 1466 | DB $........ 1467 | DB $........ 1468 | DB $........ 1469 | 1470 | INVHORIS: DB $........ 1471 | DB $........ 1472 | DB $........ 1473 | DB $........ 1474 | 1475 | VERT: DB $1....... 1476 | DB $1....... 1477 | DB $1....... 1478 | DB $1....... 1479 | 1480 | INVVERT: DB $........ 1481 | DB $........ 1482 | DB $........ 1483 | DB $........ 1484 | 1485 | UPLEFT: DB $1111.... 1486 | DB $1....... 1487 | DB $1....... 1488 | DB $1....... 1489 | 1490 | UPRIGHT: DB $1....... 1491 | DB $1....... 1492 | DB $1....... 1493 | DB $1....... 1494 | 1495 | DOWNLEFT: DB $1111.... 1496 | DB $........ 1497 | DB $........ 1498 | DB $........ 1499 | 1500 | DOWNRIGHT: DB $1....... 1501 | DB $........ 1502 | DB $........ 1503 | DB $........ 1504 | 1505 | ELSE 1506 | 1507 | DB $........ 1508 | DB $........ 1509 | 1510 | DB $........ 1511 | DB $........ 1512 | 1513 | DB $........ 1514 | DB $........ 1515 | 1516 | DB $........ 1517 | DB $........ 1518 | 1519 | EMPTY: DB $........ 1520 | DB $........ 1521 | 1522 | PILLGR: DB $1....... 1523 | DB $........ 1524 | 1525 | SUPERGR: DB $........ 1526 | DB $........ 1527 | 1528 | GATEGR: DB $........ 1529 | DB $........ 1530 | 1531 | HORIS: DB $11...... 1532 | DB $........ 1533 | 1534 | INVHORIS: DB $........ 1535 | DB $........ 1536 | 1537 | VERT: DB $1....... 1538 | DB $1....... 1539 | 1540 | INVVERT: DB $........ 1541 | DB $........ 1542 | 1543 | UPLEFT: DB $11...... 1544 | DB $1....... 1545 | 1546 | UPRIGHT: DB $1....... 1547 | DB $1....... 1548 | 1549 | DOWNLEFT: DB $11...... 1550 | DB $........ 1551 | 1552 | DOWNRIGHT: DB $1....... 1553 | DB $........ 1554 | 1555 | ENDIF 1556 | 1557 | MAZE = ? 1558 | 1559 | XREF OFF 1560 | 1561 | ; ################################################################## 1562 | ; #------------------------------- ------------------------------- # 1563 | ; #| | | O | # 1564 | ; #| ? . . . . ? . . ? . . . . ? | | ? . . . . ? . . ? . . .OOO? | # 1565 | ; #| | | OOO | # 1566 | ; #| . ------- . --- . ------- . --- . ------- . --- . ------- . | # 1567 | ; #| | | | | | | | | | # 1568 | ; #| . | ? x . ? | | ? . . ? | ? . . ? | ? . . ? | | ? . x ? | . | # 1569 | ; #| | | | | | | | | | # 1570 | ; #| . | . --------------- . ----------- . --------------- . | . | # 1571 | ; #| | | | # 1572 | ; #| ? . ? . . . . ? | ? . ? . ? . . ? . ? . ? | ? . . . . ? . ? | # 1573 | ; #| | | | # 1574 | ; #| . ----------- . | . ----- . --- . ----- . | . ----------- . | # 1575 | ; #| | | | O | | | | # 1576 | ; #| . | ? . . ? | ? ? ? | ? .O?O. . ? . ? | ? ? ? | ? . . ? | . | # 1577 | ; # | | O O | | # 1578 | ; #+ ? . ? --- . --- . --- . ----------- . --- . --- . --- ? . ? + # 1579 | ; # | | # 1580 | ; #| . | ? . . ? . . ? . . ? ----- ----- ? . . ? . . ? . . ? | . | # 1581 | ; #| | | | | | # 1582 | ; #| . ------- . --------- ? . ? | | ? . ? --------- . ------- . | # 1583 | ; #| | | | | | | | | | # 1584 | ; #| ? . x ? | . ------------- . --- . ------------- . | ? x . ? | # 1585 | ; #| | | | # 1586 | ; #| . --- . | ? . . . . ? . . ? . . ? . . ? . . . . ? | . --- . | # 1587 | ; #| | | | | | | | # 1588 | ; #| . --- . ----------- . --- . --- . --- . ----------- . --- . | # 1589 | ; #| O | | | | | # 1590 | ; #| ?OOO. ? . . . . . . ? | | ? . . ? | | ? . . . . . . ? . . ? | # 1591 | ; #| OOO | | | | | # 1592 | ; #------------------------- ----------- ------------------------- # 1593 | ; # # 1594 | ; ################################################################## 1595 | 1596 | DB UL, LR, LR, LR, LR, LR, LR, LR 1597 | DB LR, LR, LR, LR, LR, LR, LR, UR 1598 | DB UL, LR, LR, LR, LR, LR, LR, LR 1599 | DB LR, LR, LR, LR, LR, LR, LR, UR 1600 | 1601 | DB UD, MDR | PL, PL, PL, PL, PL, MDRL | PL, PL 1602 | DB PL, MDRL | PL, PL, PL, PL, PL, MDL | PL, UD 1603 | DB UD, MDR | PL, PL, PL, PL, PL, MDRL | PL, PL 1604 | DB PL, MDRL | PL, PL, PL, PL, PL, MDL | PL, UD 1605 | 1606 | DB UD, PL, UL, LR, LR, DR, PL, UL 1607 | DB UR, PL, LR, LR, LR, UR, PL, DL 1608 | DB DR, PL, UL, LR, LR, DR, PL, UL 1609 | DB UR, PL, LR, LR, LR, UR, PL, UD 1610 | 1611 | DB UD, PL, UD, MDR | PL, SP, PL, MUL | PL, UD 1612 | DB UD, MUR | PL, PL, PL, MDL | PL, UD 1613 | DB MUR | PL, PL, PL, MUL | PL 1614 | DB UD, MDR | PL, PL, PL, MUL | PL, UD 1615 | DB UD, MUR | PL, PL, SP, MDL | PL, UD, PL, UD 1616 | 1617 | DB UD, PL, DR, PL, LR, LR, LR, LR 1618 | DB LR, UL, LR, DR, PL, LR, LR, LR 1619 | DB LR, LR, DR, PL, LR, LR, UL, LR 1620 | DB LR, LR, LR, DR, PL, DR, PL, UD 1621 | 1622 | DB UD, MDUR | PL, PL, MURL | PL, PL, PL, PL, PL 1623 | DB MDL | PL, UD, MDR | PL, PL, MURL | PL, PL, 1624 | DB MDRL | PL, PL, PL, MDRL | PL 1625 | DB PL, MURL | PL, PL, MDL | PL, UD, MDR | PL 1626 | DB PL, PL, PL, PL, MURL | PL, PL, MDUL | PL, UD 1627 | 1628 | DB UD, PL, UL, LR, LR, LR, LR, UR 1629 | DB PL, DR, PL, UL, LR, DR, PL, LR 1630 | DB DR, PL, LR, LR, UR, PL, DR, PL 1631 | DB UL, LR, LR, LR, LR, UR, PL, UD 1632 | 1633 | DB DR, PL, DR, MDR | PL, PL, PL, MDL | PL, UD 1634 | DB MUR | PL, MDRL | PL, MUL | PL, UD, MDR | PL 1635 | DB PL, MURL, PL, PL, MURL | PL, PL 1636 | DB MDL | PL, UD, MUR | PL, MDRL | PL, MUL | PL 1637 | DB UD, MDR | PL, PL, PL, MDL | PL, DR, PL, DR 1638 | 1639 | DB GW, MDUR | ES, PL, MDUL | PL, LR, DR, PL, DL 1640 | DB DR, PL, LR, DR, PL, UL, LR, LR 1641 | DB LR, LR, UR, PL, LR, DR, PL, LR 1642 | DB DR, PL, LR, DR, MDUR | PL, PL, MDUL | ES, GW 1643 | 1644 | DB UD, PL, UD, MUR | PL, PL, PL, MDURL | PL, PL 1645 | DB PL, MURL | PL, PL, PL, MDUL | PL, LR, LR, UR 1646 | DB UL, LR, DR, MDUR | PL, PL, PL, MURL | PL, PL 1647 | DB PL, MDURL | PL, PL, PL, MUL | PL, UD, PL, UD 1648 | 1649 | DB UD, PL, LR, LR, LR, UR, PL, UL 1650 | DB LR, LR, LR, UR, MUR | PL, PL, MDL | PL, UD 1651 | DB UD, MDR | PL, PL, MUL | PL, UL, LR, LR, LR 1652 | DB UR, PL, UL, LR, LR, DR, PL, UD 1653 | 1654 | DB UD, MDUR | PL, PL, SP, MDL | PL, UD, PL, LR 1655 | DB LR, LR, LR, LR, LR, DR, PL, LR 1656 | DB DR, PL, LR, LR, LR, LR, LR, LR 1657 | DB DR, PL, UD, MDR | PL, SP, PL, MDUL | PL, UD 1658 | 1659 | DB UD, PL, UL, UR, PL, UD, MUR | PL, PL 1660 | DB PL, PL, PL, MDRL | PL, PL, PL, MDURL | PL, PL 1661 | DB PL, MDURL | PL, PL, PL, MDRL | PL, PL, PL, PL 1662 | DB PL, MUL | PL, UD, PL, UL, UR, PL, UD 1663 | 1664 | DB UD, PL, LR, DR, PL, LR, LR, LR 1665 | DB LR, LR, DR, PL, UL, UR, PL, LR 1666 | DB DR, PL, UL, UR, PL, LR, LR, LR 1667 | DB LR, LR, DR, PL, LR, DR, PL, UD 1668 | 1669 | DB UD, MUR | PL, PL, PL, MURL | PL, PL, PL, PL 1670 | DB PL, PL, PL, MUL | PL, UD, UD, MUR | PL, PL 1671 | DB PL, MUL | PL, UD, UD, MUR | PL, PL, PL, PL 1672 | DB PL, PL, PL, MURL | PL, PL, PL, MUL | PL, UD 1673 | 1674 | DB LR, LR, LR, LR, LR, LR, LR, LR 1675 | DB LR, LR, LR, LR, DR, LR, LR, LR 1676 | DB LR, LR, DR, LR, LR, LR, LR, LR 1677 | DB LR, LR, LR, LR, LR, LR, LR, DR 1678 | 1679 | XREF ON 1680 | 1681 | MAZEEND = ? 1682 | 1683 | EYES = ? 1684 | 1685 | IFDEF SUPER 1686 | 1687 | EYELEFT: DW $.......1111..... 1688 | DW $......1....1.... 1689 | DW $.....1..11..1... 1690 | DW $....1..1111..1.. 1691 | DW $....1.111111.1.. 1692 | DW $....1.111.11.1.. 1693 | DW $....1..1111..1.1 1694 | DW $.....1..11..1..1 1695 | DW $......1....1..11 1696 | DW $.......1111..111 1697 | DW $.............111 1698 | DW $.......11.....11 1699 | DW $......111111.... 1700 | DW $.......111111111 1701 | DW $........11111111 1702 | DW $..........111111 1703 | 1704 | EYERIGHT: DW $....1111........ 1705 | DW $...1....1....... 1706 | DW $..1..11..1...... 1707 | DW $.1..1111..1..... 1708 | DW $.1.111111.1..... 1709 | DW $.1.111.11.1..... 1710 | DW $.1..1111..1..... 1711 | DW $..1..11..1...... 1712 | DW $1..1....1....... 1713 | DW $11..1111........ 1714 | DW $11.............. 1715 | DW $1.....11........ 1716 | DW $...111111....... 1717 | DW $11111111........ 1718 | DW $1111111......... 1719 | DW $11111........... 1720 | 1721 | EYEBLINK: DW $....1111........ 1722 | DW $...111111....... 1723 | DW $..11111111...... 1724 | DW $.1111111111..... 1725 | DW $.1111111111..... 1726 | DW $.1.11111111..... 1727 | DW $.1...111111..... 1728 | DW $..1.....11...... 1729 | DW $1..1....1....... 1730 | DW $11..1111........ 1731 | DW $11......1....... 1732 | DW $1.....1111...... 1733 | DW $...111111....... 1734 | DW $11111111........ 1735 | DW $1111111......... 1736 | DW $11111........... 1737 | 1738 | ELSE 1739 | 1740 | EYELEFT: DB $..1111.. 1741 | DB $.1....1. 1742 | DB $1..11..1 1743 | DB $1..11..1 1744 | DB $.1....1. 1745 | DB $..1111.. 1746 | DB $.......1 1747 | DB $...1.... 1748 | DB $....1111 1749 | 1750 | EYERIGHT: DB $.1111... 1751 | DB $1....1.. 1752 | DB $..11..1. 1753 | DB $..11..1. 1754 | DB $1....1.. 1755 | DB $.1111... 1756 | DB $........ 1757 | DB $...1.... 1758 | DB $111..... 1759 | 1760 | EYEBLINK: DB $.1111... 1761 | DB $111111.. 1762 | DB $1111111. 1763 | DB $1111111. 1764 | DB $1....1.. 1765 | DB $.1111... 1766 | DB $........ 1767 | DB $...1.... 1768 | DB $111..... 1769 | 1770 | ENDIF 1771 | 1772 | USED OFF 1773 | ALIGN ON 1774 | 1775 | BUFFER = ? 1776 | -------------------------------------------------------------------------------- /roms/SOURCES/BREAKOUT.SRC: -------------------------------------------------------------------------------- 1 | ; This variant of BRIX, calles BREAKOUT, has larger bricks, 2 | ; making a wall like the BREAKOUT game on the Atari 2600. 3 | ; The only difference with brix is the brick sprite. 4 | ; 5 | ; Note: source of BRIX has been modified by David WINTER on 17 SEP 1997 6 | ; (only the syntax changed: it has been converted in CHIPPER) 7 | ; 8 | ; The source could be optimized to save some bytes, but I didn't wanted 9 | ; to modify it since there is no specific interest in this. 10 | ; 11 | ; NOTE THAT THE ORIGINAL SOURCE HAD SEVERAL ERRORS !!! 12 | ; 13 | ; ------------------------------------------------------ 14 | ; 15 | ; Author: vervalin@AUSTIN.LOCKHEED.COM (Paul Vervalin) 16 | ; 17 | ; register contents 18 | ; ------------------------------------------------------ 19 | ; V0 scratch 20 | ; V1 scratch 21 | ; V2 scratch 22 | ; V3 X coordinate of score 23 | ; V4 Y coordinate of score 24 | ; V5 bricks hit counter 25 | ; V6 ball X coordinate 26 | ; V7 ball Y coordinate 27 | ; V8 ball X direction 28 | ; V9 ball Y direction 29 | ; VA X coordinate when generating bricks 30 | ; VB Y coordinate when generating bricks 31 | ; VC paddle X coordinate 32 | ; VD paddle Y coordinate 33 | ; VE ball counter 34 | ; VF collision detect 35 | 36 | option binary ; If you compile for HP48 use, remove this line 37 | 38 | 39 | 40 | LD VE, 5 ; Set number of balls to 5 41 | LD V5, 0 ; Initial number of hit bricks is 0 42 | LD VB, 6 ; Set Y position of first brick to draw 43 | 44 | Draw_Bricks: 45 | LD VA, 0 ; Set X position of first brick to draw 46 | 47 | Draw_Brick_Row: 48 | LD I, Brick ; I points on the brick sprite 49 | DRW VA, VB, 1 ; Draw brick 50 | ADD VA, 4 ; Move along X to next brick location 51 | SE VA, 64 ; If location wrapped goto next row 52 | JP Draw_Brick_Row ; Otherwise draw another 53 | 54 | ADD VB, 2 ; Move down Y to next row 55 | SE VB, #12 ; If all rows drawn, continue on 56 | 57 | JP Draw_Bricks ; Otherwise draw next row 58 | 59 | LD VC, 32 ; Set X location of paddle 60 | LD VD, 31 ; Set Y location of paddle 61 | LD I, Paddle ; Get address of paddle sprite 62 | DRW VC, VD, 1 ; Draw paddle 63 | 64 | CALL Draw_Score ; Call subroutine to draw score 65 | 66 | LD V0, 0 ; Set X coord of balls remaining 67 | LD V1, 0 ; Set Y coord of balls remaining 68 | LD I, Balls ; I points on balls sprite 69 | DRW V0, V1, 1 ; Draw 4 of the five balls 70 | ADD V0, 8 ; Set X location of the 5th ball sprite 71 | LD I, Ball ; I points on ball sprite 72 | DRW V0, V1, 1 ; Draw 5th ball 73 | 74 | Play: 75 | LD V0, #40 ; Set V0 for delay 76 | LD DT, V0 ; Set delay timer 77 | Wait: 78 | LD V0, DT ; Check status of delay timer 79 | SE V0, 0 ; Skip next if delay timer is 0 80 | JP Wait ; Check again 81 | 82 | RND V6, #0F ; Get random coord for ball start 83 | LD V7, 30 ; Set Y coord of ball start 84 | LD V8, 1 ; Set X direction to RIGHT 85 | LD V9, #FF ; Set Y direction to UP 86 | 87 | LD I, Ball ; I points on single ball sprite 88 | DRW V6, V7, 1 ; Draw ball 89 | 90 | Loop: 91 | LD I, Paddle ; Get address of paddle sprite 92 | DRW VC, VD, 1 ; Draw paddle at loc. VC VD 93 | 94 | LD V0, 04 ; Set V0 to key 4 95 | SKNP V0 ; Skip next if key V0 not pressed 96 | ADD VC, #FE ; Move paddle two pixels left 97 | 98 | LD V0, 06 ; Set V0 to key 6 99 | SKNP V0 ; Skip next if key V0 not pressed 100 | ADD VC, 2 ; Move paddle two pixels right 101 | 102 | LD V0, #3F ; Set V0 right edge of screen 103 | AND VC, V0 ; Wrap paddle around if needed 104 | DRW VC, VD, 1 ; Draw paddle 105 | 106 | LD I, Ball ; Get address of ball sprite 107 | DRW V6, V7, 1 ; Draw ball 108 | ADD V6, V8 ; Move ball in X direction by V8 109 | ADD V7, V9 ; Move ball in Y direction by V9 110 | 111 | LD V0, 63 ; Set highest X coord. 112 | AND V6, V0 ; AND ball X pos. with V0 113 | 114 | LD V1, 31 ; Set highest Y coord 115 | AND V7, V1 ; AND ball Y pos. with V1 116 | 117 | SNE V7, 31 ; If ball not at bottom, skip 118 | JP Bottom ; Else check for paddle pos 119 | 120 | 121 | Check_Paddle: 122 | SNE V6, 0 ; If ball not at left side, skip 123 | LD V8, 1 ; Set X direction to RIGHT 124 | 125 | SNE V6, 63 ; If ball not at right side, skip 126 | LD V8, #FF ; Set X direction to LEFT 127 | 128 | SNE V7, 0 ; If ball not at top, skip 129 | LD V9, 1 ; Set Y direction to DOWN 130 | 131 | DRW V6, V7, 1 ; Draw ball 132 | SE VF, 1 ; If there was a collision, skip 133 | JP Brick_Untouched 134 | 135 | SNE V7, 31 ; If ball not at bottom skip 136 | JP Brick_Untouched 137 | 138 | LD V0, 5 ; Set V0 for 5 lines at screen top 139 | SUB V0, V7 ; Check if ball was in this region 140 | SE VF, 0 ; If it was not then skip 141 | JP Brick_Untouched 142 | 143 | LD V0, 1 ; There was a collision 144 | LD ST, V0 ; So beep 145 | 146 | LD V0, V6 ; Get X coord of ball 147 | LD V1, #FC ; Compute postion of the brick 148 | AND V0, V1 ; which was hit 149 | 150 | LD I, Brick ; I points on brick sprite 151 | DRW V0, V7, 1 ; Erase brick sprite by drawing 152 | LD V0, #FE ; reverse the Y direction of the 153 | XOR V9, V0 ; ball sprite 154 | 155 | CALL Draw_Score ; Call subroutine to draw score 156 | ADD V5, 1 ; Increments bricks hit counter by one 157 | CALL Draw_Score ; Call subroutine to draw score 158 | 159 | SNE V5, 96 ; If all bricks have not been hit, skip 160 | JP Over ; Else game ends, so stop 161 | 162 | 163 | Brick_Untouched: 164 | JP Loop 165 | 166 | Bottom: 167 | LD V9, #FF ; Ball is at bottom, so set direction to UP 168 | LD V0, V6 ; Get X location of ball 169 | SUB V0, VC ; Intersect with paddle 170 | SE VF, 1 ; If intersect then skip 171 | JP Ball_Lost 172 | 173 | LD V1, 2 ; 174 | SUB V0, V1 ; This portion calculates 175 | SE VF, 1 ; the direction where the 176 | JP Go_Left ; ball will bounce, 177 | SUB V0, V1 ; depending on the position 178 | SE VF, 1 ; of the ball on the paddle, 179 | JP Paddle_Beep ; and the direction it had 180 | SUB V0, V1 ; before hiting the paddle. 181 | SE VF, 1 ; 182 | JP Go_Right ; 183 | 184 | 185 | Ball_Lost: 186 | LD V0, 32 ; Set beep delay 187 | LD ST, V0 ; Beep for lost ball 188 | 189 | LD I, Ball ; I points on ball sprite 190 | ADD VE, #FF ; Remove 1 from balls counter 191 | LD V0, VE ; Set V0 to ball counter 192 | 193 | ADD V0, V0 ; Compute location of ball to erase 194 | LD V1, 0 ; Set Y location of top line 195 | DRW V0, V1, 1 ; Erase ball from remaining 196 | SE VE, 0 ; If no balls remain, skip 197 | JP Play ; Prepare for a new ball to play 198 | 199 | 200 | Over: 201 | JP Over 202 | 203 | 204 | Go_Left: 205 | ADD V8, #FF ; Make ball go LEFT 206 | SNE V8, #FE ; If ball was not going left, skip 207 | LD V8, #FF ; Make it go LEFT by 1 not 2 208 | JP Paddle_Beep 209 | 210 | 211 | Go_Right: 212 | ADD V8, 1 ; Make ball go right 213 | SNE V8, 2 ; If ball was not going right, skip 214 | LD V8,1 ; Make it go RIGHT by 1 not 2 215 | 216 | 217 | Paddle_Beep: 218 | LD V0, 4 ; Set beep time for paddle hit 219 | LD ST, V0 ; Turn on beeper 220 | LD V9, #FF ; Set ball direction to UP 221 | JP Check_Paddle ; Then, continue playing and check for paddle move 222 | 223 | 224 | Draw_Score: 225 | LD I, Score ; Set address to BCD score location 226 | LD B, V5 ; Store BCD of score 227 | LD V2, [I] ; Read BCD of score in V0...V2 228 | LD F, V1 ; Get font for tens value from V1 229 | LD V3, 55 ; Set X location of score tens place 230 | LD V4, 0 ; Set Y location of score 231 | DRW V3, V4, 5 ; Draw tens place score # 232 | ADD V3, 5 ; Set X location of score ones place 233 | LD F, V2 ; Get font for ones value from V2 234 | DRW V3, V4, 5 ; Draw ones place score # 235 | RET ; Return 236 | 237 | 238 | Brick: 239 | DW #F000 ; Brick sprite 240 | 241 | 242 | Ball: 243 | DW #8000 ; Ball sprite 244 | 245 | 246 | Paddle: 247 | DW #FC00 ; Paddle sprite 248 | 249 | 250 | Balls: 251 | DW #AA00 ; Balls remaining sprite 252 | 253 | 254 | Score: 255 | DW #0000 ; Score storage 256 | DW #0000 ; 257 | -------------------------------------------------------------------------------- /roms/SOURCES/BRIX.SRC: -------------------------------------------------------------------------------- 1 | ; Note: this source has been modified by David WINTER on 17 SEP 1997 2 | ; (only the syntax changed: it has been converted in CHIPPER) 3 | ; 4 | ; The source could be optimized to save some bytes, but I didn't wanted 5 | ; to modify it since there is no specific interest in this. 6 | ; 7 | ; NOTE THAT THE ORIGINAL SOURCE HAD SEVERAL ERRORS !!! 8 | ; 9 | ; ------------------------------------------------------ 10 | ; 11 | ; Author: vervalin@AUSTIN.LOCKHEED.COM (Paul Vervalin) 12 | ; 13 | ; register contents 14 | ; ------------------------------------------------------ 15 | ; V0 scratch 16 | ; V1 scratch 17 | ; V2 scratch 18 | ; V3 X coordinate of score 19 | ; V4 Y coordinate of score 20 | ; V5 bricks hit counter 21 | ; V6 ball X coordinate 22 | ; V7 ball Y coordinate 23 | ; V8 ball X direction 24 | ; V9 ball Y direction 25 | ; VA X coordinate when generating bricks 26 | ; VB Y coordinate when generating bricks 27 | ; VC paddle X coordinate 28 | ; VD paddle Y coordinate 29 | ; VE ball counter 30 | ; VF collision detect 31 | 32 | option binary ; If you compile for HP48 use, remove this line 33 | 34 | 35 | 36 | LD VE, 5 ; Set number of balls to 5 37 | LD V5, 0 ; Initial number of hit bricks is 0 38 | LD VB, 6 ; Set Y position of first brick to draw 39 | 40 | Draw_Bricks: 41 | LD VA, 0 ; Set X position of first brick to draw 42 | 43 | Draw_Brick_Row: 44 | LD I, Brick ; I points on the brick sprite 45 | DRW VA, VB, 1 ; Draw brick 46 | ADD VA, 4 ; Move along X to next brick location 47 | SE VA, 64 ; If location wrapped goto next row 48 | JP Draw_Brick_Row ; Otherwise draw another 49 | 50 | ADD VB, 2 ; Move down Y to next row 51 | SE VB, #12 ; If all rows drawn, continue on 52 | 53 | JP Draw_Bricks ; Otherwise draw next row 54 | 55 | LD VC, 32 ; Set X location of paddle 56 | LD VD, 31 ; Set Y location of paddle 57 | LD I, Paddle ; Get address of paddle sprite 58 | DRW VC, VD, 1 ; Draw paddle 59 | 60 | CALL Draw_Score ; Call subroutine to draw score 61 | 62 | LD V0, 0 ; Set X coord of balls remaining 63 | LD V1, 0 ; Set Y coord of balls remaining 64 | LD I, Balls ; I points on balls sprite 65 | DRW V0, V1, 1 ; Draw 4 of the five balls 66 | ADD V0, 8 ; Set X location of the 5th ball sprite 67 | LD I, Ball ; I points on ball sprite 68 | DRW V0, V1, 1 ; Draw 5th ball 69 | 70 | Play: 71 | LD V0, #40 ; Set V0 for delay 72 | LD DT, V0 ; Set delay timer 73 | Wait: 74 | LD V0, DT ; Check status of delay timer 75 | SE V0, 0 ; Skip next if delay timer is 0 76 | JP Wait ; Check again 77 | 78 | RND V6, #0F ; Get random coord for ball start 79 | LD V7, 30 ; Set Y coord of ball start 80 | LD V8, 1 ; Set X direction to RIGHT 81 | LD V9, #FF ; Set Y direction to UP 82 | 83 | LD I, Ball ; I points on single ball sprite 84 | DRW V6, V7, 1 ; Draw ball 85 | 86 | Loop: 87 | LD I, Paddle ; Get address of paddle sprite 88 | DRW VC, VD, 1 ; Draw paddle at loc. VC VD 89 | 90 | LD V0, 04 ; Set V0 to key 4 91 | SKNP V0 ; Skip next if key V0 not pressed 92 | ADD VC, #FE ; Move paddle two pixels left 93 | 94 | LD V0, 06 ; Set V0 to key 6 95 | SKNP V0 ; Skip next if key V0 not pressed 96 | ADD VC, 2 ; Move paddle two pixels right 97 | 98 | LD V0, #3F ; Set V0 right edge of screen 99 | AND VC, V0 ; Wrap paddle around if needed 100 | DRW VC, VD, 1 ; Draw paddle 101 | 102 | LD I, Ball ; Get address of ball sprite 103 | DRW V6, V7, 1 ; Draw ball 104 | ADD V6, V8 ; Move ball in X direction by V8 105 | ADD V7, V9 ; Move ball in Y direction by V9 106 | 107 | LD V0, 63 ; Set highest X coord. 108 | AND V6, V0 ; AND ball X pos. with V0 109 | 110 | LD V1, 31 ; Set highest Y coord 111 | AND V7, V1 ; AND ball Y pos. with V1 112 | 113 | SNE V7, 31 ; If ball not at bottom, skip 114 | JP Bottom ; Else check for paddle pos 115 | 116 | 117 | Check_Paddle: 118 | SNE V6, 0 ; If ball not at left side, skip 119 | LD V8, 1 ; Set X direction to RIGHT 120 | 121 | SNE V6, 63 ; If ball not at right side, skip 122 | LD V8, #FF ; Set X direction to LEFT 123 | 124 | SNE V7, 0 ; If ball not at top, skip 125 | LD V9, 1 ; Set Y direction to DOWN 126 | 127 | DRW V6, V7, 1 ; Draw ball 128 | SE VF, 1 ; If there was a collision, skip 129 | JP Brick_Untouched 130 | 131 | SNE V7, 31 ; If ball not at bottom skip 132 | JP Brick_Untouched 133 | 134 | LD V0, 5 ; Set V0 for 5 lines at screen top 135 | SUB V0, V7 ; Check if ball was in this region 136 | SE VF, 0 ; If it was not then skip 137 | JP Brick_Untouched 138 | 139 | LD V0, 1 ; There was a collision 140 | LD ST, V0 ; So beep 141 | 142 | LD V0, V6 ; Get X coord of ball 143 | LD V1, #FC ; Compute postion of the brick 144 | AND V0, V1 ; which was hit 145 | 146 | LD I, Brick ; I points on brick sprite 147 | DRW V0, V7, 1 ; Erase brick sprite by drawing 148 | LD V0, #FE ; reverse the Y direction of the 149 | XOR V9, V0 ; ball sprite 150 | 151 | CALL Draw_Score ; Call subroutine to draw score 152 | ADD V5, 1 ; Increments bricks hit counter by one 153 | CALL Draw_Score ; Call subroutine to draw score 154 | 155 | SNE V5, 96 ; If all bricks have not been hit, skip 156 | JP Over ; Else game ends, so stop 157 | 158 | 159 | Brick_Untouched: 160 | JP Loop 161 | 162 | Bottom: 163 | LD V9, #FF ; Ball is at bottom, so set direction to UP 164 | LD V0, V6 ; Get X location of ball 165 | SUB V0, VC ; Intersect with paddle 166 | SE VF, 1 ; If intersect then skip 167 | JP Ball_Lost 168 | 169 | LD V1, 2 ; 170 | SUB V0, V1 ; This portion calculates 171 | SE VF, 1 ; the direction where the 172 | JP Go_Left ; ball will bounce, 173 | SUB V0, V1 ; depending on the position 174 | SE VF, 1 ; of the ball on the paddle, 175 | JP Paddle_Beep ; and the direction it had 176 | SUB V0, V1 ; before hiting the paddle. 177 | SE VF, 1 ; 178 | JP Go_Right ; 179 | 180 | 181 | Ball_Lost: 182 | LD V0, 32 ; Set beep delay 183 | LD ST, V0 ; Beep for lost ball 184 | 185 | LD I, Ball ; I points on ball sprite 186 | ADD VE, #FF ; Remove 1 from balls counter 187 | LD V0, VE ; Set V0 to ball counter 188 | 189 | ADD V0, V0 ; Compute location of ball to erase 190 | LD V1, 0 ; Set Y location of top line 191 | DRW V0, V1, 1 ; Erase ball from remaining 192 | SE VE, 0 ; If no balls remain, skip 193 | JP Play ; Prepare for a new ball to play 194 | 195 | 196 | Over: 197 | JP Over 198 | 199 | 200 | Go_Left: 201 | ADD V8, #FF ; Make ball go LEFT 202 | SNE V8, #FE ; If ball was not going left, skip 203 | LD V8, #FF ; Make it go LEFT by 1 not 2 204 | JP Paddle_Beep 205 | 206 | 207 | Go_Right: 208 | ADD V8, 1 ; Make ball go right 209 | SNE V8, 2 ; If ball was not going right, skip 210 | LD V8,1 ; Make it go RIGHT by 1 not 2 211 | 212 | 213 | Paddle_Beep: 214 | LD V0, 4 ; Set beep time for paddle hit 215 | LD ST, V0 ; Turn on beeper 216 | LD V9, #FF ; Set ball direction to UP 217 | JP Check_Paddle ; Then, continue playing and check for paddle move 218 | 219 | 220 | Draw_Score: 221 | LD I, Score ; Set address to BCD score location 222 | LD B, V5 ; Store BCD of score 223 | LD V2, [I] ; Read BCD of score in V0...V2 224 | LD F, V1 ; Get font for tens value from V1 225 | LD V3, 55 ; Set X location of score tens place 226 | LD V4, 0 ; Set Y location of score 227 | DRW V3, V4, 5 ; Draw tens place score # 228 | ADD V3, 5 ; Set X location of score ones place 229 | LD F, V2 ; Get font for ones value from V2 230 | DRW V3, V4, 5 ; Draw ones place score # 231 | RET ; Return 232 | 233 | 234 | Brick: 235 | DW #E000 ; Brick sprite 236 | 237 | 238 | Ball: 239 | DW #8000 ; Ball sprite 240 | 241 | 242 | Paddle: 243 | DW #FC00 ; Paddle sprite 244 | 245 | 246 | Balls: 247 | DW #AA00 ; Balls remaining sprite 248 | 249 | 250 | Score: 251 | DW #0000 ; Score storage 252 | DW #0000 ; 253 | -------------------------------------------------------------------------------- /roms/SOURCES/MAZE.SRC: -------------------------------------------------------------------------------- 1 | OPTION BINARY ; We want a binary file, not an HP48 one. 2 | ALIGN OFF ; And we don't want auto alignement, as some 3 | ; data can be made of bytes instead of words. 4 | 5 | 6 | ; Drawing a random maze like this one consists in drawing random diagonal 7 | ; lines. There are two possibilities: right-to-left line, and left-to-right 8 | ; line. Each line is composed of a 4*4 bitmap. As the lines must form non- 9 | ; circular angles, the two bitmaps won't be '/' and '\'. The first one 10 | ; (right line) will be a little bit modified. See at the end of this source. 11 | ; 12 | ; The maze is composed of 8 lines (as the bitmaps are 4 pixels high), each 13 | ; line consists of 16 bitmaps. 14 | ; Bitmaps are drawn in random mode. We choose a random value (0 or 1). 15 | ; If it is 1, we draw a left line bitmap. If it is 0, we draw a right one. 16 | 17 | 18 | ; Rsgister usage: 19 | ; 20 | ; V0: X-coordinate of the bitmap 21 | ; V1: Y-coordinate of the bitmap 22 | ; V2: Random number 23 | 24 | LD V0, 0 25 | LD V1, 0 26 | 27 | LOOP: 28 | LD I, LEFT ; We draw a left line by default, as the random number 29 | ; is 0 or 1. If we suppose that it will be 1, we keep 30 | ; drawing the left line. If it is 0, we change register 31 | ; I to draw a right line. 32 | 33 | RND V2, 1 ; Load in V2 a 0...1 random number 34 | 35 | SE V2, 1 ; It is 1 ? If yes, I still refers to the left line 36 | ; bitmap. 37 | 38 | LD I, RIGHT ; If not, we change I to make it refer the right line 39 | ; bitmap. 40 | 41 | DRW V0, V1, 4 ; And we draw the bitmap at V0, V1. 42 | 43 | ADD V0, 4 ; The next bitmap is 4 pixels right. So we update 44 | ; V0 to do so. 45 | 46 | SE V0, 64 ; If V0==64, we finished drawing a complete line, so we 47 | ; skip the jump to LOOP, as we have to update V1 too. 48 | 49 | JP LOOP ; We did not draw a complete line ? So we continue ! 50 | 51 | LD V0, 0 ; The first bitmap of each line is located 0, V1. 52 | 53 | ADD V1, 4 ; We update V1. The next line is located 4 pixels doan. 54 | 55 | SE V1, 32 ; Have we drawn all the lines ? If yes, V1==32. 56 | JP LOOP ; No ? So we continue ! 57 | 58 | FIN: JP FIN ; Infinite loop... 59 | 60 | RIGHT: ; 4*4 bitmap of the left line 61 | 62 | DB $1....... 63 | DB $.1...... 64 | DB $..1..... 65 | DB $...1.... 66 | 67 | LEFT: ; 4*4 bitmap of the right line 68 | ; And YES, it is like that... 69 | DB $..1..... 70 | DB $.1...... 71 | DB $1....... 72 | DB $...1.... 73 | -------------------------------------------------------------------------------- /roms/SOURCES/PONG.SRC: -------------------------------------------------------------------------------- 1 | ; Note: this source has been modified by David WINTER on 17 SEP 1997 2 | ; (only the syntax changed: it has been converted in CHIPPER) 3 | ; 4 | ; The source could be optimized to save some bytes, but I didn't wanted 5 | ; to modify it since there is no specific interest in this. 6 | ; 7 | ; NOTE THAT THE ORIGINAL SOURCE HAD SEVERAL ERRORS !!! 8 | ; 9 | ; --------------------------------------------------------------------------- 10 | ; 11 | ; From: vervalin@AUSTIN.LOCKHEED.COM (Paul Vervalin) 12 | ; 13 | ; 14 | ; OK folks here it is! PONG for the HP48SX written in CHIP-48. 15 | ; Some things you should know before you start playing are... 16 | ; 1) This is my first attempt at programming in CHIP-48, so I 17 | ; know there are probably a few things that could have been 18 | ; done better. 19 | ; 2) The game never ends. It keeps score, but only up to 9 for 20 | ; each player, then it will roll over to 0. Sorry, its the 21 | ; only way I could think of to do it. So, you have to play 22 | ; whoever gets to a number first, wins. 23 | ; 3) It is kind of slow, but then there are two paddles and ball 24 | ; moving around all at once. 25 | ; 4) The player who got the last point gets the serve... 26 | ; 5) Keys 7 and 4 (on the HP48) control the up and down of the 27 | ; left player and the / and * keys control the up and down of 28 | ; the right player. 29 | ; 30 | ; I think that's about it, so have fun! 31 | ; 32 | ; This is a detailed breakdown of the game, sooooooo, if anybody wants to 33 | ; make it better, or change it in some way, it might be a little easier. 34 | ; Also, about half of the code was in some way extracted from the BRIX 35 | ; program. So, thanks to whoever wrote the original BRIX game. 36 | ; 37 | ; 38 | ; Registers 39 | ; --------- 40 | ; V0-V3 are scratch registers 41 | ; V4 X coord. of score 42 | ; V5 Y coord. of score 43 | ; V6 X coord. of ball 44 | ; V7 Y coord. of ball 45 | ; V8 X direction of ball motion 46 | ; V9 Y direction of ball motion 47 | ; VA X coord. of left player paddle 48 | ; VB Y coord. of left player paddle 49 | ; VC X coord. of right player paddle 50 | ; VD Y coord. of right player paddle 51 | ; VE Score 52 | ; VF collision detection 53 | 54 | 55 | option binary ; To assemble PONG for HP48 use, remove this option 56 | 57 | 58 | LD VA, 2 ; Set left player X coord. 59 | LD VB, 12 ; Set left player Y coord. 60 | LD VC, 63 ; Set right player X coord. 61 | LD VD, 12 ; Set right player Y coord. 62 | 63 | LD I, Paddle ; Get address of paddle sprite 64 | DRW VA, VB, 6 ; Draw left paddle 65 | DRW VC, VD, 6 ; Draw right paddle 66 | 67 | LD VE, 0 ; Set score to 00 68 | CALL Draw_Score ; Draw score 69 | 70 | LD V6, 3 ; Set X coord. of ball to 3 71 | LD V8, 2 ; Set ball X direction to right 72 | 73 | 74 | Big_Loop: 75 | 76 | LD V0, #60 ; Set V0=delay before ball launch 77 | LD DT, V0 ; Set delay timer to V0 78 | DT_loop: ; 79 | LD V0, DT ; Read delay timer into V0 80 | SE V0, 0 ; Skip next instruction if V0=0 81 | JP DT_Loop ; Read again delay timer if not 0 82 | 83 | RND V7, 23 ; Set Y coord. to rand # AND 23 (0...23) 84 | ADD V7, 8 ; And adjust it to is 8...31 85 | 86 | LD V9, #FF ; Set ball Y direction to up 87 | LD I, Ball ; Get address of ball sprite 88 | DRW V6, V7, 1 ; Draw ball 89 | 90 | Padl_Loop: 91 | LD I, Paddle ; Get address of paddle sprite 92 | DRW VA, VB, 6 ; Draw left paddle 93 | DRW VC, VD, 6 ; Draw right paddle 94 | 95 | LD V0, 1 ; Set V0 to KEY 1 96 | SKNP V0 ; Skip next instruction if KEY in 1 is not pressed 97 | ADD VB, #FE ; Subtract 2 from Y coord. of left paddle 98 | 99 | LD V0, 4 ; Set V0 to KEY 4 100 | SKNP V0 ; Skip next instruction if KEY in 4 is not pressed 101 | ADD VB, 2 ; Add 2 to Y coord. of left paddle 102 | 103 | LD V0, 31 ; Set V0 to max Y coord. | These three lines are here to 104 | AND VB, V0 ; AND VB with V0 | adjust the paddle position if 105 | DRW VA, VB, 6 ; Draw left paddle | it is out of the screen 106 | 107 | LD V0, #0C ; Set V0 to KEY C 108 | SKNP V0 ; Skip next instruction if KEY in C is not pressed 109 | ADD VD, #FE ; Subtract 2 from Y coord. of right paddle 110 | 111 | LD V0, #0D ; Set V0 to KEY D 112 | SKNP V0 ; Skip next instruction if KEY in D is not pressed 113 | ADD VD, 2 ; Add 2 to Y coord. of right paddle 114 | 115 | LD V0, 31 ; Set V0 to max Y coord. | These three lines are here to 116 | AND VD, V0 ; AND VD with V0 | adjust the paddle position if 117 | DRW VC, VD, 6 ; Draw right paddle | it is out of the screen 118 | 119 | LD I, Ball ; Get address of ball sprite 120 | DRW V6, V7, 1 ; Draw ball 121 | 122 | ADD V6, V8 ; Compute next X coord of the ball 123 | ADD V7, V9 ; Compute next Y coord of the ball 124 | 125 | LD V0, 63 ; Set V0 to max X location 126 | AND V6, V0 ; AND V6 with V0 127 | 128 | LD V1, 31 ; Set V1 to max Y location 129 | AND V7, V1 ; AND V7 with V1 130 | 131 | SNE V6, 2 ; Skip next instruction if ball not at left 132 | JP Left_Side ; 133 | 134 | SNE V6, 63 ; Skip next instruction if ball not at right 135 | JP Right_Side ; 136 | 137 | Ball_Loop: 138 | SNE V7, 31 ; Skip next instruction if ball not at bottom 139 | LD V9, #FF ; Set Y direction to up 140 | 141 | SNE V7, 0 ; Skip next instruction if ball not at top 142 | LD V9, 1 ; Set Y direction to down 143 | 144 | DRW V6, V7, 1 ; Draw ball 145 | JP Padl_loop ; 146 | 147 | Left_Side: 148 | LD V8, 2 ; Set X direction to right 149 | LD V3, 1 ; Set V3 to 1 in case left player misses ball 150 | LD V0, V7 ; Set V0 to V7 Y coord. of ball 151 | SUB V0, VB ; Subtract position of paddle from ball 152 | JP Pad_Coll ; Check for collision 153 | 154 | Right_Side: 155 | LD V8, 254 ; Set X direction to left 156 | LD V3, 10 ; Set V3 to 10 in case right player misses ball 157 | LD V0, V7 ; Set V0 to V7 Y coord. of ball 158 | SUB V0, VD ; Subtract position of paddle from ball 159 | 160 | Pad_Coll: 161 | SE VF, 1 ; Skip next instruction if ball not above paddle 162 | JP Ball_Lost ; 163 | 164 | LD V1, 2 ; Set V1 to 02 165 | SUB V0, V1 ; Subtract V1 from V0 166 | SE VF, 1 ; Skip next instr. if ball not at top of paddle 167 | JP Ball_Top ; Ball at top of paddle 168 | 169 | SUB V0, V1 ; Subtract another 2 from V0 170 | SE VF, 1 ; Skip next instr. if ball not at middle of paddle 171 | JP Pad_Hit ; Ball in middle of paddle 172 | 173 | SUB V0, V1 ; Subtract another 2 from V0 174 | SE VF, 1 ; Skip next instr. if ball not at bottom of paddle 175 | JP Ball_Bot ; Ball at bottom of paddle 176 | 177 | Ball_Lost: 178 | LD V0, 32 ; Set lost ball beep delay 179 | LD ST, V0 ; Beep for lost ball 180 | 181 | CALL Draw_Score ; Erase previous score 182 | ADD VE, V3 ; Add 1 or 10 to score depending on V3 183 | CALL Draw_Score ; Write new score 184 | 185 | LD V6, 62 ; Set ball X coord. to right side 186 | SE V3, 1 ; Skip next instr. if right player got point 187 | LD V6, 3 ; Set ball X coord. to left side 188 | LD V8, #FE ; Set direction to left 189 | SE V3, 1 ; Skip next instr. if right player got point 190 | LD V8, 2 ; Set direction to right 191 | JP Big_Loop ; 192 | 193 | Ball_Top: 194 | ADD V9, #FF ; Subtract 1 from V9, ball Y direction 195 | SNE V9, #FE ; Skip next instr. if V9 != FE (-2) 196 | LD V9, #FF ; Set V9=FF (-1) 197 | JP Pad_Hit 198 | 199 | Ball_Bot: 200 | ADD V9, 1 ; Add 1 to V9, ball Y direction 201 | SNE V9, 2 ; Skip next instr. if V9 != 02 202 | LD V9, 1 ; Set V9=01 203 | 204 | Pad_Hit: 205 | LD V0, 4 ; Set beep for paddle hit 206 | LD ST, V0 ; Sound beep 207 | 208 | ADD V6, 1 ; 209 | SNE V6, 64 ; 210 | ADD V6, 254 ; 211 | 212 | JP Ball_Loop 213 | 214 | Draw_Score: 215 | LD I, Score ; Get address of Score 216 | LD B, VE ; Stores in memory BCD representation of VE 217 | LD V2, [I] ; Reads V0...V2 in memory, so the score 218 | LD F, V1 ; I points to hex char in V1, so the 1st score char 219 | LD V4, #14 ; Set V4 to the X coord. to draw 1st score char 220 | LD V5, 0 ; Set V5 to the Y coord. to draw 1st score char 221 | DRW V4, V5, 5 ; Draw 8*5 sprite at (V4,V5) from M[I], so char V1 222 | ADD V4, #15 ; Set X to the X coord. of 2nd score char 223 | LD F, V2 ; I points to hex char in V2, so 2nd score char 224 | DRW V4, V5, 5 ; Draw 8*5 sprite at (V4,V5) from M[I], so char V2 225 | RET ; Return 226 | 227 | Paddle: 228 | DW #8080 229 | DW #8080 230 | DW #8080 231 | 232 | Ball: 233 | DW #8000 234 | 235 | Score: 236 | DW #0000 237 | DW #0000 238 | -------------------------------------------------------------------------------- /roms/SOURCES/PONG2.SRC: -------------------------------------------------------------------------------- 1 | ; Note: this source has been modified by David WINTER on 17 SEP 1997 2 | ; (only the syntax changed: it has been converted in CHIPPER) 3 | ; 4 | ; 99% of this source is taken from Paul Vervalin's PONG game. The only 5 | ; changes are the position of the left paddle, and the vertical line on 6 | ; the middle of the screen. This, to have a correct game under the MS-DOS 7 | ; CHIP-8 emulator. Note that the modifications are quite archaic, as they 8 | ; were hand-made (i.e: no assembler/disassembler). 9 | ; 10 | ; --------------------------------------------------------------------------- 11 | ; 12 | ; From: vervalin@AUSTIN.LOCKHEED.COM (Paul Vervalin) 13 | ; 14 | ; 15 | ; OK folks here it is! PONG for the HP48SX written in CHIP-48. 16 | ; Some things you should know before you start playing are... 17 | ; 1) This is my first attempt at programming in CHIP-48, so I 18 | ; know there are probably a few things that could have been 19 | ; done better. 20 | ; 2) The game never ends. It keeps score, but only up to 9 for 21 | ; each player, then it will roll over to 0. Sorry, its the 22 | ; only way I could think of to do it. So, you have to play 23 | ; whoever gets to a number first, wins. 24 | ; 3) It is kind of slow, but then there are two paddles and ball 25 | ; moving around all at once. 26 | ; 4) The player who got the last point gets the serve... 27 | ; 5) Keys 7 and 4 (on the HP48) control the up and down of the 28 | ; left player and the / and * keys control the up and down of 29 | ; the right player. 30 | ; 31 | ; I think that's about it, so have fun! 32 | ; 33 | ; This is a detailed breakdown of the game, sooooooo, if anybody wants to 34 | ; make it better, or change it in some way, it might be a little easier. 35 | ; Also, about half of the code was in some way extracted from the BRIX 36 | ; program. So, thanks to whoever wrote the original BRIX game. 37 | ; 38 | ; 39 | ; Registers 40 | ; --------- 41 | ; V0-V3 are scratch registers 42 | ; V4 X coord. of score 43 | ; V5 Y coord. of score 44 | ; V6 X coord. of ball 45 | ; V7 Y coord. of ball 46 | ; V8 X direction of ball motion 47 | ; V9 Y direction of ball motion 48 | ; VA X coord. of left player paddle 49 | ; VB Y coord. of left player paddle 50 | ; VC X coord. of right player paddle 51 | ; VD Y coord. of right player paddle 52 | ; VE Score 53 | ; VF collision detection 54 | 55 | 56 | option binary ; To assemble PONG for HP48 use, remove this option 57 | 58 | 59 | CALL Middle ; Draws the vertical bar at center 60 | 61 | LD VB, 12 ; Set left player Y coord. 62 | LD VC, 63 ; Set right player X coord. 63 | LD VD, 12 ; Set right player Y coord. 64 | 65 | LD I, Paddle ; Get address of paddle sprite 66 | DRW VA, VB, 6 ; Draw left paddle 67 | DRW VC, VD, 6 ; Draw right paddle 68 | 69 | LD VE, 0 ; Set score to 00 70 | CALL Draw_Score ; Draw score 71 | 72 | LD V6, 3 ; Set X coord. of ball to 3 73 | LD V8, 2 ; Set ball X direction to right 74 | 75 | 76 | Big_Loop: 77 | 78 | LD V0, #60 ; Set V0=delay before ball launch 79 | LD DT, V0 ; Set delay timer to V0 80 | DT_loop: ; 81 | LD V0, DT ; Read delay timer into V0 82 | SE V0, 0 ; Skip next instruction if V0=0 83 | JP DT_Loop ; Read again delay timer if not 0 84 | 85 | RND V7, 23 ; Set Y coord. to rand # AND 23 (0...23) 86 | ADD V7, 8 ; And adjust it to is 8...31 87 | 88 | LD V9, #FF ; Set ball Y direction to up 89 | LD I, Ball ; Get address of ball sprite 90 | DRW V6, V7, 1 ; Draw ball 91 | 92 | Padl_Loop: 93 | LD I, Paddle ; Get address of paddle sprite 94 | DRW VA, VB, 6 ; Draw left paddle 95 | DRW VC, VD, 6 ; Draw right paddle 96 | 97 | LD V0, 1 ; Set V0 to KEY 1 98 | SKNP V0 ; Skip next instruction if KEY in 1 is not pressed 99 | ADD VB, #FE ; Subtract 2 from Y coord. of left paddle 100 | 101 | LD V0, 4 ; Set V0 to KEY 4 102 | SKNP V0 ; Skip next instruction if KEY in 4 is not pressed 103 | ADD VB, 2 ; Add 2 to Y coord. of left paddle 104 | 105 | LD V0, 31 ; Set V0 to max Y coord. | These three lines are here to 106 | AND VB, V0 ; AND VB with V0 | adjust the paddle position if 107 | DRW VA, VB, 6 ; Draw left paddle | it is out of the screen 108 | 109 | LD V0, #0C ; Set V0 to KEY C 110 | SKNP V0 ; Skip next instruction if KEY in C is not pressed 111 | ADD VD, #FE ; Subtract 2 from Y coord. of right paddle 112 | 113 | LD V0, #0D ; Set V0 to KEY D 114 | SKNP V0 ; Skip next instruction if KEY in D is not pressed 115 | ADD VD, 2 ; Add 2 to Y coord. of right paddle 116 | 117 | LD V0, 31 ; Set V0 to max Y coord. | These three lines are here to 118 | AND VD, V0 ; AND VD with V0 | adjust the paddle position if 119 | DRW VC, VD, 6 ; Draw right paddle | it is out of the screen 120 | 121 | LD I, Ball ; Get address of ball sprite 122 | DRW V6, V7, 1 ; Draw ball 123 | 124 | ADD V6, V8 ; Compute next X coord of the ball 125 | ADD V7, V9 ; Compute next Y coord of the ball 126 | 127 | LD V0, 63 ; Set V0 to max X location 128 | AND V6, V0 ; AND V6 with V0 129 | 130 | LD V1, 31 ; Set V1 to max Y location 131 | AND V7, V1 ; AND V7 with V1 132 | 133 | SNE V6, 0 ; Skip next instruction if ball not at left 134 | JP Left_Side ; 135 | 136 | SNE V6, 63 ; Skip next instruction if ball not at right 137 | JP Right_Side ; 138 | 139 | Ball_Loop: 140 | SNE V7, 31 ; Skip next instruction if ball not at bottom 141 | LD V9, #FF ; Set Y direction to up 142 | 143 | SNE V7, 0 ; Skip next instruction if ball not at top 144 | LD V9, 1 ; Set Y direction to down 145 | 146 | DRW V6, V7, 1 ; Draw ball 147 | JP Padl_loop ; 148 | 149 | Left_Side: 150 | LD V8, 2 ; Set X direction to right 151 | LD V3, 1 ; Set V3 to 1 in case left player misses ball 152 | LD V0, V7 ; Set V0 to V7 Y coord. of ball 153 | SUB V0, VB ; Subtract position of paddle from ball 154 | JP Pad_Coll ; Check for collision 155 | 156 | Right_Side: 157 | LD V8, 254 ; Set X direction to left 158 | LD V3, 10 ; Set V3 to 10 in case right player misses ball 159 | LD V0, V7 ; Set V0 to V7 Y coord. of ball 160 | SUB V0, VD ; Subtract position of paddle from ball 161 | 162 | Pad_Coll: 163 | SE VF, 1 ; Skip next instruction if ball not above paddle 164 | JP Ball_Lost ; 165 | 166 | LD V1, 2 ; Set V1 to 02 167 | SUB V0, V1 ; Subtract V1 from V0 168 | SE VF, 1 ; Skip next instr. if ball not at top of paddle 169 | JP Ball_Top ; Ball at top of paddle 170 | 171 | SUB V0, V1 ; Subtract another 2 from V0 172 | SE VF, 1 ; Skip next instr. if ball not at middle of paddle 173 | JP Pad_Hit ; Ball in middle of paddle 174 | 175 | SUB V0, V1 ; Subtract another 2 from V0 176 | SE VF, 1 ; Skip next instr. if ball not at bottom of paddle 177 | JP Ball_Bot ; Ball at bottom of paddle 178 | 179 | Ball_Lost: 180 | LD V0, 32 ; Set lost ball beep delay 181 | LD ST, V0 ; Beep for lost ball 182 | 183 | CALL Draw_Score ; Erase previous score 184 | ADD VE, V3 ; Add 1 or 10 to score depending on V3 185 | CALL Draw_Score ; Write new score 186 | 187 | LD V6, 62 ; Set ball X coord. to right side 188 | SE V3, 1 ; Skip next instr. if right player got point 189 | LD V6, 3 ; Set ball X coord. to left side 190 | LD V8, #FE ; Set direction to left 191 | SE V3, 1 ; Skip next instr. if right player got point 192 | LD V8, 2 ; Set direction to right 193 | JP Big_Loop ; 194 | 195 | Ball_Top: 196 | ADD V9, #FF ; Subtract 1 from V9, ball Y direction 197 | SNE V9, #FE ; Skip next instr. if V9 != FE (-2) 198 | LD V9, #FF ; Set V9=FF (-1) 199 | JP Pad_Hit 200 | 201 | Ball_Bot: 202 | ADD V9, 1 ; Add 1 to V9, ball Y direction 203 | SNE V9, 2 ; Skip next instr. if V9 != 02 204 | LD V9, 1 ; Set V9=01 205 | 206 | Pad_Hit: 207 | LD V0, 4 ; Set beep for paddle hit 208 | LD ST, V0 ; Sound beep 209 | 210 | ADD V6, 1 ; 211 | SNE V6, 64 ; 212 | ADD V6, 254 ; 213 | 214 | JP Ball_Loop 215 | 216 | Draw_Score: 217 | LD I, Score ; Get address of Score 218 | LD B, VE ; Stores in memory BCD representation of VE 219 | LD V2, [I] ; Reads V0...V2 in memory, so the score 220 | LD F, V1 ; I points to hex char in V1, so the 1st score char 221 | LD V4, #14 ; Set V4 to the X coord. to draw 1st score char 222 | LD V5, 2 ; Set V5 to the Y coord. to draw 1st score char 223 | DRW V4, V5, 5 ; Draw 8*5 sprite at (V4,V5) from M[I], so char V1 224 | ADD V4, #15 ; Set X to the X coord. of 2nd score char 225 | LD F, V2 ; I points to hex char in V2, so 2nd score char 226 | DRW V4, V5, 5 ; Draw 8*5 sprite at (V4,V5) from M[I], so char V2 227 | RET ; Return 228 | 229 | Paddle: 230 | DW #8080 231 | DW #8080 232 | DW #8080 233 | 234 | Ball: 235 | DW #8000 236 | 237 | Score: 238 | DW #0000 239 | DW #0000 240 | 241 | MiddleLine: 242 | DW #C0C0 243 | DW #C000 244 | 245 | HorizLine: 246 | DB #FF 247 | 248 | Middle: 249 | LD VB, 32 ; Set X coord. of middle line pixels 250 | LD VC, 0 ; Set Y coord. of the first sprite to draw 251 | LD I, MiddleLine ; I Points to the bitmap of the 6 pixels to draw 252 | 253 | Draw_Middle: 254 | DRW VB, VC, 4 ; Draw 4 pixels of the line 255 | ADD VC, 4 ; Increments Y of the next 4 pixels sprite 256 | SE VC, 32 ; End loop if last pixels drawn 257 | JP Draw_Middle ; Else draw next pixels 258 | 259 | LD VA, 0 ; Set VA to X location of horizontal lines 260 | LD VB, 0 ; Set VB to Y location of upper horizontal line 261 | LD VC, 31 ; Set VC to Y location of downer horizontal line 262 | LD I, HorizLine ; I points on the bitmap of these lines... 263 | 264 | Draw_Horiz: 265 | DRW VA, VB, 1 ; Draw 8 pixels of the first horizontal line 266 | DRW VA, VC, 1 ; Draw 8 pixels of the second horizontal line 267 | ADD VA, 8 ; Increments Y of the next 8 pixels sprites 268 | SE VA, 64 ; End loop if last pixels drawn 269 | JP Draw_Horiz ; Else draw next pixels of the lines 270 | 271 | LD I, MiddleLine ; I point again on the middle line sprite 272 | LD VA, 0 ; Set player A (left side) X coord. 273 | LD VB, 32 ; Set VB to first 2*1 sprite location of vertical line 274 | DRW VB, VA, 1 ; Redraw this part which wad erased before... 275 | 276 | RET ; Return to program start 277 | ; VA must be set to 0, this has already been done. 278 | -------------------------------------------------------------------------------- /roms/SOURCES/SYZYGY.SRC: -------------------------------------------------------------------------------- 1 | option binary ; Let's compile this for a non-HP computer... 2 | align off ; And let's save some space with even-addresses allowed 3 | 4 | ; From rtrevino@cpocd5.intel.com 5 | ; 6 | ; Several people have requested the source to syzygy, so here it is. 7 | ; Actually it's the listing file. It would have been posted sooner, 8 | ; but I wanted to add *some* comments at least, etc. Hopefully whoever 9 | ; sent mail to me will see it. Anyways, I guess we can all expect to 10 | ; see tons more chip-48 programs posted now, as there is so much interest 11 | ; in source code! :-) They are actually quite easy to write. 12 | ; 13 | ; Roy 14 | ; 15 | ; PS - has anyone used the shift instructions in chip48? The documentation 16 | ; does not correlate with the "opcodes". How do they really work? 17 | 18 | ; 19 | ; SYZYGY is (c) copyright 1990 by Roy Trevino (RTT) 20 | ; 21 | ; Noncommercial distribution allowed, provided that this 22 | ; copyright message is preserved, and any modified versions 23 | ; are clearly marked as such. 24 | ; 25 | ; SYZYGY, via CHIP-48, makes use of undocumented low-level features 26 | ; of the HP48SX calculator, and may or may not cause loss of data, 27 | ; excessive battery drainage, and/or damage to the calculator 28 | ; hardware. The Author takes no responsibility whatsoever for 29 | ; any damage caused by the use of this program. 30 | ; 31 | ; THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 32 | ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 33 | ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34 | ; PURPOSE. 35 | ; 36 | ; 37 | ; Register usage (primary usage, may be others): 38 | ; 39 | ; v0 - scratch 40 | ; v1 - x position of head 41 | ; v2 - y position of head 42 | ; v3 - current direction of head 43 | ; v4 - pointer to segment table entry for head 44 | ; v5 - previous direction of head 45 | ; v6 - x position of tail 46 | ; v7 - y position of tail 47 | ; v8 - direction of tail 48 | ; v9 - pointer to segment table entry for tail 49 | ; va - count of points being added to length 50 | ; vb - x position of target 51 | ; vc - y position of target 52 | ; vd - flags if target is on or off 53 | ; ve - random on time for target 54 | ; vf - carry/borrow/collision detect 55 | 56 | 57 | up = #3 ; (9) key for up 58 | down = #6 ; (6) key for down 59 | left = #7 ; (1) key for left 60 | right = #8 ; (2) key for right 61 | 62 | ; 63 | ; Start of a circular table to track each segment of the syzygy, 64 | ; which consists of a direction and a length. 65 | ; 66 | ; The start of the table is at #800 instead of a label at the bottom 67 | ; of the program (ie. base: end) because it seems to run faster 68 | ; that way. 69 | ; 70 | 71 | base = #800 ; base of segment table 72 | 73 | 74 | jp start 75 | 76 | ; copyright notice 77 | dw #8d8d ; ->-> 78 | dw #20a9 ; (c) 79 | dw #3139 ; 19 80 | dw #3930 ; 90 81 | dw #2052 ; R 82 | dw #5454 ; TT 83 | dw #208e ; <- 84 | dw #8e00 ; <- 85 | start: 86 | call drawbord 87 | call drawtitle 88 | waitkp1: 89 | ld v0,#f ; wait for (+) (keep border) 90 | sknp v0 91 | jp starty 92 | ld v0,#e ; wait for (-) (borderless) 93 | sknp v0 94 | jp startn 95 | jp waitkp1 96 | starty: 97 | call drawtitle ; erase title (keep border) 98 | jp initgame 99 | startn: 100 | cls ; erase everything (borderless) 101 | jp initgame 102 | ; 103 | ; initialization routines 104 | ; 105 | initgame: 106 | ; 107 | ; initial head position near middle of screen 108 | ; 109 | rnd v1,#1f ; x-pos = rnd(16,47) 110 | add v1,#10 111 | rnd v2,#f ; y-pos = rnd(8,23) 112 | add v2,#8 113 | rnd v3,#3 ; direction = rnd(0,3) 114 | ld v5,v3 ; last head direction 115 | ; 116 | ; compute initial tail position 117 | ; 118 | ld v6,v1 ; start out same as head 119 | ld v7,v2 120 | ld v8,v3 ; tail direction 121 | 122 | sne v8,#0 ; up 123 | add v7,#1 124 | sne v8,#1 ; down 125 | add v7,#ff 126 | sne v8,#2 ; left 127 | add v6,#1 128 | sne v8,#3 ; right 129 | add v6,#ff 130 | ; 131 | ; draw initial syzygy, save initial segment to table 132 | ; 133 | ld i,dot 134 | drw v1,v2,#1 ; draw head 135 | drw v6,v7,#1 ; draw tail 136 | 137 | ld v4,#f0 ; init ptr to head vector 138 | ld v9,#f1 ; init ptr to tail vector 139 | 140 | ld i,base ; save direction 141 | add i,v4 142 | ld v0,v3 143 | ld [i],v0 144 | add v4,#1 ; increment head ptr 145 | ld i,base ; save segment count 146 | add i,v4 147 | ld v0,#1 148 | ld [i],v0 149 | 150 | ; 151 | ; compute coordinates and value of first target 152 | ; plus set up flag and time until target 153 | ; 154 | call rndtarg 155 | 156 | 157 | ld va,#0 ; additional length 158 | 159 | ; 160 | ; initial addition to syzygy for test purposes 161 | ; 162 | add va,#0 163 | ; 164 | ; main loop begins here 165 | ; 166 | loop: 167 | ld v0,dt ; check if a target is due 168 | se v0,#0 169 | jp endtarg 170 | se vd,#0 171 | jp targoff 172 | 173 | ld v0,#0 ; draw target 174 | ld f,v0 175 | drw vb,vc,#5 176 | 177 | se vf,#1 ; if on body, erase immediately 178 | jp targon 179 | drw vb,vc,#5 180 | call rndtarg ; set up new target 181 | ld dt,v0 ; no delay though 182 | jp endtarg ; process at least one move 183 | 184 | targon: 185 | ld dt,ve ; set up on-time 186 | ld vd,#1 ; set flag to denote on 187 | ld ve,#0 ; number of points unless hit 188 | jp endtarg 189 | 190 | targoff: 191 | ld v0,ve ; erase old target 192 | ld f,v0 193 | drw vb,vc,#5 194 | 195 | call rndtarg ; set up new target 196 | 197 | endtarg: 198 | ld v0,up ; check for user input 199 | sknp v0 200 | ld v3,#0 ; new direction 201 | 202 | ld v0,down 203 | sknp v0 204 | ld v3,#1 205 | 206 | ld v0,left 207 | sknp v0 208 | ld v3,#2 209 | 210 | ld v0,right 211 | sknp v0 212 | ld v3,#3 213 | ; 214 | ; compute next head position 215 | ; 216 | sne v3,#0 ; up 217 | add v2,#ff 218 | sne v3,#1 ; down 219 | add v2,#1 220 | sne v3,#2 ; left 221 | add v1,#ff 222 | sne v3,#3 ; right 223 | add v1,#1 224 | ; 225 | ; draw next head position 226 | ; 227 | ld i,dot 228 | drw v1,v2,#1 229 | ; 230 | ; check for collision 231 | ; 232 | se vf,#1 233 | jp chkhead 234 | ; 235 | ; if collision is due to target, add points (else die) 236 | ; this also means no doubling back on self 237 | ; 238 | se vd,#1 ; check if target is even on 239 | jp endgame 240 | 241 | ld v0,#3f ; mask off extra x and y bits 242 | and v1,v0 243 | ld v0,#1f 244 | and v2,v0 245 | 246 | ld v0,vb ; check if < target on left 247 | subn v0,v1 248 | se vf,#1 249 | jp endgame 250 | 251 | ld v0,vb ; check if > target on right 252 | add v0,#3 253 | sub v0,v1 254 | se vf,#1 255 | jp endgame 256 | 257 | ld v0,vc ; check if < target on top 258 | subn v0,v2 259 | se vf,#1 260 | jp endgame 261 | 262 | ld v0,vc ; check if > target on bottom 263 | add v0,#4 264 | sub v0,v2 265 | se vf,#1 266 | jp endgame 267 | ; 268 | ; if made it this far, add points, erase target, etc 269 | ; 270 | ld v0,#4 ; beep (actually, a "bip") 271 | ld st,v0 272 | 273 | rnd ve,#7 ; award rnd(2,9) points 274 | add ve,#2 ; 275 | add va,ve ; add points 276 | 277 | ld i,dot ; temporarily erase head 278 | drw v1,v2,#1 279 | ld v0,#0 ; erase target 280 | ld f,v0 281 | drw vb,vc,#5 282 | ld v0,ve ; draw points instead 283 | ld f,v0 284 | drw vb,vc,#5 285 | 286 | ld v0,#30 ; delay for a while 287 | ld dt,v0 288 | targwait: 289 | ld v0,dt 290 | se v0,#0 291 | jp targwait 292 | 293 | ld i,dot 294 | drw v1,v2,#1 ; redraw head 295 | ; 296 | ; if direction changed, create a new segment record 297 | ; 298 | chkhead: 299 | sne v3,v5 300 | jp conthead 301 | 302 | add v4,#1 ; new segment record 303 | ld i,base 304 | add i,v4 305 | ld v0,v3 ; save direction 306 | ld [i],v0 307 | add v4,#1 ; point to counter 308 | ld i,base ; initialize segment count to 309 | add i,v4 310 | ld v0,#0 311 | ld [i],v0 312 | 313 | ld v5,v3 ; reset previous direction 314 | 315 | conthead: 316 | ld i,base ; simply add to current record 317 | add i,v4 318 | ld v0,[i] 319 | add v0,#1 ; increment head count 320 | ld [i],v0 321 | ; 322 | ; don't erase tail if adding points to length 323 | ; 324 | sne va,#0 325 | jp contpts ; if pts = 0, continue normally 326 | 327 | ld v0,#c ; delay just a little to compensate 328 | delhead: 329 | add v0,#ff 330 | se v0,#0 331 | jp delhead 332 | 333 | add va,#ff ; decrement and loop 334 | jp loop 335 | 336 | contpts: 337 | ; 338 | ; erase last tail position 339 | ; 340 | ld i,dot 341 | drw v6,v7,#1 342 | 343 | ; 344 | ; compute next tail position 345 | ; 346 | sne v8,#0 ; up 347 | add v7,#ff 348 | sne v8,#1 ; down 349 | add v7,#1 350 | sne v8,#2 ; left 351 | add v6,#ff 352 | sne v8,#3 ; right 353 | add v6,#1 354 | 355 | ld i,base ; get tail segment record 356 | add i,v9 357 | ld v0,[i] 358 | add v0,#ff ; decrement tail count 359 | ld [i],v0 ; save 360 | se v0,#0 ; if zero, get new record 361 | jp loop 362 | 363 | add v9,#1 ; new segment record 364 | ld i,base ; get new direction 365 | add i,v9 366 | ld v0,[i] 367 | ld v8,v0 368 | add v9,#1 ; point to new count 369 | ; 370 | ; end of main loop 371 | ; 372 | jp loop 373 | ; 374 | ; endgame routines 375 | ; 376 | endgame: 377 | ld v0,#d ; beep 378 | ld st,v0 379 | 380 | ld v0,#b ; wait for (space) keypress 381 | endkp: 382 | skp v0 383 | jp endkp 384 | ; 385 | ; finish up tail to count points: digits are in vd:vc:vb format 386 | ; note that it is theoretically possible to get 64*32=2048 points, 387 | ; while three digits will only hold 999. Unlikely but possible. 388 | ; 389 | ld vb,#1 ; one's digit 390 | ld vc,#0 ; ten's digit 391 | ld vd,#0 ; hundred's digit 392 | 393 | endtail: 394 | ; 395 | ; increment score 396 | ; 397 | add vb,#1 398 | se vb,#a 399 | jp endtailcont 400 | ld vb,#0 401 | add vc,#1 402 | se vc,#a 403 | jp endtailcont 404 | ld vc,#0 405 | add vd,#1 406 | ; 407 | ; compute next tail position to add up score 408 | ; 409 | endtailcont: 410 | ld i,dot ; erase last tail position 411 | drw v6,v7,#1 412 | 413 | sne v8,#0 ; up 414 | add v7,#ff 415 | sne v8,#1 ; down 416 | add v7,#1 417 | sne v8,#2 ; left 418 | add v6,#ff 419 | sne v8,#3 ; right 420 | add v6,#1 421 | 422 | ld i,base ; get tail segment record 423 | add i,v9 424 | ld v0,[i] 425 | add v0,#ff ; decrement tail count 426 | ld [i],v0 ; save 427 | se v0,#0 ; if zero, get new record 428 | jp endtail 429 | 430 | sne v9,v4 ; done when pointers are equal 431 | jp drawscore 432 | 433 | add v9,#1 ; new segment record 434 | ld i,base ; get new direction 435 | add i,v9 436 | ld v0,[i] 437 | ld v8,v0 438 | add v9,#1 ; point to new count 439 | jp endtail 440 | ; 441 | ; draw score 442 | ; 443 | drawscore: 444 | cls 445 | ld v6,#11 ; draw border 446 | ld v7,#9 447 | ld v8,#2f 448 | ld v9,#17 449 | ld i,vbar 450 | drw v6,v7,#e 451 | drw v8,v7,#e 452 | add v7,#ff 453 | ld i,hbar 454 | drw v6,v7,#1 455 | drw v6,v9,#1 456 | add v6,#8 457 | drw v6,v7,#1 458 | drw v6,v9,#1 459 | add v6,#8 460 | drw v6,v7,#1 461 | drw v6,v9,#1 462 | add v6,#8 463 | ld i,hbar2 464 | drw v6,v7,#1 465 | drw v6,v9,#1 466 | 467 | ld i,sc ; show score (not high score yet) 468 | ld v6,#13 469 | ld v7,#11 470 | call showscore 471 | ; 472 | ; figure out if it's the high score, save it if it is 473 | ; 474 | ld i,high_score ; recover old high score into v3v2v1 475 | ld v3,[i] 476 | 477 | sne v3,vd ; if =, check next digit 478 | jp conthigh1 479 | ld v0,v3 ; if borrow, it's a new high score! 480 | sub v0,vd 481 | se vf,#1 482 | jp savehigh 483 | jp drawhigh 484 | 485 | conthigh1: 486 | sne v2,vc ; etc. as above for other digits 487 | jp conthigh2 488 | ld v0,v2 489 | sub v0,vc 490 | se vf,#1 491 | jp savehigh 492 | jp drawhigh 493 | 494 | conthigh2: 495 | ld v0,v1 496 | sub v0,vb 497 | se vf,#0 498 | jp drawhigh 499 | 500 | savehigh: 501 | ld i,high_score 502 | ld v3,vd ; save new high score 503 | ld v2,vc 504 | ld v1,vb 505 | ld [i],v3 506 | ; 507 | ; draw the high score 508 | ; 509 | drawhigh: 510 | ld i,high_score 511 | ld v3,[i] 512 | ld v6,#13 513 | add v7,#f9 514 | ld vd,v3 515 | ld vc,v2 516 | ld vb,v1 517 | ld i,hi 518 | call showscore 519 | ; 520 | ; random memory wasting stuff goes here 521 | ; 522 | waitkp2: 523 | 524 | rnd v1,#3f ; get random position 525 | rnd v2,#1f 526 | 527 | ld v0,#d ; check left 528 | sub v0,v1 529 | se vf,#0 530 | jp drawrand 531 | 532 | ld v0,#30 ; check right 533 | subn v0,v1 534 | se vf,#0 535 | jp drawrand 536 | 537 | ld v0,#3 ; check top 538 | sub v0,v2 539 | se vf,#0 540 | jp drawrand 541 | 542 | ld v0,#18 ; check bottom 543 | subn v0,v2 544 | se vf,#0 545 | jp drawrand 546 | jp chkkp2 547 | 548 | drawrand: 549 | rnd v3,#0f ; draw random number 550 | ld f,v3 551 | drw v1,v2,#5 552 | 553 | chkkp2: 554 | ld v0,#f ; check for keypress 555 | sknp v0 556 | jp conty 557 | ld v0,#e 558 | sknp v0 559 | jp contn 560 | jp waitkp2 561 | 562 | conty: 563 | cls 564 | call drawbord 565 | jp initgame 566 | contn: 567 | cls 568 | jp initgame 569 | ; 570 | ; function showscore: 571 | ; digits in vd:vc:vb, descriptor in i, initial coords in v6,v7 572 | ; 573 | showscore: 574 | drw v6,v7,#5 575 | ld i,col 576 | add v6,#2 577 | drw v6,v7,#4 578 | ld f,vd 579 | add v6,#a 580 | drw v6,v7,#5 581 | ld f,vc 582 | add v6,#5 583 | drw v6,v7,#5 584 | ld f,vb 585 | add v6,#5 586 | drw v6,v7,#5 587 | 588 | ret 589 | ; 590 | ; function drawbord: 591 | ; draw border, try to do it fast 592 | ; 593 | drawbord: 594 | ld i,hbar 595 | ld v1,#0 ; left 596 | ld v2,#0 ; right 597 | ld v6,#1f ; lower 598 | horiz1: 599 | drw v1,v2,#1 ; draw x,0 600 | drw v1,v6,#1 ; draw x,31 601 | add v1,#8 602 | se v1,#40 ; same as 0 603 | jp horiz1 604 | 605 | ld i,vbar 606 | ld v2,#1 607 | ld v5,#3f 608 | drw v1,v2,#f 609 | drw v5,v2,#f 610 | add v2,#f 611 | drw v1,v2,#f 612 | drw v5,v2,#f 613 | 614 | ret 615 | ; 616 | ; function drawtitle: draws game title 617 | ; 618 | drawtitle: 619 | ld v1,#c 620 | ld v2,#7 621 | ld i,Title_s 622 | drw v1,v2,#a 623 | ld i,Title_y 624 | add v1,#6 625 | drw v1,v2,#a 626 | ld i,Title_z 627 | add v1,#6 628 | drw v1,v2,#a 629 | ld i,Title_y 630 | add v1,#6 631 | drw v1,v2,#a 632 | ld i,Title_g 633 | add v1,#6 634 | drw v1,v2,#a 635 | ld i,Title_y 636 | add v1,#6 637 | drw v1,v2,#a 638 | 639 | ld v1,#e 640 | ld v2,#18 641 | ld i,Title_v 642 | drw v1,v2,#3 643 | ld i,vers 644 | add v1,#8 645 | add v2,#ff 646 | drw v1,v2,#4 647 | add v1,#9 648 | add v2,#fe 649 | ld i,Title_r 650 | drw v1,v2,#6 651 | add v1,#6 652 | add v2,#1 653 | ld i,Title_tt 654 | drw v1,v2,#5 655 | 656 | ret 657 | ; 658 | ; function rndtarg: 659 | ; returns coords as (vb,vc) 660 | ; 0 in vd 661 | ; time until target in dt 662 | ; on-time value ve 663 | ; 664 | rndtarg: 665 | ; 666 | ; x-pos = rnd(1,59) 667 | ; 668 | ld vd,#c5 ; -#3b (-59d) 669 | rndx: rnd vb,#3f ; rnd (0,63) 670 | ld ve,vb 671 | add ve,vd ; check if > 58 672 | sne vf,#1 673 | jp rndx ; try again if too big 674 | 675 | add vb,#1 676 | ; 677 | ; y-pos = rnd(1,26) 678 | ; 679 | 680 | ld vd,#e6 ; -#1a (-26d) 681 | rndy: rnd vc,#1f 682 | ld ve,vc 683 | add ve,vd 684 | sne vf,#1 685 | jp rndy 686 | add vc,#1 687 | ld vd,#0 ; flag marking new target 688 | rnd ve,#3f ; random off delay (64 - 127) 689 | add ve,#40 690 | ld dt,ve 691 | rnd ve,#3f ; random on delay (64 - 127) 692 | add ve,#40 693 | ret 694 | 695 | dot: dw #8000 ; dot for syzygy 696 | hbar: dw #ff00 ; horizontal border segment 697 | hbar2: dw #fe00 698 | vbar: dw #8080 ; vertical border segment 699 | dw #8080 700 | dw #8080 701 | dw #8080 702 | dw #8080 703 | dw #8080 704 | dw #8080 705 | dw #8080 706 | ; 707 | ; True memory wasting stuff goes here (but why not?) 708 | ; 709 | Title_s: ; s character 710 | db $...11111 711 | db $...1.... 712 | db $...1.... 713 | db $...1.... 714 | db $...11111 715 | db $.......1 716 | db $.......1 717 | db $.......1 718 | db $.......1 719 | db $...11111 720 | 721 | Title_y: ; y character 722 | db $...1...1 723 | db $...1...1 724 | db $...1...1 725 | db $...1...1 726 | db $...11111 727 | db $.....1.. 728 | db $.....1.. 729 | db $.....1.. 730 | db $.....1.. 731 | db $.....1.. 732 | 733 | Title_z: ; z character 734 | db $...11111 735 | db $.......1 736 | db $......1. 737 | db $......1. 738 | db $.....1.. 739 | db $.....1.. 740 | db $....1... 741 | db $....1... 742 | db $...1.... 743 | db $...11111 744 | 745 | Title_g: ; g character 746 | db $...11111 747 | db $...1...1 748 | db $...1.... 749 | db $...1.... 750 | db $...1.... 751 | db $...1..11 752 | db $...1...1 753 | db $...1...1 754 | db $...1...1 755 | db $...11111 756 | 757 | Title_v: ; v character for version 758 | db $.....1.1 759 | db $.....1.1 760 | db $......1. 761 | db $........ 762 | 763 | vers: ; version number characters 764 | db $.111...1 765 | db $.1.1...1 766 | db $.1.1...1 767 | db $.111.1.1 768 | 769 | 770 | Title_r: ; R character for signature 771 | db $....11.. 772 | db $...1..1. 773 | db $...1111. 774 | db $...1.1.. 775 | db $...1..1. 776 | db $....1..1 777 | 778 | Title_tt: ; tt characters for signature 779 | db $...1.1.. 780 | db $..11111. 781 | db $...1.1.1 782 | db $...1.1.1 783 | db $..1.1.1. 784 | db $........ 785 | 786 | 787 | sc: ; sc characters for score 788 | db $.111.111 789 | db $.1...1.. 790 | db $..1..1.. 791 | db $...1.1.. 792 | db $.111.111 793 | db $........ 794 | 795 | hi: ; hi character for high score 796 | db $.1.1.111 797 | db $.1.1..1. 798 | db $.111..1. 799 | db $.1.1..1. 800 | db $.1.1.111 801 | db $........ 802 | 803 | col: dw #0001 ; : character for scores 804 | dw #0001 805 | 806 | high_score: 807 | dw #0000 ; high score storage 808 | dw #0000 809 | -------------------------------------------------------------------------------- /roms/SOURCES/UFO.SRC: -------------------------------------------------------------------------------- 1 | option binary 2 | align off 3 | 4 | LD I, l2CD 5 | LD V9, #38 6 | LD VA, #08 7 | DRW V9, VA, 3 8 | LD I, l2D0 9 | LD VB, #00 10 | LD VC, #03 11 | DRW VB, VC, 3 12 | LD I, l2D6 13 | LD V4, #1D 14 | LD V5, #1F 15 | DRW V4, V5, 1 16 | LD V7, #00 17 | LD V8, #0F 18 | CALL l2A2 19 | l21E: CALL l2AC 20 | SNE V8, #00 21 | l222: JP l222 22 | LD V4, #1E 23 | LD V5, #1C 24 | LD I, l2D3 25 | DRW V4, V5, 3 26 | LD VE, #00 27 | l22E: LD V6, #80 28 | LD VD, #04 29 | SKNP VD 30 | LD V6, #FF 31 | LD VD, #05 32 | SKNP VD 33 | LD V6, #00 34 | LD VD, #06 35 | SKNP VD 36 | LD V6, #01 37 | SE V6, #80 38 | CALL l2D8 39 | l246: LD I, l2D0 40 | DRW VB, VC, 3 41 | RND VD, #01 42 | ADD VB, VD 43 | DRW VB, VC, 3 44 | SE VF, #00 45 | JP l292 46 | LD I, l2CD 47 | DRW V9, VA, 3 48 | RND VD, #01 49 | SE VD, #00 50 | LD VD, #FF 51 | ADD V9, #FE 52 | DRW V9, VA, 3 53 | SE VF, #00 54 | JP l28C 55 | SNE VE, #00 56 | JP l22E 57 | LD I, l2D3 58 | DRW V4, V5, 3 59 | SNE V5, #00 60 | JP l286 61 | ADD V5, #FF 62 | ADD V4, V6 63 | DRW V4, V5, 3 64 | SE VF, #01 65 | JP l246 66 | LD VD, #08 67 | AND VD, V5 68 | SNE VD, #08 69 | JP l28C 70 | JP l292 71 | l286: CALL l2AC 72 | ADD V8, #FF 73 | JP l21E 74 | l28C: CALL l2A2 75 | ADD V7, #05 76 | JP l296 77 | l292: CALL l2A2 78 | ADD V7, #0F 79 | l296: CALL l2A2 80 | LD VD, #03 81 | LD ST, VD 82 | LD I, l2D3 83 | DRW V4, V5, 3 84 | JP l286 85 | l2A2: DW #A2F8 ;LD I, l2F8 as we cannot load an effective address 86 | LD B, V7 87 | LD V3, #00 88 | CALL l2B6 89 | RET 90 | l2AC: DW #A2F8 ;LD I, l2F8 as we cannot load an effective address 91 | LD B, V8 92 | LD V3, #32 93 | CALL l2B6 94 | RET 95 | l2B6: LD VD, #1B 96 | LD V2, [I] 97 | LD F, V0 98 | DRW V3, VD, 5 99 | ADD V3, #05 100 | LD F, V1 101 | DRW V3, VD, 5 102 | ADD V3, #05 103 | LD F, V2 104 | DRW V3, VD, 5 105 | RET 106 | DB #01 107 | l2CD: DB #7C ; .11111.. 108 | DB #FE ; 1111111. 109 | DB #7C ; .11111.. 110 | l2D0: 111 | DB #60 ;.11..... 112 | DB #F0 ;1111.... 113 | DB #60 ;.11..... 114 | 115 | l2D3: DB #40 ;.1...... 116 | DB #E0 ;111..... 117 | DB #A0 ;1.1..... 118 | 119 | l2D6: DB #F8 ;11111... 120 | DB #D4 ;11.1.1.. 121 | l2D8: LD VE, #01 122 | LD VD, #10 123 | LD ST, VD 124 | RET 125 | -------------------------------------------------------------------------------- /roms/SOURCES/VBRIX.SRC: -------------------------------------------------------------------------------- 1 | ; **************************************************************************** 2 | ; **************************************************************************** 3 | ; *** Vertical Brix v1.0 (C) Paul Robson 1996 *** 4 | ; **************************************************************************** 5 | ; **************************************************************************** 6 | 7 | ; **************************************************************************** 8 | ; 9 | ; r7 lives 10 | ; r8 score 11 | ; r9 bat y 12 | ; ra,rb location of ball 13 | ; rc,rd direction of ball 14 | ; re Number of brix remaining in wall 15 | ; 16 | ; **************************************************************************** 17 | 18 | TopLine:equ 0 ; top line of breakout 19 | BottomLine:equ 31 ; bottom line of breakout 20 | LeftSide:equ 0 ; left side of game area 21 | RightSide:equ 63 ; right side of game area 22 | BrickX:equ 34 ; brick start 23 | BrickXCt:equ 7 ; number of bricks across , x 24 | BrickYCt:equ 10 ; and y 25 | BatX: equ 2 ; bat x position 26 | Sound: equ 1 ; 1 sound,0 nosound 27 | KeyUp: equ 1 ; up key 28 | KeyDown:equ 4 ; down key 29 | KeyStart:equ 7 ; start key 30 | 31 | cls 32 | jsr Title 33 | wstart: 34 | mov v0,KeyStart ; wait for start 35 | skpr v0 36 | jmp wstart 37 | 38 | begin: mov r8,0 ; score = 0 39 | mov r7,3 ; lives = 3 40 | jsr DrawBorder 41 | jsr InitBat 42 | jsr InitBall 43 | jsr DrawBricks 44 | jsr DrawScore 45 | jsr DrawLives 46 | key v0 47 | loop: jsr MoveBat 48 | jsr MoveBat 49 | jsr MoveBall 50 | jsr Collide 51 | skeq ra,0 52 | jmp loop 53 | 54 | mov rc,1 ; ball back out 55 | jsr DrawLives ; dec lives 56 | add r7,-1 57 | jsr DrawLives 58 | 59 | mov r0,120 ; wait 2 secs 60 | sdelay r0 61 | wait: gdelay r0 62 | skeq r0,0 63 | jmp wait 64 | 65 | skeq r7,0 66 | jmp loop 67 | jsr DrawLives ; erase lives,we've finished 68 | 69 | mov r0,KeyStart 70 | skpr r0 71 | jmp .-2 72 | jmp begin 73 | halt 74 | 75 | ; **************************************************************************** 76 | ; *** initialise the bat *** 77 | ; **************************************************************************** 78 | InitBat:mov r9,16 79 | mov v0,BatX 80 | mvi BatSpr 81 | sprite v0,v9,5 82 | rts 83 | BatSpr: db $10000000 84 | db $10000000 85 | db $10000000 86 | db $10000000 87 | db $10000000 88 | ; **************************************************************************** 89 | ; *** move the bat *** 90 | ; **************************************************************************** 91 | MoveBat:mov r0,KeyUp 92 | skup r0 93 | jmp MoveUp 94 | mov r0,KeyDown 95 | skup r0 96 | jmp MoveDown 97 | rts 98 | 99 | MoveUp: mov r0,r9 ; move it up 100 | add r0,-1 101 | skne r0,TopLine 102 | rts 103 | jmp MoveIt 104 | MoveDown: 105 | mov r0,r9 ; move it down 106 | add r0,1 107 | skne r0,BottomLine-4 108 | rts 109 | jmp MoveIt 110 | MoveIt: mov r1,BatX ; redraw the graphic 111 | mvi BatSpr 112 | sprite r1,r9,5 113 | sprite r1,r0,5 114 | mov r9,r0 ; do the move 115 | rts 116 | 117 | ; **************************************************************************** 118 | ; *** has the bat hit the ball *** 119 | ; **************************************************************************** 120 | Collide:mov v0,va ; va (x) must be batx 121 | add v0,-2 122 | skeq v0,0 123 | rts 124 | mov v0,vb ; v0 = bally-baty 125 | sub v0,v9 126 | skne vf,0 ; if bally < baty exit 127 | rts 128 | mov v1,v0 ; if v0 >= 5 exit 129 | mov v2,5 130 | sub v1,v2 131 | skeq vf,0 132 | rts 133 | mvi dirtab ; get the new y direction 134 | adi v0 ; out of the table 135 | ldr v0-v0 136 | mov vd,v0 137 | 138 | skne vb,TopLine+1 139 | mov vd,1 140 | skne vb,BottomLine-1 141 | mov vd,-1 142 | 143 | mov rc,1 ; bounce back out 144 | mov r0,10*sound 145 | ssound r0 146 | rts 147 | dirtab: db -1,-1,0,1,1 148 | ; **************************************************************************** 149 | ; *** initialise the ball register *** 150 | ; **************************************************************************** 151 | InitBall: 152 | random vb,BottomLine-TopLine-1 153 | add rb,TopLine+1 154 | mov va,4 155 | mov vc,1 156 | mov vd,1 157 | mvi Pixel 158 | sprite va,vb,1 159 | rts 160 | ; **************************************************************************** 161 | ; *** move the ball,bouncing off the walls *** 162 | ; *** destroys v0,v1,v2,v3,v4 *** 163 | ; **************************************************************************** 164 | MoveBall: 165 | mov v0,va ; save position in va,vb 166 | mov v1,vb 167 | add va,vc ; work out new position 168 | add vb,vd 169 | mvi Pixel 170 | skne vb,TopLine+1 ; bounce off the walls 171 | mov vd,1 172 | skne vb,BottomLine-1 173 | mov vd,-1 174 | skne va,RightSide-1 175 | mov vc,-1 176 | 177 | skne va,0 ; DEBUGGING,NO LOSS OF BALL 178 | mov vc,1 179 | 180 | sprite v0,v1,1 ; Draw the ball,delete old ball 181 | sprite va,vb,1 182 | skne vf,0 ; ball has hit something - stop 183 | rts 184 | mov v0,va ; if hit the bat,pass ! 185 | mov v1,brickx-1 ; if < brickx forget it ! 186 | sub v0,v1 187 | skne vf,0 188 | rts 189 | mov v0,va ; ball position in v0,v1 190 | mov v1,vb 191 | add v0,-brickx ; convert to ball coordinate 192 | add v1,-topline-1 193 | mov v2,-1 ; v2,v3 will be the ball location 194 | mov v3,-1 ; in logical coordinates. 195 | mov v4,3 196 | div3x: add v2,1 ; divide v0 by 3 197 | sub v0,v4 198 | skeq vf,0 199 | jmp div3x 200 | div3y: add v3,1 201 | sub v1,v4 202 | skeq vf,0 203 | jmp div3y 204 | mov v0,v2 ; v0,v1 contain the ball coords (log) 205 | mov v1,v3 206 | add v0,v2 ; convert them to physical coords 207 | add r0,r2 208 | add v1,v3 209 | add v1,v3 210 | add v0,BrickX 211 | add v1,TopLine+1 212 | mvi Brick ; erase the brick 213 | sprite v0,v1,3 214 | add ve,-1 ; decrement bricks remaining counter 215 | mov v0,0 ; bounce the ball 216 | rsb vc,v0 ; xi = -xi 217 | mov r0,2*sound 218 | ssound r0 219 | jsr DrawScore ; increment the score 220 | add v8,1 221 | jsr DrawScore 222 | skeq ve,0 ; cleared the wall ? 223 | rts 224 | jsr DrawBricks ; redraw it 225 | rts 226 | 227 | ; **************************************************************************** 228 | ; *** Draw the border *** 229 | ; *** destroys r0,r1,r2,i *** 230 | ; **************************************************************************** 231 | DrawBorder: 232 | cls ; start with a clear screen 233 | mov v0,LeftSide ; (r0,r1) and (r0,r2) are start pos 234 | mov v1,TopLine ; of the horizontal lines 235 | mov v2,BottomLine 236 | mvi Pixel 237 | DBLoop: sprite v0,v1,1 ; draw the vertical lines 238 | sprite v0,v2,1 239 | add v0,1 240 | skeq v0,RightSide 241 | jmp DBLoop 242 | DBLoop2:sprite v0,v1,1 ; draw the horizontal lines 243 | add v1,1 244 | skeq v1,BottomLine+1 245 | jmp DBLoop2 246 | rts 247 | Pixel: db $10000000 ; pixel used for drawing walls. 248 | ; **************************************************************************** 249 | ; *** redraw all the bricks *** 250 | ; *** destroys r0,r1,r2,r3,i *** 251 | ; **************************************************************************** 252 | DrawBricks: 253 | mov v1,TopLine+1 254 | mov v3,BrickYCt 255 | mvi Brick 256 | DBXLoop:mov v0,BrickX 257 | mov v2,BrickXCt 258 | DBXLp2: sprite v0,v1,3 259 | add v0,3 260 | add v2,-1 261 | skeq v2,0 262 | jmp DBXLp2 263 | add v1,3 264 | add v3,-1 265 | skeq v3,0 266 | jmp DBXLoop 267 | mov ve,BrickXCt*BrickYCt 268 | rts 269 | Brick: db $11100000 270 | db $10100000 271 | db $11100000 272 | ; **************************************************************************** 273 | ; *** Draw the score (in r8) *** 274 | ; **************************************************************************** 275 | DrawScore: 276 | mvi Temp 277 | bcd v8 278 | ldr v0-v2 279 | mov v3,3 280 | mov v4,TopLine+2 281 | font v0 282 | sprite v3,v4,5 283 | add v3,5 284 | font v1 285 | sprite v3,v4,5 286 | add v3,5 287 | font v2 288 | sprite v3,v4,5 289 | rts 290 | Temp: dw 0,0,0 291 | ; **************************************************************************** 292 | ; *** draw the number of lives *** 293 | ; **************************************************************************** 294 | DrawLives: 295 | mov r0,20 296 | mov r1,TopLine+2 297 | font r7 298 | sprite r0,r1,5 299 | rts 300 | ; **************************************************************************** 301 | ; *** draw the title *** 302 | ; **************************************************************************** 303 | Title: mov r0,10 304 | mov r1,12 305 | mov r2,9 306 | mov r3,5 307 | mvi TitleSpr 308 | TtlLoop:sprite r0,r1,5 309 | adi r3 310 | add r0,5 311 | add r2,-1 312 | skeq r2,0 313 | jmp TtlLoop 314 | rts 315 | TitleSpr: 316 | db $10010000 317 | db $10010000 318 | db $10010000 319 | db $10010000 320 | db $01100000 321 | 322 | db $11100000 323 | db $10010000 324 | db $11100000 325 | db $10010000 326 | db $11100000 327 | 328 | db $11100000 329 | db $10010000 330 | db $11100000 331 | db $10010000 332 | db $10010000 333 | 334 | 335 | db $00100000 336 | db $00100000 337 | db $00100000 338 | db $00100000 339 | db $00100000 340 | 341 | db $10010000 342 | db $10010000 343 | db $01100000 344 | db $10010000 345 | db $10010000 346 | 347 | db $00000000 348 | db $00000000 349 | db $01100000 350 | db $00000000 351 | db $00000000 352 | 353 | db $11110000 354 | db $10010000 355 | db $11110000 356 | db $10000000 357 | db $10000000 358 | 359 | db $11110000 360 | db $10000000 361 | db $11110000 362 | db $00010000 363 | db $11110000 364 | 365 | db $11100000 366 | db $10010000 367 | db $11100000 368 | db $10010000 369 | db $10010000 370 | 371 | 372 | -------------------------------------------------------------------------------- /roms/SPACEF.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/SPACEF.ch8 -------------------------------------------------------------------------------- /roms/SQUASH.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/SQUASH.ch8 -------------------------------------------------------------------------------- /roms/SYZYGY.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/SYZYGY.ch8 -------------------------------------------------------------------------------- /roms/TANK.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TANK.ch8 -------------------------------------------------------------------------------- /roms/TEST/C8PIC.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TEST/C8PIC.ch8 -------------------------------------------------------------------------------- /roms/TEST/IBM.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TEST/IBM.ch8 -------------------------------------------------------------------------------- /roms/TEST/Rocket2.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TEST/Rocket2.ch8 -------------------------------------------------------------------------------- /roms/TEST/TAPEWORM.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TEST/TAPEWORM.ch8 -------------------------------------------------------------------------------- /roms/TEST/TIMEBOMB.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TEST/TIMEBOMB.ch8 -------------------------------------------------------------------------------- /roms/TEST/X-MIRROR.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TEST/X-MIRROR.ch8 -------------------------------------------------------------------------------- /roms/TETRIS.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TETRIS.ch8 -------------------------------------------------------------------------------- /roms/TICTAC.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TICTAC.ch8 -------------------------------------------------------------------------------- /roms/TRON.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/TRON.ch8 -------------------------------------------------------------------------------- /roms/UFO.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/UFO.ch8 -------------------------------------------------------------------------------- /roms/VBRIX.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/VBRIX.ch8 -------------------------------------------------------------------------------- /roms/VERS.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/VERS.ch8 -------------------------------------------------------------------------------- /roms/WALL.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/WALL.ch8 -------------------------------------------------------------------------------- /roms/WIPEOFF.ch8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f0lg0/CHIP-8/88aca7cfa643b76c04989d1fe31b84effad79f12/roms/WIPEOFF.ch8 -------------------------------------------------------------------------------- /src/chip8.c: -------------------------------------------------------------------------------- 1 | #include "chip8.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define debug_print(fmt, ...) \ 11 | do { \ 12 | if (DEBUG) fprintf(stderr, fmt, __VA_ARGS__); \ 13 | } while (0) 14 | 15 | int DEBUG = 1; 16 | extern int errno; 17 | 18 | /* 19 | * Memory map: 20 | * 21 | * Total: 4096 bytes (4K) 22 | * 23 | * 0x000 - 0x1FF INTERPRETER 24 | * 0x200 - 0xFFF Program/Data space 25 | * 26 | * NOTE: 27 | * opcodes are stored big-endian! 28 | * 29 | * */ 30 | 31 | /* 32 | ========================================================== 33 | # CHIP-8 architecture 34 | ========================================================== 35 | */ 36 | 37 | // Font set 38 | unsigned char fontset[80] = { 39 | 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 40 | 0x20, 0x60, 0x20, 0x20, 0x70, // 1 41 | 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 42 | 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 43 | 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 44 | 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 45 | 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 46 | 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 47 | 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 48 | 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 49 | 0xF0, 0x90, 0xF0, 0x90, 0x90, // A 50 | 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B 51 | 0xF0, 0x80, 0x80, 0x80, 0xF0, // C 52 | 0xE0, 0x90, 0x90, 0x90, 0xE0, // D 53 | 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E 54 | 0xF0, 0x80, 0xF0, 0x80, 0x80 // F 55 | }; 56 | 57 | // Memory 58 | unsigned char memory[4096] = {0}; 59 | 60 | /* 61 | * Registers: 62 | * 16 general purpose 8-bit registers, usually referred to as Vx 63 | * where x is a hexadecimal digit. 64 | * 65 | * a char is 8-bits, so we store 16 of them 66 | * */ 67 | unsigned char V[16] = {0}; 68 | 69 | /* 70 | * Special 16-bit register called I 71 | * It is used to store memory addresses. 72 | * 73 | * a short is 16-bits 74 | * */ 75 | unsigned short I = 0; 76 | 77 | /* 78 | * Pseudo-register: PC 79 | * The program counter is a 16-bit pseudo register used to 80 | * store the currectly executing address 81 | * */ 82 | unsigned short pc = 0x200; 83 | 84 | /* 85 | * Pseudo-register: SP 86 | * The stack pointer register is used to point to the topmost level of the stack 87 | * 88 | * It is a 8-bit register 89 | * */ 90 | unsigned char sp = 0; 91 | 92 | /* 93 | * The Stack: 94 | * Array of 16 16-bit values, used to store the address that the interpreter 95 | * should return to when finished with a subroutine 96 | * */ 97 | unsigned short stack[16] = {0}; 98 | 99 | // Keypad 100 | unsigned char keypad[16] = {0}; 101 | 102 | /* 103 | * The Display: 104 | * A 64x32 px monochrome display 105 | * */ 106 | unsigned char display[64 * 32] = {0}; 107 | 108 | // Delay Timer 109 | unsigned char dt = 0; 110 | 111 | // Sound Timer 112 | unsigned char st = 0; 113 | 114 | // Update display flag 115 | unsigned char draw_flag = 0; 116 | 117 | // Play a sound flag 118 | unsigned char sound_flag = 0; 119 | 120 | /* 121 | ========================================================== 122 | # CHIP-8 logic 123 | ========================================================== 124 | */ 125 | 126 | /** 127 | * init_cpu: Initialize CPU by loading fontset into mem 128 | * @param void 129 | * @return void 130 | * */ 131 | void init_cpu(void) { 132 | srand((unsigned int)time(NULL)); 133 | 134 | // load fonts into memory 135 | memcpy(memory, fontset, sizeof(fontset)); 136 | } 137 | 138 | /** 139 | * load_rom: load the provided rom to memory 140 | * @param filename The rom filename 141 | * @return 0 if success, -1 if fread failure, errno if failure 142 | * */ 143 | int load_rom(char* filename) { 144 | FILE* fp = fopen(filename, "rb"); 145 | 146 | if (fp == NULL) return errno; 147 | 148 | struct stat st; 149 | stat(filename, &st); 150 | size_t fsize = st.st_size; 151 | 152 | size_t bytes_read = fread(memory + 0x200, 1, sizeof(memory) - 0x200, fp); 153 | 154 | fclose(fp); 155 | 156 | if (bytes_read != fsize) { 157 | return -1; 158 | } 159 | 160 | return 0; 161 | } 162 | 163 | /** 164 | * emulate_cycle: run chip-8 instructions 165 | * @param void 166 | * @return void 167 | * 168 | * 1) Fetch the operation code 169 | * - fetch one opcode from the memory at the location specified by the 170 | * program counter. Each array address contains one byte, an opcode is 2 bytes 171 | * long so we need to fetch 2 consecutive bytes and merge them to get the actual 172 | * opcode. 173 | * - for example: 174 | * 0xA2F0 --> pc = 0xA2, pc + 1 = 0xF0 175 | * opcode = pc << 8 | pc + 1 176 | * - shifting A0 left by 8 bits, which adds 8 zeros (0xA200) 177 | * - bitwise OR to merge them 178 | * 179 | * 2) Decode the operation code 180 | * - look up to the optable to see what the op means 181 | * - for example: 182 | * 0xA2F0 --> ANNN: sets I to the address NNN (0x2F0) 183 | * 3) Execute the operation code 184 | * - execute the parsed op 185 | * - for example: 186 | * 0xA2F0 --> store 0x2F0 into the I register, as only 12-bits are 187 | * containing the value we need to store, we use a bitwise AND (with the value 188 | * 0x0FFF) to get rid of the first four bits. 189 | * - I = opcode & 0x0FFF 190 | * pc += 2 --> every instruction is 2 bytes long 191 | * 4) Update timers 192 | * - count to zero at 60hz if they are set to a number greater than 0 193 | * */ 194 | void emulate_cycle(void) { 195 | draw_flag = 0; 196 | sound_flag = 0; 197 | 198 | unsigned short op = memory[pc] << 8 | memory[pc + 1]; 199 | 200 | // Vx register, we are basically "grabbing" the x present in some 201 | // instructions like 3XNN 202 | unsigned short x = (op & 0x0F00) >> 8; 203 | 204 | // Vy register, we are basically "grabbing" the y present in some 205 | // instructions like 5XY0 206 | unsigned short y = (op & 0x00F0) >> 4; 207 | 208 | switch (op & 0xF000) { 209 | // we need extra checking 210 | case 0x0000: 211 | switch (op & 0x00FF) { 212 | // 00E0: Clears the screen 213 | case 0x00E0: 214 | debug_print("[OK] 0x%X: 00E0\n", op); 215 | for (int i = 0; i < 64 * 32; i++) { 216 | display[i] = 0; 217 | } 218 | pc += 2; 219 | break; 220 | // 00EE: Returns from a subroutine 221 | case 0x00EE: 222 | debug_print("[OK] 0x%X: 00EE\n", op); 223 | pc = stack[sp]; 224 | sp--; 225 | pc += 2; 226 | break; 227 | default: 228 | debug_print("[FAILED] Unknown opcode: 0x%X\n", op); 229 | break; 230 | } 231 | break; 232 | 233 | // 1NNN: Jumps to address NNN 234 | case 0x1000: 235 | debug_print("[OK] 0x%X: 1NNN\n", op); 236 | pc = op & 0x0FFF; 237 | break; 238 | 239 | // 2NNN: Calls subroutine at NNN 240 | case 0x2000: 241 | debug_print("[OK] 0x%X: 2NNN\n", op); 242 | 243 | /* 244 | * We need to jump to NNN so we should store the current 245 | * address of the program counter in the stack. But before storing 246 | * we increment the stack pointer to prevent overwriting the current 247 | * stack. After correctly storing the address we can set the pc to 248 | * the address NNN. Since we are calling a subroutine at a specific 249 | * address we don't have to increase the program counter by two. 250 | * */ 251 | sp += 1; 252 | stack[sp] = pc; 253 | pc = op & 0x0FFF; // getting the NNN 254 | break; 255 | 256 | // 3XNN: Skips the next instruction if Vx equals NN 257 | case 0x3000: 258 | debug_print("[OK] 0x%X: 3XNN\n", op); 259 | 260 | // (big-endian) a right shift by 8 increases the byte addr by 1 261 | if (V[x] == (op & 0x00FF)) { 262 | pc += 2; 263 | } 264 | 265 | pc += 2; 266 | break; 267 | 268 | // 4XNN: Skips the next instruction if Vx !equal NN 269 | case 0x4000: 270 | debug_print("[OK] 0x%X: 4XNN\n", op); 271 | 272 | if (V[x] != (op & 0x00FF)) { 273 | pc += 2; 274 | } 275 | 276 | pc += 2; 277 | break; 278 | 279 | // 5XY0: Skips the next instruction if Vx equals Vy 280 | case 0x5000: 281 | debug_print("[OK] 0x%X: 5XY0\n", op); 282 | 283 | if (V[x] == V[y]) { 284 | pc += 2; 285 | } 286 | 287 | pc += 2; 288 | break; 289 | 290 | // 6XNN: Sets Vx to NN 291 | case 0x6000: 292 | debug_print("[OK] 0x%X: 6XNN\n", op); 293 | 294 | V[x] = (op & 0x00FF); 295 | pc += 2; 296 | break; 297 | 298 | // 7XNN: Adds NN to Vx 299 | case 0x7000: 300 | debug_print("[OK] 0x%X: 7XNN\n", op); 301 | 302 | V[x] += op & 0x00FF; 303 | pc += 2; 304 | break; 305 | 306 | // 8XYn: Multiple instructions where n is a number 0-7 or E 307 | case 0x8000: 308 | switch (op & 0x000F) { 309 | // 8XY0: Sets Vx to the value of Vy 310 | case 0x0000: 311 | debug_print("[OK] 0x%X: 8XY0\n", op); 312 | 313 | V[x] = V[y]; 314 | pc += 2; 315 | break; 316 | 317 | // 8XY1: Sets Vx to Vx | Vy 318 | case 0x0001: 319 | debug_print("[OK] 0x%X: 8XY1\n", op); 320 | 321 | V[x] = (V[x] | V[y]); 322 | pc += 2; 323 | break; 324 | 325 | // 8XY2: Sets Vx to Vx & Vy 326 | case 0x0002: 327 | debug_print("[OK] 0x%X: 8XY2\n", op); 328 | 329 | V[x] = (V[x] & V[y]); 330 | pc += 2; 331 | break; 332 | 333 | // 8XY3: Sets vx to Vx 334 | case 0x0003: 335 | debug_print("[OK] 0x%X: 8XY3\n", op); 336 | 337 | V[x] = (V[x] ^ V[y]); 338 | pc += 2; 339 | break; 340 | 341 | // 8XY4: Adds Vy to Vx. Vf is set to 1 when there's a carry 342 | case 0x0004: 343 | debug_print("[OK] 0x%X: 8XY4\n", op); 344 | 345 | V[0xF] = (V[x] + V[y] > 0xFF) ? 1 : 0; 346 | V[x] += V[y]; 347 | 348 | pc += 2; 349 | break; 350 | 351 | // 8XY5: Vy is substracted from Vx. Vf is set to 0 when there's 352 | // a borrow 353 | case 0x0005: 354 | debug_print("[OK] 0x%X: 8XY5\n", op); 355 | 356 | V[0xF] = (V[x] > V[y]) ? 1 : 0; 357 | V[x] -= V[y]; 358 | 359 | pc += 2; 360 | break; 361 | 362 | // 8XY6: Stores the least significant bit of Vx in Vf and then 363 | // shifts Vx to the right by 1 364 | case 0x0006: 365 | debug_print("[OK] 0x%X: 8XY6\n", op); 366 | 367 | V[0xF] = V[x] & 0x1; 368 | V[x] = (V[x] >> 1); 369 | 370 | pc += 2; 371 | break; 372 | 373 | // 8XY7: Sets Vx to Vy minus Vx. Vf is set to 0 when there's a 374 | // borrow. 375 | case 0x0007: 376 | debug_print("[OK] 0x%X: 8XY7\n", op); 377 | 378 | V[0xF] = (V[y] > V[x]) ? 1 : 0; 379 | V[x] = V[y] - V[x]; 380 | 381 | pc += 2; 382 | break; 383 | 384 | // 8XYE: Stores the most significant bit of Vx in Vf and shifts 385 | // Vx to the left by 1 386 | case 0x000E: 387 | debug_print("[OK] 0x%X: 8XYE\n", op); 388 | 389 | V[0xF] = (V[x] >> 7) & 0x1; 390 | V[x] = (V[x] << 1); 391 | 392 | pc += 2; 393 | break; 394 | 395 | default: 396 | printf("[FAILED] Unknown op: 0x%X\n", op); 397 | break; 398 | } 399 | break; 400 | 401 | // 9XY0: SKips the next instruction if Vx !equal Vy 402 | case 0x9000: 403 | debug_print("[OK] 0x%X: 9XY0", op); 404 | 405 | if (V[x] != V[y]) { 406 | pc += 2; 407 | } 408 | 409 | pc += 2; 410 | break; 411 | 412 | // ANNN: Sets I to the address NNN 413 | case 0xA000: 414 | debug_print("[OK] 0x%X: ANNN\n", op); 415 | 416 | I = op & 0x0FFF; 417 | pc += 2; 418 | break; 419 | 420 | // BNNN: Jumps to the address NNN plus V0 421 | case 0xB000: 422 | debug_print("[OK] 0x%X: BNNN\n", op); 423 | 424 | pc = (op & 0x0FFF) + V[0]; 425 | break; 426 | 427 | // CXNN: Sets Vx to the result of a bitwise and operation on a random 428 | // number and NN 429 | case 0xC000: 430 | debug_print("[OK] 0x%X: CXNN\n", op); 431 | 432 | V[x] = (rand() % 256) & (op & 0x00FF); 433 | pc += 2; 434 | break; 435 | 436 | /* 437 | * DXYN: 438 | * 439 | * Draws a 8px * (N+1)px sprite at (V[x], Vy) 440 | * Each row of 8 pixels is read as bit-coded starting 441 | * from memory location I; I value doesn't change 442 | * after the execution of this instruction. 443 | * As described above, V[F] is set to 1 444 | * if any screen pixels are flipped from set 445 | * to unset when the sprite is 446 | * drawn, and to 0 if that doesn't happen. 447 | */ 448 | case 0xD000: 449 | debug_print("[OK] 0x%X: DXYN\n", op); 450 | draw_flag = 1; 451 | 452 | unsigned short height = op & 0x000F; 453 | unsigned short px; 454 | 455 | // set collision flag to 0 456 | V[0xF] = 0; 457 | 458 | // loop over each row 459 | for (int yline = 0; yline < height; yline++) { 460 | // fetch the pixel value from the memory starting at location I 461 | px = memory[I + yline]; 462 | 463 | // loop over 8 bits of one row 464 | for (int xline = 0; xline < 8; xline++) { 465 | // check if current evaluated pixel is set to 1 (0x80 >> 466 | // xline scnas throught the byte, one bit at the time) 467 | if ((px & (0x80 >> xline)) != 0) { 468 | // if drawing causes any pixel to be erased set the 469 | // collision flag to 1 470 | if (display[(V[x] + xline + ((V[y] + yline) * 64))] == 471 | 1) { 472 | V[0xF] = 1; 473 | } 474 | 475 | // set pixel value by using XOR 476 | display[V[x] + xline + ((V[y] + yline) * 64)] ^= 1; 477 | } 478 | } 479 | } 480 | 481 | pc += 2; 482 | break; 483 | 484 | // 2 instructions: 9E and A1 485 | case 0xE000: 486 | switch (op & 0x00FF) { 487 | // EX9E: Skips the next instruction if the key store in Vx is 488 | // pressed 489 | case 0x009E: 490 | debug_print("[OK] 0x%X: EX9E\n", op); 491 | if (keypad[V[x]]) { 492 | pc += 2; 493 | } 494 | 495 | pc += 2; 496 | break; 497 | 498 | // EXA1: Skips the next instruction if the key store in Vx isn't 499 | // pressed 500 | case 0x00A1: 501 | debug_print("[OK] 0x%X: EXA1\n", op); 502 | if (!keypad[V[x]]) { 503 | pc += 2; 504 | } 505 | 506 | pc += 2; 507 | break; 508 | 509 | default: 510 | printf("[FAILED] Unknown op: 0x%X", op); 511 | } 512 | break; 513 | 514 | // Set of 7 instructions starting with FX 515 | case 0xF000: 516 | switch (op & 0x00FF) { 517 | // FX07: Sets Vx to the value of the delay timer 518 | case 0x0007: 519 | debug_print("[OK] 0x%X: FX07\n", op); 520 | V[x] = dt; 521 | 522 | pc += 2; 523 | break; 524 | 525 | // FX0A: A key press is awaited and then stored in Vx (blocking) 526 | case 0x000A: 527 | debug_print("[OK] 0x%X: FX0A\n", op); 528 | 529 | for (int i = 0; i < 16; i++) { 530 | if (keypad[i]) { 531 | V[x] = i; 532 | pc += 2; 533 | break; 534 | } 535 | } 536 | break; 537 | 538 | // FX15: Sets the delay timer to Vx 539 | case 0x0015: 540 | debug_print("[OK] 0x%X: FX15\n", op); 541 | 542 | dt = V[x]; 543 | pc += 2; 544 | break; 545 | 546 | // FX18: Sets the sound timer to Vx 547 | case 0x0018: 548 | debug_print("[OK] 0x%X: FX18\n", op); 549 | 550 | st = V[x]; 551 | pc += 2; 552 | break; 553 | 554 | // FX1E: Adds Vx to I 555 | case 0x001E: 556 | debug_print("[OK] 0x%X: FX1E\n", op); 557 | 558 | I += V[x]; 559 | pc += 2; 560 | break; 561 | 562 | // FX29: Sets I to the location of the sprite for the character 563 | // in Vx 564 | case 0x0029: 565 | debug_print("[OK] 0x%X: FX29\n", op); 566 | 567 | // each digit is 5 bytes long 568 | I = V[x] * 5; 569 | pc += 2; 570 | break; 571 | 572 | /* 573 | * FX33: 574 | * 575 | * Stores the binary-coded decimal representation 576 | * of VX, with the most significant of three digits 577 | * at the address in I, the middle digit at I plus 578 | * 1, and the least significant digit at I plus 2. 579 | * (In other words, take the decimal representation 580 | * of VX, place the hundreds digit in memory 581 | * at location in I, the tens digit at 582 | * location I+1, and the ones digit at 583 | * location I+2.) 584 | * */ 585 | case 0x0033: 586 | debug_print("[OK] 0x%X: FX33\n", op); 587 | 588 | memory[I] = (V[x] % 1000) / 100; 589 | memory[I + 1] = (V[x] % 100) / 10; 590 | memory[I + 2] = (V[x] % 10); 591 | 592 | pc += 2; 593 | break; 594 | 595 | // FX55: Stores V0 through Vx (Vx included) in memory starting 596 | // at addr I. 597 | case 0x0055: 598 | debug_print("[OK] 0x%X: FX55\n", op); 599 | 600 | for (int i = 0; i <= x; i++) { 601 | memory[I + i] = V[i]; 602 | } 603 | 604 | pc += 2; 605 | break; 606 | 607 | // Fills V0 through Vx (Vx included) with values from memory 608 | // starting at addr I. 609 | case 0x0065: 610 | debug_print("[OK] 0x%X: FX65\n", op); 611 | 612 | for (int i = 0; i <= x; i++) { 613 | V[i] = memory[I + i]; 614 | } 615 | 616 | pc += 2; 617 | break; 618 | 619 | default: 620 | printf("[FAILED] Unknown op: 0x%X\n", op); 621 | break; 622 | } 623 | break; 624 | 625 | default: 626 | debug_print("[FAILED] Unknown opcode: 0x%X\n", op); 627 | break; 628 | } 629 | 630 | /* 631 | * Update timers: 632 | * 633 | * Decrement timers if they are > 0 634 | * */ 635 | if (dt > 0) dt -= 1; 636 | if (st > 0) { 637 | sound_flag = 1; 638 | puts("BEEP"); 639 | st -= 1; 640 | } 641 | } 642 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 500 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "chip8.h" 8 | #include "peripherals.h" 9 | extern int should_quit; 10 | 11 | int main(int argc, char** argv) { 12 | if (argc != 2) { 13 | error("usage: emulator rom.ch8"); 14 | return 1; 15 | } 16 | 17 | puts("[PENDING] Initializing CHIP-8 arch..."); 18 | init_cpu(); 19 | puts("[OK] Done!"); 20 | 21 | char* rom_filename = argv[1]; 22 | printf("[PENDING] Loading rom %s...\n", rom_filename); 23 | 24 | int error = load_rom(rom_filename); 25 | if(error) { 26 | if (error == -1) { 27 | error("[FAILED] fread() failure: the return value was not equal to the rom file size."); 28 | } else { 29 | perror("Error while loading rom"); 30 | } 31 | return 1; 32 | } 33 | 34 | puts("[OK] Rom loaded successfully!"); 35 | 36 | init_display(); 37 | puts("[OK] Display successfully initialized."); 38 | 39 | while (!should_quit) { 40 | emulate_cycle(); 41 | sdl_ehandler(keypad); 42 | 43 | if (draw_flag) { 44 | draw(display); 45 | } 46 | 47 | //delay to emulate chip-8's clock speed. 48 | usleep(1500); 49 | } 50 | 51 | stop_display(); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /src/peripherals.c: -------------------------------------------------------------------------------- 1 | #include "peripherals.h" 2 | 3 | #include 4 | 5 | SDL_Window* screen; 6 | 7 | // struct that handles all rendering 8 | SDL_Renderer* renderer; 9 | 10 | /** 11 | * Mapping Keyboard Keys 12 | * 13 | * A new layout is being used, not the original one: 14 | * 15 | * 1 2 3 4 16 | * q w e r 17 | * a s d f 18 | * z x c v 19 | */ 20 | SDL_Scancode keymappings[16] = { 21 | SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, 22 | SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R, 23 | SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D, SDL_SCANCODE_F, 24 | SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V}; 25 | 26 | int should_quit = 0; 27 | 28 | /** 29 | * init_display: initialize SDL display 30 | * @param void 31 | * @return void 32 | */ 33 | void init_display(void) { 34 | SDL_Init(SDL_INIT_VIDEO); 35 | 36 | screen = SDL_CreateWindow("CHIP-8", SDL_WINDOWPOS_CENTERED, 37 | SDL_WINDOWPOS_CENTERED, 64 * 8, 32 * 8, 0); 38 | renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED); 39 | } 40 | 41 | /** 42 | * draw: draw SDL rectangle to screen 43 | * @param display a pointer to the display 44 | * @return void 45 | */ 46 | void draw(unsigned char* display) { 47 | SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); 48 | 49 | // clear the current rendering target with the drawing color 50 | SDL_RenderClear(renderer); 51 | 52 | SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); 53 | 54 | // iterating thru the display (64*32) 55 | for (int y = 0; y < 32; y++) { 56 | for (int x = 0; x < 64; x++) { 57 | if (display[x + (y * 64)]) { 58 | SDL_Rect rect; 59 | 60 | rect.x = x * 8; 61 | rect.y = y * 8; 62 | rect.w = 8; 63 | rect.h = 8; 64 | 65 | SDL_RenderFillRect(renderer, &rect); 66 | } 67 | } 68 | } 69 | 70 | // update the screen 71 | SDL_RenderPresent(renderer); 72 | } 73 | 74 | /** 75 | * sdl_handler: SDL Event Handler for keypress 76 | * @param keypad pointer to the keypad 77 | * @return void 78 | */ 79 | void sdl_ehandler(unsigned char* keypad) { 80 | SDL_Event event; 81 | 82 | // check for event 83 | if (SDL_PollEvent(&event)) { 84 | // get snapshot of current state of the keyboard 85 | const Uint8* state = SDL_GetKeyboardState(NULL); 86 | 87 | switch (event.type) { 88 | case SDL_QUIT: 89 | should_quit = 1; 90 | break; 91 | default: 92 | if (state[SDL_SCANCODE_ESCAPE]) { 93 | should_quit = 1; 94 | } 95 | 96 | // updating the keypad with the current state 97 | for (int keycode = 0; keycode < 16; keycode++) { 98 | keypad[keycode] = state[keymappings[keycode]]; 99 | } 100 | 101 | break; 102 | } 103 | } 104 | } 105 | 106 | /** 107 | * stop_display: destroy SDL window and quit 108 | * @param void 109 | * @return void 110 | */ 111 | void stop_display(void) { 112 | SDL_DestroyWindow(screen); 113 | SDL_Quit(); 114 | } 115 | -------------------------------------------------------------------------------- /test_emu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | make clean 4 | make 5 | ./bin/emulator.out ./roms/LANDING.ch8 6 | --------------------------------------------------------------------------------