The three rules of Ruby Q.:
-
Please do not post any solutions or spoiler discussion for this quiz
until
48 hours have passed from the time on this message. -
Support Ruby Q. by submitting ideas as often as you can:
- Enjoy!
Suggestion: A [QUIZ] in the subject of emails about the problem helps
everyone
on Ruby T. follow the discussion. Please reply to the original quiz
message,
if you can.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
by Ethan P.
CHIP-8 was an interpreted language used in the 1970’s for basic games
like Pong.
While it is technically an interpreted language, it defines many
components a
real computer has, such as registers and a processor. Today, like many
other
gaming consoles, it is kept alive by emulators allowing it to be played
on most
any modern computer. Emulation is where raw operation codes (the most
low-level
way of feeding instructions to a computer) are translated by another
computer,
giving a totally different system the ability to run programs not
designed for
it.
Your job is to make an emulator. It will only cover some basic parts of
it, but
all emulators have to start somewhere. I have written a simple program,
and will
give you a list of all the opcodes I used and what they are supposed to
do. We
won’t worry about graphics right now, just simple operations. Four
things need
to be done:
1. Make the emulator read the file. All opcodes are four digit hex
numbers,
but those will need to be split.
2. Set up the registers and other assorted things so they can be
modified.
3. Interpret the function of the opcode in Ruby.
4. Dump all the registers so you can check and make sure everything
went well.
Like I said, all opcodes are four digit long hex numbers. So you read
four hex
digits worth of data, process it, then move on to the next four digits.
There
are 16 registers (areas where data can be stored). They are named V0
through VF,
and are all eight bits wide. VF is usually used as a carry for math
operations.
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
the end
of the file and have nothing left to read, so you therefore need
to exit
gracefully.
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
would
assume that VF would act as a carry if needed.
The
included program will not need a carry for
this
function, so providing for one is purely
optional.)
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
isn’t.
8X06 VX = VX SHIFT RIGHT 1 (VX=VX/2), VF is set to the value of the
least
significant bit of VX before the
shift.
8XY7 VX = VY - VX, VF is set to 0 if there is a borrow, 1 if there
isn’t.
8X0E VX = VX SHIFT LEFT 1 (VX=VX*2), VF is set to the value of the most
significant bit of VX before the
shift.
CXKK VX = Random number AND KK
Lets explain how to read these opcodes. Take opcode 1NNN for example.
Since the
1NNN starts with 1, we know that no matter what comes after it we will
be doing
a jump instruction. Same with the other codes. For the opcode 8XY2, we
know if
an opcode starts with 8 and ends in 2 it will be the operation “VX = VX
AND VY”.
The variables NNN, KK, X and Y are a little different. They can
represent any
hex number (0-F), and also are used to note how big of chunks to read
them in.
For NNN, you will want to read those as a three digit hex number. Lets
do an
example opcode (in hex): 1234. Since it starts with 1, we know it is a
“Jump to
address NNN” command. The three numbers after that (the NNN part), are
234, so
we know to jump to location 234 in the file (this is a hex number, not
decimal).
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
current
address in the file is how many bytes you are from the beginning of the
file. So
if I am at address 008 in the file, I am eight bytes away from the
beginning of
the file, and therefore the next byte I read will be byte nine. Say we
had the
opcode 100F, that means we would jump to after byte 16 (it is a hex
remember).
If your wondering how the carries work, here are some examples. First
off,
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
register. So
what we do is make VF equal 00000001, and then roll over to 00000000.
Sort of
like an old car odometer. When it hits 99,999 miles, it goes back to
00,000
miles, except we are keeping track of the fact that it rolled over.
Subtraction
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
it
positive. So what we do is “borrow”, making VX equal to 100000000. All
of a
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
borrow
was needed. If a borrow was not needed, VF gets set to 00000001, since
you
didn’t need the extra.
Now for shifts. To sum it up, if you shift left, the far left number
gets taken
away, and a zero added to the far right. So 10101111 would become
01011110,
because we got rid of the far left number and added a zero to the far
right.
Shift right is the same except going the other way (get rid of far right
number,
add 0 to the left). As you can see, a number disappears when you shift.
VF is
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
1.5:
http://www.pdc.kth.se/%7Elfo/chip8/CHIP8.htm
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
all
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
machine
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
changes
VF:00000000
A note: If everything is working as it is supposed to, you should run
straight
through the file once. If you are looping, I would start with double
checking
all your math operations.
Good Luck!