**********************************
* VIDEO TETRIS (C) Rickard Gune *
**********************************

(This text is mostly a copy of the Video Pong page on my homepage:
http://www.rickard.gunee.com/projects)

 
---- Introduction ----
I have made the game Tetris using a PIC16F84 running @ 12MHz. Tetris is an old Russian
computer game where you should try to fit in block into a play-field, quite simple but
really fun. In my version, the video signal is generated in software. The only hardware
used for the video generation is two resistors forming a 2-bit DA converter. Usually
the video signal is generated in video games is created with a dedicated video chips,
reading the image data from a graphics memory. In this project the video signal
is calculated in real-time by the microprocessor as the electron beam sweeps over
the screen.

 
---- How to play the game ----
When the power is turned on the game starts! (was no memory left for a fancy intro
screen or similar). The score is shown in the bottom right corner, and the next block
to come is shown in the upper left corner of the screen. As the blocks fall down,
they can be moved sideways by using the joystick (left gameport on hardware), the
fall speed can temporary be increased by moving joystick down. The fire-button is
used to rotate the blocks. When one horizontal line is full, then it is removed.
You get points for full lines and placed blocks. As you get more points the difficult
level is increased by increased block falling speed. The musics speed is increased as
the game speed increases. You get game over when the playfield level has reached to
the top and there is not room for more blocks.
 

---- The software ----
With a processor performing 3MIPS, it is not easy to make a video signal in software.
Each instruction performed takes 1/3 us. Each scan-line on the screen takes 64us, where
52us are visible, so it gives 52*3=156 visible clock cycles per line. Maximum resolution
that can be obtained is 156 pixels in x-axis if the software is setting one pixel per
clock (using for example only bcf and bsf), but more is needed to make a game, like
loops and such. A loop quantifies the time to 3-clock pieces, giving a resolution of
52 pixels. (One could obtain a kind of 156pixels resolution with one or two offset nops,
but the code to select this would eat to many clock cycles to do any good). However
Tetris is quite simple, the resoluton is quite low, and there is no motion, the blocks
of pixels are just turned on and off. The most demanding part of the game is to show the
score at the bottom of the screen, it is shown in the bottom of the screen. It obtains
higher resolution by loading the PORTB with the bitmap for the number and shift it out
one pixel per clock cycle.

So far I've only talked about the graphic generation. But there is more to it to get a
video signal. All scan-lines first have a 4us-sync pulse, then black for 8us, then the
52us graphic comes. These horizontal sync-pulses makes the TV understand when a scan-line
starts, but there is needed to send information about when a new picture starts too, it
is called vertical sync, and is a special pattern that tells the TV that a new image is
coming. There are two kinds of vertical sync, because the image is divided into two part
images, showing even and odd lines, to get less flickering. In Tetris, the two images are
identical, so the game is not using the full y-resolution possible, but it doesn't matter
because it is way better than the x-resolution anyway, making the x-resolution the
biggest problem.

The game-field is kept in memory as a 32byte array, 16x16 bits, where one bit is one pixel-
block on the screen. The area to the upper left is for showing the next block, and by making
it a part of the game field it is possible to use the same block-drawing routines as for the
game, and thereby saving memory. Each frame, the falling block is first removed from the
game-field, and then tests are performed if the block can move, as the player wants it to.
Then the block is drawn back to the screen at the new position. When a block is to be tested,
put or removed, it first must be generated. To generate a block means compressing it from the
compressed data, rotating it and then store the relative coordinates of the block in the block
array. The block data is compressed in relative coordinates. In compressed format, each 
coordinate is stored in two bits for both x and y, where the two bits can represent the numbers
1,0,1,2. These values need to be uncompressed to 4*2 byte sized values representing the
coordinates in twos complement format. Depending of the angle the block should have, the
coordinates might need to be mirrored or/and swapped. When the block have been created it can 
easily be put, removed or tested. The test routine checks if there is any pixels set on the
block positions where the block should be put. If pixels are set, then the block cant be put
there. New blocks are selected at random, where the random number is a counter that increases
for every frame, making the random number dependent of how long it takes for the player to place
the block, making a quite good random number.
The game stuff, like checking joystick and move stuff around, is taken care of in the first
scan-lines, when no graphics is drawn. During the time before the play-field is shown, there is
a little bit of free time to play the music, but there is not time to play it on all lines, and
that make the music sound distorted. The music is stored in the data eeprom, and stored in a
compressed one byte format,where one byte
contains length and note. The note's frequency is looked up in a table, and so is the length too.
(The frequencies are based on the line frequency so they are not exactly the correct frequencies)
The speed of the game is increasing constantly and music-speed increases as the game speed
increases. 
Making this kind of software is mostly a clock-cycle-counting project, all timings are quite
critical, so whatever paths the execution-flow of the program takes, it must take the same number
of clock cycles. This is quite hard, and I've not managed to do this on all lines, so the image
is a little bit bent in some places. (Most analog TV-sets fix this, but on some digital projectors
it is more visible)


---- The hardware ----
The hardware is quite simple because everything is made in software. Two resistors, forming a DA
converter together with the input impedance of the TV, generate the video signal. This can generate
the levels 0v (sync), 0.3v (black), 0.7v (gray), and 1.0v (white). To be able to handle the variation
of input resistance of different audio equipment, two resistors are used to make a 1-bit DA to generate
the audio. When generating the video, the PORTB is used as a shift register to get one pixel per
instruction when high-resolution text is shown on the screen. Shifting a port requires the port to
be set as output if a whole byte is to be shifted out. First, this seems like a problem, the whole
port can't be used for anything else than video generation, but that is not quite correct. A port
can be used as an input when not used as a shift register, so in Tetris PORTB it is used for joystick
input when not used as a shift register. The digital joystick is a switch to ground, so all needed
to connect it to the PIC is a couple of pull up resistors, and that is available inside the PIC.
Unfortunately it is not that simple, if a pin on a port is grounded when used as an output, the output
buffer of the pic would burn up, so this is solved by adding one extra 1k resistor on each pin to
limit the current. What about those pull up resistors? There are 10k pull up resistors built into
the PIC that can be switched on and off. However, using them would be a too strong pull up, so the 1k
current limiting resistor (plus bad switches in the joystick) can't pull the input low enough.
Therefor an external 100k resistor pull up network is added. The power supply part of the circuit is
quite simple, it uses a standard 7805 to get a 5v supply. The input can be 8-18 volt, DC or AC
(Thanks to the diode at the power input)


---- Over-clocking a PIC16X84 ----
To get enough processing power to generate the video signal, a little bit higher clock frequency was
needed. The clock frequency should be a multiple of 4Mhz to make it easier to generate the correct
timing. The PIC16X84s are available in a 4MHz version and a 10MHz version, but the 10Mhz version was
quite expensive when I started to make this project, so I tried to over-clock it, and it worked
without problems, well, almost anyway. The 16C84 became unerasable after a while when over-clocked,
but the 16F84 seemed to work without problems, I've had them running for hundreds of hours without
problems. (But I wouldn't recommend you to use a over-clocked PIC in a commercial project). Some
people claims that the 4Mhz and the 10Mhz versions are the same chip with different text on the
package, it would explain why the chip can be over-clocked more than 3 times, but I don't know.


---- Contens of ZIP-file ----

tetris.txt              You're reading it now ! =)
gamefaq.txt             Frequently asked questions about my games.
tetris.asm              The tetris game main source code (PAL version)
tetris.hex              The hex-file to put in a PIC16F84 to get the game up and running.
ntsctetr.asm            The tetris game main source code (NTSC version)
ntsctetr.hex            The hex-file to put in a PIC16F84 to get the game up and running (NTSC version).
tetris.jpg              Picture of the game in action.
tetris_schematics.png   schematic over the hardware
tetris_layout.png       the layout
tetris_components.jpg   the component placement


---- Problems ? ----
If you have questions about the games, make sure to check out the video game FAQ (Frequently Asked Questions)
before you ask me. Also have a look at my microcontroller based projects homepage, which is located at
http://www.rickard.gunee.com/projects


---- Legal stuff ---- 
PIC-Tetris (C) Rickard Gune. This is open source, use this at your own risk ! You may use the information on
this page for your own projects as long as you refer to the original author (by name and link to authors
homepage), don't do it for profit and don't hurt or harm anyone or anything with it. The author can not be
held responsible for any damage caused by the information on this and related pages.
