The three rules of Ruby Q.:
Please do not post any solutions or spoiler discussion for this quiz
48 hours have passed from the time on this message.
Support Ruby Q. by submitting ideas as often as you can:
Suggestion: A [QUIZ] in the subject of emails about the problem helps
on Ruby T. follow the discussion. Please reply to the original quiz
if you can.
by Ethan P.
CHIP-8 was an interpreted language used in the 1970’s for basic games
While it is technically an interpreted language, it defines many
real computer has, such as registers and a processor. Today, like many
gaming consoles, it is kept alive by emulators allowing it to be played
any modern computer. Emulation is where raw operation codes (the most
way of feeding instructions to a computer) are translated by another
giving a totally different system the ability to run programs not
Your job is to make an emulator. It will only cover some basic parts of
all emulators have to start somewhere. I have written a simple program,
give you a list of all the opcodes I used and what they are supposed to
won’t worry about graphics right now, just simple operations. Four
to be done:
1. Make the emulator read the file. All opcodes are four digit hex
but those will need to be split.
2. Set up the registers and other assorted things so they can be
3. Interpret the function of the opcode in Ruby.
4. Dump all the registers so you can check and make sure everything
Like I said, all opcodes are four digit long hex numbers. So you read
digits worth of data, process it, then move on to the next four digits.
are 16 registers (areas where data can be stored). They are named V0
and are all eight bits wide. VF is usually used as a carry for math
Here is the list of opcodes you will need to interpret:
NNN is an address KK is an 8 bit constant X and Y are two 4 bits constants 0000 This is nothing. If you see this, it should mean that you are at
of the file and have nothing left to read, so you therefore need
1NNN Jump to the address NNN of the file 3XKK Skip next instruction if VX == KK 6XKK VX = KK 7XKK VX = VX + KK (Note: The documentation does not mention this, but I
assume that VF would act as a carry if needed.
included program will not need a carry for
function, so providing for one is purely
8XY0 VX = VY 8XY1 VX = VX OR VY 8XY2 VX = VX AND VY 8XY3 VX = VX XOR VY 8XY4 VX = VX + VY, Sets VF to 1 if there is a carry, 0 if there isn't 8XY5 VX = VX - VY, VF is set to 0 if there is a borrow, 1 if there
8X06 VX = VX SHIFT RIGHT 1 (VX=VX/2), VF is set to the value of the
significant bit of VX before the
8XY7 VX = VY - VX, VF is set to 0 if there is a borrow, 1 if there
8X0E VX = VX SHIFT LEFT 1 (VX=VX*2), VF is set to the value of the most significant bit of VX before the
CXKK VX = Random number AND KK
Lets explain how to read these opcodes. Take opcode 1NNN for example.
1NNN starts with 1, we know that no matter what comes after it we will
a jump instruction. Same with the other codes. For the opcode 8XY2, we
an opcode starts with 8 and ends in 2 it will be the operation “VX = VX
The variables NNN, KK, X and Y are a little different. They can
hex number (0-F), and also are used to note how big of chunks to read
For NNN, you will want to read those as a three digit hex number. Lets
example opcode (in hex): 1234. Since it starts with 1, we know it is a
address NNN” command. The three numbers after that (the NNN part), are
we know to jump to location 234 in the file (this is a hex number, not
KK and X/Y are similar, just for different sized chunks.
While I’m on the subject, let’s talk about addresses in detail. Your
address in the file is how many bytes you are from the beginning of the
if I am at address 008 in the file, I am eight bytes away from the
the file, and therefore the next byte I read will be byte nine. Say we
opcode 100F, that means we would jump to after byte 16 (it is a hex
If your wondering how the carries work, here are some examples. First
addition. Say we add these two numbers (opcode 8xy4):
11111111 <--This is VX + 00000001 <--This is VY
Obviously this would equal 100000000, but that is too big for one
what we do is make VF equal 00000001, and then roll over to 00000000.
like an old car odometer. When it hits 99,999 miles, it goes back to
miles, except we are keeping track of the fact that it rolled over.
is similar (opcode 8xy5):
00000000 <-- This is VX - 00000001 <-- This is VY
Since the registers can only deal with positive numbers, we have to keep
positive. So what we do is “borrow”, making VX equal to 100000000. All
sudden our subtraction works:
100000000 <--VX - 00000001 <--VY = 11111111
If we do this though, we have to make sure VF is zero to indicate that a
was needed. If a borrow was not needed, VF gets set to 00000001, since
didn’t need the extra.
Now for shifts. To sum it up, if you shift left, the far left number
away, and a zero added to the far right. So 10101111 would become
because we got rid of the far left number and added a zero to the far
Shift right is the same except going the other way (get rid of far right
add 0 to the left). As you can see, a number disappears when you shift.
set to the number that disappears (obviously it can only be a 1 or 0).
A full list of opcodes can be had at David W.'s page, under section
He also has a full explanation of everything, so if check there for more
details. If you want to write code for an opcode that I didn’t list, by
means go for it.
Be sure to start reading the attached program from the beginning. To my
understanding in a real Chip-8 game up to address 200 was reserved for
code which we wont worry about.
The register values you should get are:
V1:01000101 V2:10111011 V3:11101100 V4:this number should be random, so do multiple runs to make sure it
A note: If everything is working as it is supposed to, you should run
through the file once. If you are looping, I would start with double
all your math operations.