updated comments for all vcs examples

This commit is contained in:
Steven Hugg 2018-09-30 21:07:45 -04:00
parent b6197a009a
commit 46f8028117
28 changed files with 226 additions and 31 deletions

View File

@ -6,6 +6,12 @@ GPLv2
---
https://github.com/gasman/jsspeccy2
GPLv3
---
https://github.com/sehugg/javatari.js
GNU Affero General Public License v3.0

View File

@ -69,6 +69,7 @@ TODO:
- C/asm formatter
- fix WebAudio (https://news.ycombinator.com/item?id=18066474)
- Safari: verilog scope doesn't work
- no errors for verilog inline asm
WEB WORKER FORMAT

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,4 +1,4 @@

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 64K Tigervision bank-switching example

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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