What's new

Chip 8

orphean

New member
Chip8 Assembler

Well I finished my Chip 8 Assembler. Working on speeding up my emulator right now, it works more or less but its amazing slow so I've done all my assembler testing on Hap's Fish n' chips emu.

The assembler has a built in chip8/schip code editor with most of the usual 'code editor' features:
c8asm.jpg


Its quite fast as you might imagine dealing with such a simple instruction set and tiny programs.

The program in the screenshot above is a simple C8 program I wrote that is included in the attached rar. It was assembled with the assembler and when running it looks like this:
bounce.jpg


The compiled program and the source for it is included in the attached rar. It requires .NET 2.0 to run.

I figure pretty much noone has been waiting for a new Chip8 assembler but I wrote it, so here it is!

Update: I updated the rar file after fixing some bugs in the assembler, also added support for the FX30 opcode (point I to the hi res font char in X) which wasn't in the main Winter's doc but is used in games and documented in the CHIPPER docs. There are some stupid UI bugs I'll quash soon and update again, but nothing that will keep someone from using it.

Code:
C8Asm Quick Docs

Note: These docs are not a substitute for 'real' chip8/schip docs. It does not cover particulars of when VF is set and why, etc.  
Its main purpose is simply to list the mnemonics and syntax for the opcodes.

; starts a comment, comments are terminated at a newline.

All number literals are in hexadecimal and are preceded by # (ie, #FFFF)

Labels must be on their own line and terminate with a colon (:) (ie, label:)
Whitespace is mostly irrelevant except in special cases (like the required newline following a label declaration)

Opcode mnemonics are case insensitive.

The registers are as follows:
V# where # is 0-F - The 16 general purpose chip8 registers.
I - The memory pointer register.
[I] - Access value pointed at I (used for the reg->mem, mem->reg opcodes)
ST - Sound Timer
DT - Delay Timer
K - Key
F - Low Res Font
HF - High Res Font

Instructions:

high
Sets SCHIP graphics mode
Opcode: 00FF

low
sets CHIP8 graphics mode
Opcode: 00FE

cls
Clears the screen
Opcode: 00E0

exit
Quit program
Opcode: 00FD

sclr
Scroll 4 pixels right
Opcode: 00FB

scll
Scroll 4 pixels left
Opcode: 00FC

scld [literal]
Scroll [literal] pixels down. Ex: scld #4 will scroll down 4 pixels
Opcode: 00CK

dw [literal]
Echo [literal] into the bytestream. Ex: dw #FFFF will write #FFFF into the executable.
Opcode: None, Assembler directive.

call [label]
Calls a chip8/schip subroutine located at [label].
Opcode: 2NNN

jp [label]
Preforms an unconditional jump to [label]
Opcode: 1NNN

jp [label], [register]
Preforms an unconditional jump to [label] + contents of [register] Ex: jp main, V0
Opcode: BNNN

ret
Return from a chip8/schip subroutine.
Opcode: 00EE

drw [register1], [register2], [literal]
Draws a sprite 8x[literal] lines at [reg1],[reg2]. If [literal] is 0 it draws a 16x16 sprite. Ex: drw V0, V1, #3
Opcode: DXYK

se [register], [literal]
Skip next line iff [register] == [literal]
Opcode: 3XKK

se [reg1], [reg2]
Skip next line iff [reg1] == [reg2]
Opcode: 5XY0

sne [register], [literal]
Skip next line iff [register] != [literal]
Opcode: 4XKK

sne [reg1], [reg2]
Skip next line iff [reg1] != [reg2]
Opcode: 9XY0

skp [register]
Skip next line iff the key in [register] is pressed.
Opcode: EX9E

sknp [register]
Skip next line iff the key in [register] is not pressed.
Opcode: EXA1

rnd [register], [literal]
Stores a random number in [register] with the range 0-[literal]
Opcode: CXKK

add [register], [literal]
Adds [literal] to [register]
Opcode: 7XKK

add [reg1], [reg2]
Adds [reg2] to [reg1]
Opcode: 8XY4

add I, [register]
Adds [register] to I.
Opcode: FX1E

sub [reg1], [reg2]
Subtracts [reg2] from [reg1]
Opcode: 8XY5

subn [reg1], [reg2]
[reg1] = [reg2] - [reg1]
Opcode: 8XY7

or [reg1], [reg2]
[reg1] = [reg1] | [reg2]
Opcode: 8XY1

and [reg1], [reg2]
[reg1] = [reg1] & [reg2]
Opcode: 8XY2

xor [reg1], [reg2]
[reg1] = [reg1] ^ [reg2]
Opcode: 8XY3

