Jump to content



Robert M's Photo

Robert M

Member Since 30 Dec 2002
OFFLINE Last Active Oct 18 2011 5:49 PM

Topics I've Started

Script based sound driver?

Tue Oct 4, 2011 7:20 AM

I have been thinking about developing a script driven sound driver for the VCS. My thoughts are outlined below. I thought it would be good to get some feedback on what I have in mind before implementing it:

Script Driven Sound Driver for VCS:
===================================
This document outlines a proposal for a scripting language for the VCS that
will enable simpliciation of the programming of the sound features of the TIA.
PROS:
-----
- Scripts can be shared.
- Development of sound can be more easily handed off to another team member.
- No need to write a new sound driver for a game.
CONS:
----
- Interpreting scripts is fairly time intensive. Each script command will take
  between 40 and 60 cycles to complete.  That said, sound generation requires
  few commands, and large calculations can be spread over several TV frames. In
  general I expect a program will need to commit between 3 to 5 scanlines of
  processor time for each TIA Audio channel every TV frame.
- ROM and RAM usage will not be optimal. This only matters if you are a trying
  for a minimum size game.  With bankswitching and other recent ROM and RAM
  expansion modes this is no longer a real issue.
PROGRAMMER'S MODEL:
====================
The TIA has two audio channels numbered 0 and 1.  Each audio channel has three
write-only registers:
	    AUDVx = Channel volume    0 to 15 (0 == min/off, 15 == max)
	    AUDFx = Channel frequency 0 to 31 (0 = highest, 31 = lowest)
	    AUDCx = Channel Waveform  0 to 15 (Documented elsewhere)
Since the TIA registers are write-only, we need RAM available for scripts to
perform calculations and keep track of state, such as loop counters. For each TIA
audio channel we will add up to 8 virtual read/write registers of 8-bits each.
The registers are numbered 0 through 7.  A good script will use as few virtual
registers as possible to conserve RAM.
In addition to these registers, each Audio channel driver requires a two byte
pointer in RAM (script_pointer) that points to the next byte in the current
script, and a second two byte pointer of temporary RAM (temp_pointer) is needed
while the driver is actively executing script commands during a TV update.
During the rest of the TV frame temp_pointer RAM is free to hold other values.
Both of these pointers and the eight virtual registers will need to be in
zero page RAM.  Note: If you use scripts that require less than 8 virtual
registers, then your program need not allocate RAM for the unused registers, and
that RAM may be used for other purposes
SCRIPT LANGUAGE INSTRUCTION SET: (Proposed)
================================
For the instruction parameters below:
	    <dest-all>	  = AUDCx, AUDVx, AUDFx, REG[0-7]
	    <dest>		  = REG[0-7]
	    <src>		   = REG[0-7]
	    <reg>		   = REG[0-7]
	    <value>		 = An immediate 8-bit value.
INSTRUCTION:			    QUICK DESCRIPTION:
------------			    ------------------
DONE					    ; Completed processing for current TV frame.
						    ; Whatever values are in the TIA Audio registers
						    ; are set for the current TV frame. Processing
						    ; continues at the next script instruction on the
						    ; following TV frame.
DURD    <reg>			   ; Decrement <reg>, if (<reg> != 0) then end
						    ; script processing as if the instruction was DONE,
						    ; and repeat this instruction next frame.
						    ; Else, processing proceeds to next instruction.
						    ; Use this instruction to play a fixed note for a
						    ; duration.
MOVR    <dest-all>, <src>   ; Put the value of register <src>, or the
MOVI    <dest-all>, <value> ; immediate <value> into the register <dest>
ADDR    <dest>, <src>	   ; Add the value of register <src>, or the
ADDI    <dest>, <value>	 ; immediate <value> to <dest-reg> and store the
						    ; result in <dest>.
XORR    <dest>, <src>	   ; Perform a bitwise exclusive-OR of the value in
XORI    <dest>, <value>	 ; register <src>, or the immediate <value> with
						    ; the contest of register <dest> and store the
						    ; result in <dest>
ANDR    <dest>, <src>	   ; Perform a bitwise AND of the value stored in
ANDI    <dest>, <value>	 ; register <src>, or the immediate <value> with
						    ; the contest of register <dest> and store the
						    ; result in <dest>
TRUNC   <AUDVx|AUDFx>,<src> ; Truncate the value in <src> and write it to the
						    ; TIA volume or frequency register.  The value in
						    ; <src> is treated as a fixed point value allowing
						    ; fractional volume and frequencies:
						    ;  AUDVx => <src> is 4.4 fixed point value.
						    ;  AUDFx => <src> is 5.3 fixed point value.
						    ;				    | |
						    ;				    | +-> Fraction part is ignored
						    ;				    +---> Integer part written to
						    ;						  the register.
DIV2    <reg>			   ; Divide the value in <reg> by 2, and discard any
						    ; fractional portion. { bitwise shift right one }
GO	  <label-in-bank>	 ; Jump to the given address in the script.
						    ; {MUST BE IN THE SAME MEMORY BANK!}
ONGO    <index-reg>		 ; Use the value in <index-reg> to select a 'GO'
	    GO <index0-label>   ; instruction from the following list. No bounds
	    GO <index1-label>   ; checking is done, so be sure you won't go off
	    GO <index2-label>   ; the end of the list
	    GO <indexN-label>
LKUP    <dest>, <table-label>, <index-reg>
						    ; This is a table lookup instruction.  The value in
						    ; Given: <table-label> = pointer to table in bank.
						    ;	    <index-reg>   = register 0 to 7
						    ; <dest> = value at [<table-label> + <index-reg>]
DECT    <reg>			   ; Decrement <reg>, if <reg> is zero skip the next
						    ; instruction.  Used to build loops by having a
						    ; GO instruction next.
ZERT    <reg>			   ; If <reg> is zero skip the next instruction.
						    ; Used to build loops by having a GO instruction
						    ; next.
CMPR    <reg>, <reg>	    ; Compare a register against another or an
CMPI    <reg>, <value>	  ; immediate value. If <true?> then skip the next
						    ; instruction.