diff --git a/LICENSE.txt b/LICENSE.txt index 99da2e51..84e20f04 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -6,6 +6,12 @@ GPLv2 --- +https://github.com/gasman/jsspeccy2 + +GPLv3 + +--- + https://github.com/sehugg/javatari.js GNU Affero General Public License v3.0 diff --git a/doc/notes.txt b/doc/notes.txt index 7db2e54f..9d75de03 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -69,8 +69,12 @@ TODO: - C/asm formatter - fix WebAudio (https://news.ycombinator.com/item?id=18066474) - Safari: verilog scope doesn't work +<<<<<<< HEAD - share playable link w/ verilog? - pixedit Sprite Rotation bitmap wrong (bpw?) +======= +- no errors for verilog inline asm +>>>>>>> 951088dd3b2f4cea5bb8ef5dfc8ea728fee3bbd7 WEB WORKER FORMAT diff --git a/presets/vcs/examples/adventure.a b/presets/vcs/examples/adventure.a index d7673074..28d3753a 100644 --- a/presets/vcs/examples/adventure.a +++ b/presets/vcs/examples/adventure.a @@ -5,6 +5,8 @@ org $f000 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; Now, we'll finally put everything together and ; make a little person with a hat that can move ; back and forth and throw rocks. We'll use one player @@ -21,6 +23,8 @@ ; ; Note: the Y coordinate goes bottom-top, not top-bottom ; as in the next section. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; counter equ $81 ; increments each frame yplyr equ $82 ; player y pos diff --git a/presets/vcs/examples/bankswitching.a b/presets/vcs/examples/bankswitching.a index 14226532..96f6b090 100644 --- a/presets/vcs/examples/bankswitching.a +++ b/presets/vcs/examples/bankswitching.a @@ -1,9 +1,23 @@ - + processor 6502 include "vcs.h" include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; The VCS only supports 4096 bytes of address space for +; cartridge ROMs, but you can use 8192 or more bytes by +; using a bank-switching scheme. This lets you map segments +; of address space to multiple ROM segments. +; +; This example demonstrates standard Atari bank-switching, +; which just lets you switch multiple segments into the main +; $1000 bytes of cartridge ROM. Because all bytes must be +; switched at once, this forces you to build a trampoline -- +; a segment of code that remains valid during the bank-switch +; process. +; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; seg.u Variables diff --git a/presets/vcs/examples/bigsprite.a b/presets/vcs/examples/bigsprite.a index a78ffca7..c061cb39 100644 --- a/presets/vcs/examples/bigsprite.a +++ b/presets/vcs/examples/bigsprite.a @@ -4,6 +4,18 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example demonstrates 48-pixel sprites. +; We'll use a technique similar to the Asynchronous Playfields +; trick -- reprogramming the TIA registers on-the-fly, writing +; to each register multiple times during the scanline. If we +; time our writes carefully, we'll be able to draw six unique +; sprites per scanline, for example to draw a six-digit +; scoreboard, or one large 48-pixel sprite. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 @@ -12,8 +24,6 @@ LoopCount byte THREE_COPIES equ %011 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - seg Code org $f000 diff --git a/presets/vcs/examples/bitmap.a b/presets/vcs/examples/bitmap.a index ef45aa0c..10e4a0b7 100644 --- a/presets/vcs/examples/bitmap.a +++ b/presets/vcs/examples/bitmap.a @@ -4,11 +4,17 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example demonstrates an asymmetric playfield, which +; allows different patterns for the left and right sides of +; the playfield, giving you 40 unique playfied pixels per line. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - seg Code org $f000 diff --git a/presets/vcs/examples/brickgame.a b/presets/vcs/examples/brickgame.a index d876769f..f4df9887 100644 --- a/presets/vcs/examples/brickgame.a +++ b/presets/vcs/examples/brickgame.a @@ -1,22 +1,24 @@ -j + processor 6502 include "vcs.h" include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; We've got collisions working, but now we'd like some more ; interaction. We can make a little "breakout" style game ; where the ball knocks out rows of bricks. We'll need to ; draw several rows of bricks, any or all of which might be ; missing. - +; ; We'll use a technique called "asychronous playfields". ; Remember that the playfield is either symmetric (20 pixels ; followed by the same 20 pixels reversed) or repeated (20 pixels ; repeated twice). But if we change the playfield registers ; *during* the scanline, we can make the second half a ; different bitmap than the first half. - +; ; We're going to move away from the HMPx/HMOVE method of ; setting object position and use the SetHorizPos method, since ; we really need to know the X position of both player and ball @@ -24,13 +26,15 @@ j ; two scanlines per object. But we do it during the overscan ; period at the end of the frame, and we've got the cycles ; to spare. - +; ; Also, we're going to keep score and have a rudimentary ; scoreboard, which makes this sort of an actual game! - +; ; Fun fact: Messing with the HMOVE register causes a "comb" ; effect on the left 8 pixels of the screen, which can be seen ; at the bottom of the screen in the overscan region. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; seg.u Variables org $80 diff --git a/presets/vcs/examples/collisions.a b/presets/vcs/examples/collisions.a index 1886c87b..859f373c 100644 --- a/presets/vcs/examples/collisions.a +++ b/presets/vcs/examples/collisions.a @@ -7,6 +7,8 @@ seg.u Variables org $80 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; In this example, we're going to tackle collision detection, ; which is one thing in the VCS that's easier than expected. ; The TIA has 15 different collision flags that can detect a @@ -14,19 +16,21 @@ ; and playfield. You can check these flags at any time (at the ; end of the frame is pretty common). When you're done checking ; you clear them all at once by writing to CXCLR. - +; ; For this example we'll use the ball object, and detect collisions ; between it and the playfield and the player. We only know ; the Y position of the ball and player (the X position is in ; the TIA chip) so we'll base our bounce decisions on the Y position ; of the ball (for playfield bounces) or the relative Y position of ; ball and player (for player bounces). - +; ; Note: You can press the button to capture the ball. - +; ; We're going to also include sound, which is generated by writing ; a volume register, a frequency register, and a mode register for ; one of two channels. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; counter byte ; increments each frame yplyr byte ; player y pos diff --git a/presets/vcs/examples/complexscene.a b/presets/vcs/examples/complexscene.a index e8f3dc8e..4cd99cf4 100644 --- a/presets/vcs/examples/complexscene.a +++ b/presets/vcs/examples/complexscene.a @@ -4,6 +4,13 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example demonstrates a scene with a full-screen +; playfield, and a single sprite overlapping it. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 diff --git a/presets/vcs/examples/complexscene2.a b/presets/vcs/examples/complexscene2.a index 76defb66..18cc0fbc 100644 --- a/presets/vcs/examples/complexscene2.a +++ b/presets/vcs/examples/complexscene2.a @@ -4,6 +4,14 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example demonstrates a scene with a full-screen +; playfield, and two sprites overlapping it. This takes more +; CPU time, so our kernel operates in 4-line chunks. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 diff --git a/presets/vcs/examples/lines.a b/presets/vcs/examples/lines.a index c245faf8..31e8b145 100644 --- a/presets/vcs/examples/lines.a +++ b/presets/vcs/examples/lines.a @@ -4,6 +4,13 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example draws a moving line using 16-bit fixed-point +; math and a missile object. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 diff --git a/presets/vcs/examples/missiles.a b/presets/vcs/examples/missiles.a index 87fd8a28..fedcc195 100644 --- a/presets/vcs/examples/missiles.a +++ b/presets/vcs/examples/missiles.a @@ -3,8 +3,8 @@ include "vcs.h" include "macro.h" - org $f000 - +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; Besides the two 8x1 sprites ("players") the TIA has ; two "missiles" and one "ball", which are just variable-length ; dots or dashes. They have similar positioning and display @@ -12,6 +12,10 @@ ; set the horizontal position of any of them. ; But we can also use the HMPx/HMOVE registers directly to move the ; objects by small offsets without using this routine every time. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + org $f000 counter equ $81 diff --git a/presets/vcs/examples/multisprite2.a b/presets/vcs/examples/multisprite2.a index cdcbdbff..10a22725 100644 --- a/presets/vcs/examples/multisprite2.a +++ b/presets/vcs/examples/multisprite2.a @@ -4,13 +4,15 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; For lots of games, we'd like to display more than two sprites. ; There are lots of different ways to tackle this on the VCS, ; but we're going to try for a generalized approach that lets ; use have N different sprites at any X-Y coordinate, each with ; its own bitmap and color table. This is tricky because we can ; only do so much on each scanline. - +; ; Our approach is to separate the problem into three phases. ; In the sort phase, we sort all sprites by Y coordinate. ; We do one sort pass per frame, so it may take several frames @@ -20,7 +22,7 @@ ; coming up. We then allocate it to one of the two player ; objects in hardware and set its position using the SetHorizPos ; method. We can set one or both of the player objects this way. - +; ; In the display phase, we display the objects which we previously ; assigned and positioned. First we figure out how many scanlines are ; required. If only one object is scheduled, we just use its height. @@ -30,7 +32,7 @@ ; registers at the appropriate time. We don't have time to do much ; else, so we don't look for any new objects to schedule until ; we're done with this loop. - +; ; This scheme can only display up to two objects on a given ; scanline, so if the system tries to schedule a third, it will ; be ignored. Also, the positioning routine takes a few scanlines @@ -52,6 +54,8 @@ ; There are still some timing issues to fix as you'll see when you ; move the adventure person around with the joystick. These might ; add additional lines to the display. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; seg.u Variables org $80 diff --git a/presets/vcs/examples/multisprite3.a b/presets/vcs/examples/multisprite3.a index fff20c8d..efc5bfee 100644 --- a/presets/vcs/examples/multisprite3.a +++ b/presets/vcs/examples/multisprite3.a @@ -4,13 +4,15 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; For lots of games, we'd like to display more than two sprites. ; There are lots of different ways to tackle this on the VCS, ; but we're going to try for a generalized approach that lets ; use have N different sprites at any X-Y coordinate, each with ; its own bitmap and color table. This is tricky because we can ; only do so much on each scanline. - +; ; Our approach is to separate the problem into three phases. ; In the sort phase, we sort all sprites by Y coordinate. ; We do one sort pass per frame, so it may take several frames @@ -20,7 +22,7 @@ ; coming up. We then allocate it to one of the two player ; objects in hardware and set its position using the SetHorizPos ; method. We can set one or both of the player objects this way. - +; ; In the display phase, we display the objects which we previously ; assigned and positioned. First we figure out how many scanlines are ; required. If only one object is scheduled, we just use its height. @@ -30,7 +32,7 @@ ; registers at the appropriate time. We don't have time to do much ; else, so we don't look for any new objects to schedule until ; we're done with this loop. - +; ; This scheme can only display up to two objects on a given ; scanline, so if the system tries to schedule a third, it will ; be ignored. Also, the positioning routine takes a few scanlines @@ -41,6 +43,8 @@ ; sprite entry is missed. In the sort phase, we move those sprites ; ahead of lower priority sprites in the sort order. This makes ; overlapping sprites flicker instead of randomly disappear. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; seg.u Variables org $80 diff --git a/presets/vcs/examples/musicplayer.a b/presets/vcs/examples/musicplayer.a index 11de0e9d..aff5cd27 100644 --- a/presets/vcs/examples/musicplayer.a +++ b/presets/vcs/examples/musicplayer.a @@ -6,26 +6,30 @@ org $f000 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; This program demonstrates a VCS music player based on tracks ; and patterns. A pattern is a list of variable-length notes, ; each of which is defined by a pitch and duration. ; There are two tracks, one for each audio channel. ; Each track consists of a list of patterns, each entry being ; a byte offset into the Patterns array. - +; ; The patterns in the tracks are played in-order until one ends, ; and then both tracks are restarted. It's up to the composer ; to make sure the durations in each track line up properly. - +; ; Patterns consist of NOTE or TONE commands. TONE sets the ; tone of the channel (the AUDCx register) and NOTE plays a note ; with a duration taken from a lookup table. ; TONE 0 ends a pattern. - +; ; Both channels share the same logical array for tracks and patterns, ; so both tracks can take up to 255 bytes total, and all patterns ; can use up to 255 bytes total. ; The music player uses 8 bytes of RAM (not counting stack). +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Trk0idx equ $e0 ; offset into tracks for channel 0 Trk1idx equ $e1 ; offset into tracks for channel 1 diff --git a/presets/vcs/examples/pal.a b/presets/vcs/examples/pal.a index d682bb55..00676ab8 100644 --- a/presets/vcs/examples/pal.a +++ b/presets/vcs/examples/pal.a @@ -6,6 +6,8 @@ org $f000 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; To output a PAL signal, you need the following: ; ; - 3 scanlines of VSYNC @@ -14,23 +16,25 @@ ; - 36 blank lines ; ; Total = 312 lines (vs 262 for NTSC) - +; ; PAL runs at 50 Hz (vs 60 Hz for NTSC) ; so your game will run more slowly. ; Since you have extra cycles to play with, you could just ; call your position update routine twice every five frames. - +; ; Note also that PAL has different colors than NTSC. ; (See http://www.randomterrain.com/atari-2600-memories-tia-color-charts.html) - +; ; The TIMER_SETUP macro only goes up to 215 lines, ; so for the PAL visible frame you would need to use ; multiple sections (say 215 + 13 = 228) or count manually ; like we do in this example. - +; ; Many VCS games use conditional defines ; (IFCONST and IFNCONST in DASM) ; to switch between NTSC and PAL constants. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; background color BGColor equ $81 diff --git a/presets/vcs/examples/playfield.a b/presets/vcs/examples/playfield.a index 71b9f5c8..fbbac0d3 100644 --- a/presets/vcs/examples/playfield.a +++ b/presets/vcs/examples/playfield.a @@ -4,11 +4,15 @@ include "macro.h" org $f000 - + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; We're going to mess with the playfield registers, PF0, PF1 and PF2. ; Between them, they represent 20 bits of bitmap information ; which are replicated over 40 wide pixels for each scanline. ; By changing the registers before each scanline, we can draw bitmaps. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Counter equ $81 diff --git a/presets/vcs/examples/procgen1.a b/presets/vcs/examples/procgen1.a index 26d08c2b..ba9fbf3e 100644 --- a/presets/vcs/examples/procgen1.a +++ b/presets/vcs/examples/procgen1.a @@ -4,6 +4,14 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example uses a linear-feedback shift register to +; procedurally generate random rooms for the player to walk +; through. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 diff --git a/presets/vcs/examples/retrigger.a b/presets/vcs/examples/retrigger.a index cf7549fa..d609a2bb 100644 --- a/presets/vcs/examples/retrigger.a +++ b/presets/vcs/examples/retrigger.a @@ -4,6 +4,18 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; The sprite retrigger trick relies on a behavior when the +; NUSIZ register is set to display multiple copies of objects +; (usually two). Basically, if the RESPx register is strobed +; multiple times on a given scanline, the first (leftmost) copy +; of the object will be hidden, and the TIA will draw the other +; copy. You can keep strobing the register to output multiple +; copies on the same scanline. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + org $f000 CurRow equ $8f diff --git a/presets/vcs/examples/road.a b/presets/vcs/examples/road.a index b02e32fd..cddbcb7a 100644 --- a/presets/vcs/examples/road.a +++ b/presets/vcs/examples/road.a @@ -3,6 +3,30 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example draws a pseudo-3D road using the two missiles +; and ball objects. With these, we'll draw the two shoulders +; of the road, and also the dashed center line. +; +; Our plan is this: The two missiles and ball all start at the +; same position on the horizon. As we go down the screen, we'll +; move the three objects slightly based on the curve of the road. +; The left shoulder of the road will be biased a little more to +; the left, and the right shoulder will bias a little more right. +; We can use the HMOVE registers for movement, since each object +; will not need to move more than seven pixels on any given +; scanline. +; +; It'd be easier if the scanlines went from bottom to top, +; because we could just start at the horizontal center of the +; screen and follow the road curve to the horizon, ending up +; wherever the road takes us. But scanlines go top to bottom, +; so we have to also do some preprocessing before the frame begins +; to figure out where the road ends up. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 diff --git a/presets/vcs/examples/score6.a b/presets/vcs/examples/score6.a index 4595e0f4..f13dbf4e 100644 --- a/presets/vcs/examples/score6.a +++ b/presets/vcs/examples/score6.a @@ -4,6 +4,13 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example uses the 48-pixel retriggering method to display +; a six-digit scoreboard. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 diff --git a/presets/vcs/examples/scoreboard.a b/presets/vcs/examples/scoreboard.a index aa73dcd6..77e59ff5 100644 --- a/presets/vcs/examples/scoreboard.a +++ b/presets/vcs/examples/scoreboard.a @@ -4,6 +4,15 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example draws a scoreboard using the playfield +; and a 4x5 font. We encode the left and right digits in a +; single byte, so we just mask one side or the other, and +; combine them into a 8-bit byte to draw a digit. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 diff --git a/presets/vcs/examples/sprite.a b/presets/vcs/examples/sprite.a index 4c593f09..5bb5ad47 100644 --- a/presets/vcs/examples/sprite.a +++ b/presets/vcs/examples/sprite.a @@ -5,6 +5,8 @@ org $f000 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; Sprites are a tricky beast on the 2600. ; You only have two of them. ; They are 8 bits wide and 1 bit high. @@ -14,6 +16,8 @@ ; To position Y, you simply wait until the desired scanline and ; set the bits of your sprite to a non-zero value. ; Having fun yet? :) +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Counter equ $81 diff --git a/presets/vcs/examples/tigervision[3E].a b/presets/vcs/examples/tigervision[3E].a index 3aec45c7..10f92562 100644 --- a/presets/vcs/examples/tigervision[3E].a +++ b/presets/vcs/examples/tigervision[3E].a @@ -1,4 +1,4 @@ - + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 64K Tigervision bank-switching example diff --git a/presets/vcs/examples/timing1.a b/presets/vcs/examples/timing1.a index e4c14986..54821f33 100644 --- a/presets/vcs/examples/timing1.a +++ b/presets/vcs/examples/timing1.a @@ -5,12 +5,16 @@ org $f000 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; We're going to try to animate sprites horizontally. ; Remember, we have to pause the CPU until the exact moment the ; scanline hits the desired horizontal position of the sprite. ; Since we can't hard-code the SLEEP macro we'll have to do it ; dynamically somehow. But since the TIA beam is racing so much ; faster than the CPU clock, we'll have to be clever. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; counter equ $81 diff --git a/presets/vcs/examples/timing2.a b/presets/vcs/examples/timing2.a index 86692236..b3be23b8 100644 --- a/presets/vcs/examples/timing2.a +++ b/presets/vcs/examples/timing2.a @@ -5,6 +5,8 @@ org $f000 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ; We're going to use a more clever way to position sprites ; ("players") which relies on additional TIA features. ; Because the CPU timing is 3 times as coarse as the TIA's, @@ -12,6 +14,8 @@ ; CPU delays alone. ; Additional TIA registers let us nudge the final position ; by discrete TIA clocks and thus target all 160 positions. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; counter equ $81 diff --git a/presets/vcs/examples/tinyfonts2.a b/presets/vcs/examples/tinyfonts2.a index fb80aae1..c50f8e7a 100644 --- a/presets/vcs/examples/tinyfonts2.a +++ b/presets/vcs/examples/tinyfonts2.a @@ -4,10 +4,30 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; Now that we know how to draw extra-wide sprites, we can +; apply this technique to another type of object: text. +; +; We can draw scoreboards and other kinds of text using the +; playfield registers. However, these are pretty blocky, and +; limited to 40 pixels in width. But we can draw lines of text +; that are 48 pixels width by five pixels high using the +; sprite retriggering trick. +; +; Instead of fetching our bitmap data from ROM, we build a +; bitmap in RAM using lookup tables. Building the bitmap array +; efficiently is a challenge, because we've got to look up 60 +; bytes in memory and combine those into 30 bytes. If we did +; this without regard to performance, it might consume a few +; thousand CPU cycles, which would require 30 or 40 scanlines +; just to set up the sprite. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 - Temp .byte WriteOfs .byte ; offset into dest. array FontBuf LoopCount .byte ; counts scanline when drawing diff --git a/presets/vcs/examples/wavetable.a b/presets/vcs/examples/wavetable.a index 2d29503a..54ceb06a 100644 --- a/presets/vcs/examples/wavetable.a +++ b/presets/vcs/examples/wavetable.a @@ -4,6 +4,14 @@ include "macro.h" include "xmacro.h" +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; This example drives the VCS audio DAC directly to generate +; 4-voice music. Unfortunately, the CPU is 100% utilized so +; we can't display anything. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + seg.u Variables org $80 diff --git a/presets/verilog/7segment.v b/presets/verilog/7segment.v index f05e36a8..684a0661 100644 --- a/presets/verilog/7segment.v +++ b/presets/verilog/7segment.v @@ -2,6 +2,11 @@ `include "hvsync_generator.v" /* +seven_segment_decoder - Decodes a digit into 7 segments. + +segments_to_bitmap - Encodes a 7-segment bitmask into + a 5x5 bitmap. + Segment bit indices: 6666 diff --git a/presets/verilog/ball_absolute.v b/presets/verilog/ball_absolute.v index 60573577..e2cf3cbe 100644 --- a/presets/verilog/ball_absolute.v +++ b/presets/verilog/ball_absolute.v @@ -1,6 +1,10 @@ `include "hvsync_generator.v" +/* +A bouncing ball using absolute coordinates. +*/ + module ball_absolute_top(clk, reset, hsync, vsync, rgb); input clk; diff --git a/presets/verilog/ball_paddle.v b/presets/verilog/ball_paddle.v index 87b7a0f1..c74300e6 100644 --- a/presets/verilog/ball_paddle.v +++ b/presets/verilog/ball_paddle.v @@ -3,6 +3,10 @@ `include "digits10.v" `include "scoreboard.v" +/* +A brick-smashing ball-and-paddle game. +*/ + module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb); input clk; diff --git a/presets/verilog/ball_slip_counter.v b/presets/verilog/ball_slip_counter.v index 0082b86d..dae9dfad 100644 --- a/presets/verilog/ball_slip_counter.v +++ b/presets/verilog/ball_slip_counter.v @@ -1,6 +1,11 @@ `include "hvsync_generator.v" +/* +A bouncing ball using the "slipping counter" method, as +used in Pong, Computer Space, and other early arcade games. +*/ + module ball_slip_counter_top(clk, reset, hsync, vsync, rgb); input clk; diff --git a/presets/verilog/clock_divider.v b/presets/verilog/clock_divider.v index 12f4a83a..b1f4b56f 100644 --- a/presets/verilog/clock_divider.v +++ b/presets/verilog/clock_divider.v @@ -1,4 +1,9 @@ +/* +A clock divider in Verilog, using both the cascading +flip-flop method and the counter method. +*/ + module clock_divider( input clk, input reset, diff --git a/presets/verilog/cpu_platform.v b/presets/verilog/cpu_platform.v index 92f3b8e8..a4c5ee78 100644 --- a/presets/verilog/cpu_platform.v +++ b/presets/verilog/cpu_platform.v @@ -8,6 +8,18 @@ `include "sound_generator.v" `include "cpu16.v" +/* +A full video game console, with the following components: + + 64 kilobytes (32,678 16-bit words) of RAM + 16-bit CPU running at 4.857 MHz + 32x30 tile graphics with 256 x 8 tile ROM + 32 16x16 sprites per frame with sprite ROM + 16 colors (two per tile, one per sprite) + Two game controllers (four direction switches, two buttons) + One paddle/analog stick controller +*/ + module cpu_platform(clk, reset, hsync, vsync, hpaddle, vpaddle, switches_p1, switches_p2, diff --git a/presets/verilog/digits10.v b/presets/verilog/digits10.v index 7a9768b8..aa12829f 100644 --- a/presets/verilog/digits10.v +++ b/presets/verilog/digits10.v @@ -4,6 +4,15 @@ `include "hvsync_generator.v" +/* +ROM module with 5x5 bitmaps for the digits 0-9. + +digits10_case - Uses the case statement. +digits10_array - Uses an array and initial block. + +These two modules are functionally equivalent. +*/ + // module for 10-digit bitmap ROM module digits10_case(digit, yofs, bits); diff --git a/presets/verilog/hvsync_generator.v b/presets/verilog/hvsync_generator.v index 175145af..24587616 100644 --- a/presets/verilog/hvsync_generator.v +++ b/presets/verilog/hvsync_generator.v @@ -2,6 +2,13 @@ `ifndef HVSYNC_GENERATOR_H `define HVSYNC_GENERATOR_H +/* +Video sync generator, used to drive a simulated CRT. +To use: +- Wire the hsync and vsync signals to top level outputs +- Add a 3-bit (or more) "rgb" output to the top level +*/ + module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos); input clk; diff --git a/presets/verilog/lfsr.v b/presets/verilog/lfsr.v index fd2e7129..c2f97ebb 100644 --- a/presets/verilog/lfsr.v +++ b/presets/verilog/lfsr.v @@ -2,6 +2,10 @@ `ifndef LFSR_V `define LFSR_V +/* +Configurable Linear Feedback Shift Register. +*/ + module LFSR(clk, reset, enable, lfsr); parameter TAPS = 8'b11101; // bitmask for taps diff --git a/presets/verilog/paddles.v b/presets/verilog/paddles.v index 3202f1fe..d2019775 100644 --- a/presets/verilog/paddles.v +++ b/presets/verilog/paddles.v @@ -1,6 +1,10 @@ `include "hvsync_generator.v" +/* +Paddle demonstration. +*/ + module paddles_top(clk, reset, hsync, vsync, hpaddle, vpaddle, rgb); input clk, reset; diff --git a/presets/verilog/racing_game.v b/presets/verilog/racing_game.v index 168be4de..e1a57444 100644 --- a/presets/verilog/racing_game.v +++ b/presets/verilog/racing_game.v @@ -3,6 +3,11 @@ `include "sprite_bitmap.v" `include "sprite_renderer.v" +/* +A simple racing game with two sprites and a scrolling playfield. +This version does not use a CPU; all logic is straight Verilog. +*/ + module racing_game_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); input clk; diff --git a/presets/verilog/racing_game_cpu.v b/presets/verilog/racing_game_cpu.v index 046a8851..6aa64f9e 100644 --- a/presets/verilog/racing_game_cpu.v +++ b/presets/verilog/racing_game_cpu.v @@ -4,6 +4,11 @@ `include "sprite_renderer.v" `include "cpu8.v" +/* +A simple racing game with two sprites and a scrolling playfield. +This version uses the 8-bit CPU. +*/ + // uncomment to see scope view //`define DEBUG diff --git a/presets/verilog/ram.v b/presets/verilog/ram.v index 43441151..093b3d7c 100644 --- a/presets/verilog/ram.v +++ b/presets/verilog/ram.v @@ -2,6 +2,17 @@ `ifndef RAM_H `define RAM_H +/* +RAM_sync - Synchronous RAM module. +RAM_async - Asynchronous RAM module. +RAM_async_tristate - Async RAM module with bidirectional data bus. + +Module parameters: + +A - number of address bits (default = 10) +D - number of data bits (default = 8) +*/ + module RAM_sync(clk, addr, din, dout, we); parameter A = 10; // # of address bits diff --git a/presets/verilog/ram1.v b/presets/verilog/ram1.v index 2f76b00e..b732eba7 100644 --- a/presets/verilog/ram1.v +++ b/presets/verilog/ram1.v @@ -3,6 +3,10 @@ `include "digits10.v" `include "ram.v" +/* +Displays a grid of digits on the CRT using a RAM module. +*/ + module test_ram1_top(clk, reset, hsync, vsync, rgb); input clk, reset; diff --git a/presets/verilog/scoreboard.v b/presets/verilog/scoreboard.v index cda8c499..1fdef21a 100644 --- a/presets/verilog/scoreboard.v +++ b/presets/verilog/scoreboard.v @@ -5,6 +5,11 @@ `include "hvsync_generator.v" `include "digits10.v" +/* +player_stats - Holds two-digit score and one-digit lives counter. +scoreboard_generator - Outputs video signal with score/lives digits. +*/ + module player_stats(reset, score0, score1, lives, incscore, declives); input reset; diff --git a/presets/verilog/sound_generator.v b/presets/verilog/sound_generator.v index 1cd34eef..2e25fc58 100644 --- a/presets/verilog/sound_generator.v +++ b/presets/verilog/sound_generator.v @@ -2,6 +2,13 @@ `include "hvsync_generator.v" `include "lfsr.v" +/* +Sound generator module. +This module has a square-wave oscillator (VCO) which can +be modulated by a low-frequency oscillator (LFO) and also +mixed with a LFSR noise source. +*/ + module sound_generator(clk, reset, spkr, lfo_freq,noise_freq, vco_freq, vco_select, noise_select, lfo_shift, mixer); diff --git a/presets/verilog/sprite_bitmap.v b/presets/verilog/sprite_bitmap.v index d0327b10..5c503e6c 100644 --- a/presets/verilog/sprite_bitmap.v +++ b/presets/verilog/sprite_bitmap.v @@ -4,6 +4,13 @@ `include "hvsync_generator.v" +/* +Simple sprite renderer example. + +car_bitmap - ROM for a car sprite. +sprite_bitmap_top - Example sprite rendering module. +*/ + module car_bitmap(yofs, bits); input [3:0] yofs; diff --git a/presets/verilog/sprite_renderer.v b/presets/verilog/sprite_renderer.v index 9a1d702d..5e6a85fc 100644 --- a/presets/verilog/sprite_renderer.v +++ b/presets/verilog/sprite_renderer.v @@ -1,10 +1,14 @@ - + `ifndef SPRITE_RENDERER_H `define SPRITE_RENDERER_H `include "hvsync_generator.v" `include "sprite_bitmap.v" +/* +Displays a 16x16 sprite (8 bits mirrored left/right). +*/ + module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits, gfx, in_progress); diff --git a/presets/verilog/sprite_rotation.v b/presets/verilog/sprite_rotation.v index 20c4aadf..eea6dc1f 100644 --- a/presets/verilog/sprite_rotation.v +++ b/presets/verilog/sprite_rotation.v @@ -1,10 +1,15 @@ - + `ifndef SPRITE_ROTATION_H `define SPRITE_ROTATION_H `include "hvsync_generator.v" -// tank bitmap ROM module +/* +tank_bitmap - ROM for tank bitmaps (5 different rotations) +sprite_renderer2 - Displays a 16x16 sprite. +tank_controller - Handles display and movement for one tank. +*/ + module tank_bitmap(addr, bits); input [7:0] addr; diff --git a/presets/verilog/sprite_scanline_renderer.v b/presets/verilog/sprite_scanline_renderer.v index c3cf895a..4d733bbe 100644 --- a/presets/verilog/sprite_scanline_renderer.v +++ b/presets/verilog/sprite_scanline_renderer.v @@ -2,6 +2,13 @@ `include "hvsync_generator.v" `include "ram.v" +/* +sprite_scanline_renderer - Module that renders multiple + sprites whose attributes are fetched from shared RAM, + and whose bitmaps are stored in ROM. Made to be paired + with the FEMTO-16 CPU. +*/ + module example_bitmap_rom(addr, data); input [15:0] addr; diff --git a/presets/verilog/starfield.v b/presets/verilog/starfield.v index d63491d0..d0ab4f30 100644 --- a/presets/verilog/starfield.v +++ b/presets/verilog/starfield.v @@ -2,6 +2,10 @@ `include "hvsync_generator.v" `include "lfsr.v" +/* +Scrolling starfield generator using a period (2^16-1) LFSR. +*/ + module starfield_top(clk, reset, hsync, vsync, rgb); input clk, reset; diff --git a/presets/verilog/switches.v b/presets/verilog/switches.v index 26a50159..ed45067b 100644 --- a/presets/verilog/switches.v +++ b/presets/verilog/switches.v @@ -1,7 +1,9 @@ - + `include "hvsync_generator.v" /* +Switch test program. + Player 1 Keys: arrow keys + space + shift Player 2 Keys: A/D/W/S + Z + X */ diff --git a/presets/verilog/tank.v b/presets/verilog/tank.v index b4f878d1..001e962d 100644 --- a/presets/verilog/tank.v +++ b/presets/verilog/tank.v @@ -3,6 +3,15 @@ `include "digits10.v" `include "sprite_rotation.v" +/* +Tank game. + +minefield - Displays the minefield. +playfield - Displays the playfield maze. +tank_game_top - Runs the tank game, using two tank_controller + modules. +*/ + module minefield(hpos, vpos, mine_gfx); input [8:0] hpos; diff --git a/presets/verilog/test_hvsync.v b/presets/verilog/test_hvsync.v index 2c938c90..a3445ce8 100644 --- a/presets/verilog/test_hvsync.v +++ b/presets/verilog/test_hvsync.v @@ -1,6 +1,10 @@ `include "hvsync_generator.v" +/* +A simple test pattern using the hvsync_generator module. +*/ + module test_hvsync_top(clk, reset, hsync, vsync, rgb); input clk, reset; diff --git a/presets/verilog/tile_renderer.v b/presets/verilog/tile_renderer.v index 6d5b65cf..8a09de12 100644 --- a/presets/verilog/tile_renderer.v +++ b/presets/verilog/tile_renderer.v @@ -3,6 +3,11 @@ `include "font_cp437_8x8.v" `include "ram.v" +/* +Displays a 32x30 grid of 8x8 tiles, whose attributes are + fetched from RAM, and whose bitmap patterns are in ROM. +*/ + module tile_renderer(clk, reset, hpos, vpos, rgb, ram_addr, ram_read, ram_busy,