shl [register]
[register] << 1
Opcode: 8X0E

shr [register]
[register] >> 1
Opcode: 8X06

bcd [register]
Stores the BCD representation of M(I)..M(I+2) in [register]
Opcode: FX33

hps [register]
Store registers V0 to [register] in HP Flags where [register] < 8
Opcode: FX75

hpl [register]
Load registers V0 to [register] from HP Flags where [register] < 8
Upcode: FX85

ld [register], [literal]
Loads [literal] into [register]
Opcode: 6XKK

ld [reg1], [reg2]
Loads [reg2] into [reg1]
Opcode: 8XY0

ld I, [label]
Loads the address of [label] into I.
Opcode: ANNN

ld F, [register]
Points I to the lowres font char stored in [register]
Opcode: FX29

ld HF, [register]
Points I to the hires font char stored in [register]
Opcode: FX30

ld [I], [register]
Saves registers V0 to [register] in memory starting at location I.
Opcode: FX55

ld [register], [I]
Loads registers V0 to [register] from memory starting at location I.
Opcode: FX65

ld [register], DT
Stores the contents of DT into [register]
Opcode: FX07

ld DT, [register]
Stores [register] into DT
Opcode: FX15

ld ST, [register]
Stores [register] into ST
Opcode: FX18

ld [register], K
Waits for keypress and stores result in [register]
Opcode: FX0A
 
Last edited:

deltaphc

New member
Hello everyone.

After reading through most of this thread and consulting two or three Chip-8 docs, I've made yet another Chip-8/SChip emulator!

http://delta.slinked.net/files/ChipSharp/ChipSharp-100beta1.zip
Called ChipSharp. Programmed using C#, .NET 2.0, and SdlDotNet.

Some features:
  • Speed control
  • Screenshot function
  • 2x/4x/8x zoom
  • Adjustable colors
  • Adjustable beep
  • CPU runs most programs. A few still have problems, like hap's emutest
  • Download includes hap's Chip-8 program collection
  • Uses the 1234QWERASDFZXCV key layout

It's in beta mostly 'cause there's more I want to add, like input remapping, saving user preferences, and compatibility options. As for source code, I'll release the emulation core a bit later; still doing tweaking, adding comments, etc.

Development started on January 2nd. I'm surprised it turned out as well as it did; this is my first emulator. It could probably use a little optimization, but it appears to run fine in most cases.

Screenshots:



 
Last edited:

Zieg

New member
Hi guys, I'm starting a Chip-8 emulator too.
But there's something I don't understand...
In pong, for example, there's the opcode 22D4, so it should run a subroutine at the address 724.
But the Pong ROM is only 246 bytes long....
How can I run the subroutine at 724 if that address doesn't exist?
Someone explain please ^^
 

Garstyciuks

New member
The first 512 bytes of memory is reserved for the interpreter. It used to contain the interpreter code for some processors, so they could execute the chip8 code. You may use it anyway you like it. I personally use that space to store the font data in my emulator. And you have to load the ROM starting from memory address 0x200 (or 512 in decimal).
 

deltaphc

New member
http://delta.slinked.net/files/ChipSharp/ChipSharp-100beta2.zip

ChipSharp v1.00 beta 2 released! Now includes full source code, under a BSD license.

Changes since beta 1:
  • Now compiled using C# 2008/VS2008. Still only requires .NET 2.0, thanks to multitargeting.
  • In Chip8 mode, 4 pixels are now drawn internally on a 128x64 display. Before, it would skip every other pixel and depend on the video output routine to draw 4 pixels to the final bitmap.
  • Scrolling is more accurate. Scroll Test and Emutest both produce better output.
  • Fixed a subtraction and left shift opcode; Sokoban is now playable.
  • [video output] Using GDI+ instead of SdlDotNet's SurfaceControl.
  • [video output] Significant speedup.
  • [video output] Picture is no longer blurry.
  • [video output] Performs well regardless of how many pixels are set.
  • Added input remapping. Available in Options-->Input-->Configure.
  • Added shortcut keys for various functions. Look in the menus for details.
  • Added option for disabling sprite wrapping.
  • Fixed a crash when the beep sound would run out of channels to play on.
  • Fixed a crash when the user closes the emulator while having a program running.
  • Several DLLs were deleted, since they are no longer needed.
  • Miscellaneous tweaks and polish.
 

Zieg

New member
The first 512 bytes of memory is reserved for the interpreter. It used to contain the interpreter code for some processors, so they could execute the chip8 code. You may use it anyway you like it. I personally use that space to store the font data in my emulator. And you have to load the ROM starting from memory address 0x200 (or 512 in decimal).

Got it, thanks!
 

Memery

New member
I recall somebody mentioning that a particular emulator was able to detect when some ROMs were in "Game Over" state. I've noticed most ROMs will enter an infinite loop to signify the end of gameplay - this can be handled by checking if a jmp destination is equal to its own address in memory (which would cause an infinite loop) and breaking execution with a game over notification of some sort.

How do you all deal with display refreshes? I send off the video RAM for processing whenever a sprite or cls opcode is executed. I'm thinking of periodically updating the display at some fixed time period (Eg. 60Hz) rather than hammering away whenever a long sequence of sprite opcodes are executed... What was your strategy?

Sprite wrapping seems inconsistent between ROMs. BLITZ will not execute correct if vertical wrapping is enabled, but it seems that almost every other ROM expects wrapping along both X and Y axes. Is this an error of the programmer, or David Winter's documentation?
 
Last edited:

hap

New member
If you tell your OS to update the display every time the CHIP-8 graphics are updated, it might cause slowdown. Just write to a secondary VRAM buffer for graphics updates, and yes, update the OS display at a fixed interval like 60Hz.

Sprite wrapping is an emulator enhancement. I don't think any games rely on it, eg. Brix doesn't work properly with it either: if the bat is halfway off the screen, the part on the left side won't deflect the ball.
 

Marce1991

Programmer
Thousands of questions

Hey guys!
I have alot of questions here(about 8 chip), I was wondering if anyone could help me O.O
Well here it goes:
1-People say 'NN' (part of an opcode) is a constant. Is it an integer?What's its value?
2-I'm currently doing the emulation the worst way I suppose, here goes a sketch on pseudo coding:
read rom
search memory for opcodes
if opcode1
doopcode1();
if opcode2
doopcode2();
...
What's the best way of doing this?
3-I have ran few checks, and it seems that 'pong' does not have some of the opcodes ( for instance 00EE). Is that normal?
4-How do I declare/build an array containing many strings?I'd at least like to search for the opcodes by index O.O
e.g.: (this is the mem search function)
I'd like to do this
search = (char*) memchr(memblock, *op[n] , size);
but currently im more onto this:
search = (char*) memchr(memblock, *op0 , size);
search = (char*) memchr(memblock, *op1 , size);
search = (char*) memchr(memblock, *op2 , size);
...

(lol)
5- What are those flags (VF-VX). Are they adresses? Bool variables?Im kinda confused.
6-What's the best way of rendering?Go straight for directX, windows or maybe can the c++ language handle monochromatic rendering?haha
7-The 'sprites' the opcodes refer to are actually white spots right?
Thanks in advance!And sorry for the excessive questioning...
Cheers~
edit:sorry almost forgot...
8-How do I deal with the hertz cycle, ppl say it counts down to zero at 60 hertz.But 60 hertz is a frequency. So from what value do I start? And how is the interruption?How long does it last?
9- How do I handle the 'carry' thing and the 'borrow'. What are them for?
Thanks again!
 
Last edited:

Garstyciuks

New member
Here goes:

1. All opcodes are 2 bytes size. For example, if an opcode is 1NNNN (the jmp opcode), then you get the NNN number by doing (opcode&0x0FFF).

2. The easiest way to emulate something is to directly interpret all of its opcodes. Here's an example of a possible execution function:

PHP:
void execute()
{
    unsigned short opcode = (memory[pc]<<8) | memory[pc+1];
    switch((opcode&0xF000)>>24)
    {
        case 0x0:
            if ((opcode&0x00FF) == 0xE0)
            {
                //clear screen
            }
            else if ((opcode&0x00FF) == 0xEE)
            {
                //return from a subroutine
            }
            pc += 2;
            break;

        case 0x1:
           pc = opcode&0x0FFF; 
           break;

        case ...:
           ...
     }
}

3. Each ROM use the opcodes they need to use.

4. You aren't supposed to search for the opcodes. You simply load the ROM starting at memory address 512 and start the execution from there, not caring what value is located at the program counter (pc). If the ROM doesn't contain any errors, then your emulator will work fine.

5. V0 - VF aren't flags. They are CPU registers, there are 16 of them and they can store 1 byte (unsigned char) values. They are used for remembering the x and y locations of objects, etc...

6. There is no best way of rendering. It really depends on your preference. For example, I used OpenGL on the Windows version of my emulator and SDL on the cross-platform version.

7. The DRAW opcode requires the I (address) register to point to the pixel data. The width of sprites in basic chip8 mode is fixed to 8 and the height is specified in the opcode's last nibble. Each byte represents one line of the sprite, one bit represents one pixel (1 for white, 0 for black).

8. The delay and sound counters initially are set to 0. You only need to decrement them if they are larger than 0. If the delay counter is set, then you need to stop the execution of other opcodes, until the counter is 0, and if the sound counter is set, you continue execution, but play a beeping sound as long as the sound counter is larger than 0. And you should decrement them at 60Hz interval.

9. The carry and borrow flags are generated by arithmetic opcodes and are saved in VF register (16th register) as 1 (if carry/borrow occurred) or 0, if it didn't. The carry occurs when you add two values and the result exceeds the number of bits. For example if you would add 0x10 and 0xFF, the result would be 0x09 (since all the registers are 8bit sized) and a carry flag would be generated. The borrow flag is pretty similar to carry flag and it is set when the first operand of subtraction is smaller than the second one.


Hope I made some things clearer. Good luck on your programming!
 
Last edited:

Doomulation

?????????????????????????
8-How do I deal with the hertz cycle, ppl say it counts down to zero at 60 hertz.But 60 hertz is a frequency. So from what value do I start? And how is the interruption?How long does it last?
It means it should execute 60 cycles per second. Timing isn't very good for chip8, so typically they just mean that you should execute 60 opcodes, check the registers and whatnot, all 60 times per second.
 

CodeSlinger

New member
Running the emulator at 60 opcodes per second I find is dead slow. Games like wipeoff and invaders are just too tedius to play.

Trouble is that ive never played the original chip8 or played anyone elses emulator to know what the correct speed of the game should be.

I find running it at 400 opcodes per second is the most enjoyable.
 

Doomulation

?????????????????????????
This, is unfortunately a problem. Some games run faster than others. Some require a lot of cycles / second, some requires few. There's no way around it, unfortunately.
Timing in chip8 is not known very much.
 

CodeSlinger

New member
Thanks for the reply.

I guess I'll leave timing as is for the moment then. Sound seems to work fine no matter how i deal with the timing so I guess the best way forward is to perhaps have the emulator ini file configurable for how many opcodes per second it should exectue. That way the player can adjust it themselves. Not that anyone's ever gonna play on it, but still worth doing.

I'll iron out a few more bugs like why some of the graphics flicker on and off and then i'll start the gameboy emulator.
 

Garstyciuks

New member
The graphics flicker because it's the way chip8 is designed. It moves an object by drawing the same image data on top of where the object originally was and then draws the sprite at a different location. If the screen gets updated in the middle of this, the graphics flicker.

I don't see any reliable and well designed solution for this. Though there could be some hacks made, like not updating the screen until the sprite is moved, but there are certain situations which would destroy the balance of this method.
 

Doomulation

?????????????????????????
Yes, it would be more like hacks and can break things.
It is unfortunately the way Chip8 was designed. It's a weak system, after all.
 

CodeSlinger

New member
I see. I dont mind the graphics flickering if they are supposed to flicker because that means im doing something right. To stop the graphics flickering would mean hacking the original system which I guess is not the point in emulation.

When i get a chance i'll track down the other bugs in the emu, but it's sounding like im fairly close to having it working.

Thanks guys.
 

J0hn

New member
This is my emulator, there's also a simple schip/chip8 disassembler in pseudo c code and the rom of the game blitz whitout the "instant game over" bug.

Link
 
Last edited:

Thesuperchang

New member
Chip8

Hi, I am the one known as Thesuperchang. Recently I've been working on a chip8 emulator. At the moment I am only missing the Super, sound, input and graphics opcodes so the emulator should emulate as specified.

I have developed my emulator in a Linux environment so its likely that I'll use the X Library for all my graphics and user input. As for the sound, I'm still not sure.

The source to my emulator can be found below:
http://www.megaupload.com/?d=JQRZ1P42

Any constructive criticism would be greatly appreciated.

---

I've reworked a few things in the emulator above. Quite a few bugs have been located and fixed. Graphics has been implemented, however there are gfx bugs. This is likely due to by drawing algorithm as all graphics are rotated 90 degrees and some overlap.

Most recent source can be downloaded below;
http://www.megaupload.com/?d=BPYJPB35

Regards,
-Thesuperchang
 
Last edited:

Aire83

New member
i've coded all the opcodes , now im need to somehow display the graphic onto the screen, which i'm totally lost. Can somone help me get started?

so i have a multi-d array for the video memory that contains bool values. I don't get how to use these values to draw the sprites onto the screen.

I've looked through all the posts in this thread and didnt found anything helpful on this matter
 
Last edited:

Top