;AY-Voice ----- Thomas Henry ;Last Revision: 6/22/2012 ;****************** Constant Definitions ****************** symbol control = outpinsA ;control lines to the AY chip symbol BC1 = A.0 ;A.0 is BC1 on the AY chip symbol BDIR = A.1 ;A.1 is BDIR on the AY chip symbol bus = outpinsB ;data/address bus to AY chip symbol buttons = pinsC ;C.2-C.5 are arrow buttons ;These are time constants based on a 64 MHz clock. The numbers ;may seem inconsistent since they refer to the pause, pauseus ;or pulsout commands which all use different base units. symbol AYpulse = 4 ;2.5 uSec for pulsout symbol LCDpulse = 8 ;10 uSec for pauseus symbol uSec50 = 40 ;50 uSec for pauseus symbol mSec = 8 ;1 mSec for pause symbol mSec2 = 16 ;2 mSec for pause symbol mSec50 = 400 ;50 mSec for pause symbol mSec200 = 1600 ;200 mSec for pause symbol mSec500 = 4000 ;500 mSec for pause symbol secOne = 8000 ;one second symbol sec3 = 24000 ;3 seconds ;AY-8910 control codes and register addresses symbol inactive = %00000000 ;data/address bus inactive symbol latchAddr = %00000011 ;latch the address on the DA bus symbol Reg7 = %00000111 ;Register 7 - data direction symbol Reg15 = %00001111 ;Register 15 - Port IOB symbol IOBOut = %11111111 ;IOB data direction-out ;Here are various LCD commands which can be used. symbol clrHome = 1 ;clear the display, home the cursor symbol home = 2 ;home the cursor only symbol RtoL = 4 ;print characters right to left symbol insR = 5 ;insert characters to right symbol LtoR = 6 ;print characters left to right symbol insL = 7 ;insert characters to left symbol lcdOff = 8 ;LCD screen off symbol lcdOn = 12 ;LCD screen on, no cursor symbol curOff = 12 ;an alias for the above symbol block = 13 ;LCD screen on, block cursor symbol under = 14 ;LCD screen on, underline cursor symbol undblk = 15 ;blinking and underline cursor symbol panR = 24 ;pan viewing window right symbol panL = 28 ;pan viewing window left symbol mode1 = 32 ;one-line mode (4-bit data) symbol mode2 = 40 ;two-line mode (4-bit data) symbol bus4 = 32 ;4-bit data bus mode symbol bus8 = 48 ;8-bit data bus mode symbol uchar = 64 ;start of user-defined character RAM symbol line1 = 128 ;go to start of line 1 symbol line2 = 192 ;go to start of line 2 symbol unchecked = 0 ;ASCII code for the unchecked box symbol checked = 1 ;ASCII code for the checked box ;arrow button values symbol up = 1 symbol down = 2 symbol left = 3 symbol right = 4 ;the supported MIDI modes symbol mono = 1 symbol omni = 2 symbol noMIDI = 3 ;checkbox flags symbol BoxA = 4 symbol BoxB = 2 symbol BoxC = 1 ;envelope types symbol AR = 1 ;attack/release symbol perc = 2 ;percussive (0 attack) symbol eRev = 3 ;reversed (0 release) symbol trem = 4 ;tremolo (attack = release, repeats) ;tone frequency limits symbol fMin = 32 ;min frequency symbol fMax = 15625 ;nax frequency (Hz) symbol eMin = 0 ;minimum envelope time symbol eMax = 7999 ;maximum envelope time (mS) symbol levelMin = 0 ;minimum voice level symbol levelMax = 15 ;maximum voice level symbol nMin = 0 ;minimum noise frequency symbol nMax = 31 ;maximum noise frequency ;****************** Variable Definitions ****************** symbol bitFlags = w0 ;bit flags ;AY Voice Parameters - do not use for anything else symbol aTime = w1 ;attack time in mSec symbol rTime = w2 ;release time in mSec symbol toneA = w3 ;tone frequency A symbol toneB = w4 ;tone frequency B symbol toneC = w5 ;tone frequency C symbol tEnable = b12 ;tone enable flags symbol nEnable = b13 ;noise enable flags symbol eEnable = b14 ;envelope enable flags symbol aLevel = b15 ;channel A voice level (0-15) symbol bLevel = b16 ;channel B voice level (0-15) symbol cLevel = b17 ;channel C voice level (0-15) symbol envType = b18 ;AR, tremolo, percussive, reverse symbol mode = b19 ;mono, omni, off symbol nFreq = b20 ;noise frequency symbol base = b21 ;base MIDI channel (1 to 13) ;MIDI variables symbol head = w11 ;head of MIDI queue symbol midi = b24 ;message byte to be processed symbol place = b24 ;(alias) decimal place in number symbol dummy = b25 ;setup mode variables - may be reused with care symbol eTime = w13 ;parameter for time print routine symbol toneP = w13 ;(alias) parameter for tone frequency symbol tempW = w14 ;temporary word variable symbol powerW = w14 ;(alias) power of ten symbol numW = w15 ;number-to-ASCII input parameter symbol placeW = w16 ;place value for multiplier symbol pMinW = w17 ;parameter minimum value symbol pMaxW = w18 ;parameter maximum value symbol char = b38 ;ASCII character to be displayed symbol cmd = b38 ;(alias) LCD command byte symbol temp = b39 ;local variable only for subs symbol colSave = b40 ;save old column number symbol chrSave = b40 ;(alias) save current character symbol arrow = b41 ;current arrow button pressed symbol dig4 = b42 ;(local) ten-thousands digit in number symbol dig3 = b43 ;(local) thousands digit in number symbol dig2 = b44 ;(local) hundreds digit in number symbol dig1 = b45 ;(local) tens digit in number symbol dig0 = b46 ;(local) units digit in number symbol row = b47 ;current LCD row symbol col = b48 ;current LCD column symbol i = b49 ;loop variable symbol vLevel = b50 ;level parameter for subroutine symbol digits = b51 ;number of digits in string symbol ABC = b42 ;(alias) 4=box A, 2=box B, 1=box C symbol check = b43 ;(alias) checkbox flag symbol msg = b44 ;(alias) offset into message table symbol value = b45 ;(alias) AY register number (0-15) symbol register = b46 ;(alias) value to store in AY register ;*********************** Messages ************************* eeprom 0, ("AY-VOICE",0) eeprom 9, ("SETUP MENU",0) eeprom 20, ("MIDI MODE",0) eeprom 30, ("MONO",0) eeprom 35, ("OMNI",0) eeprom 40, ("OFF",0) eeprom 44, ("MIDI CHANNEL",0) eeprom 57, ("TONE ENABLE",0) eeprom 69, ("NOISE ENABLE",0) eeprom 82, ("ENVELOPE ENABLE",0) eeprom 98, ("ENVELOPE TYPE",0) eeprom 112,("ATTACK/RELEASE",0) eeprom 127,("PERCUSSIVE",0) eeprom 138,("REVERSE",0) eeprom 146,("TREMOLO",0) eeprom 154,("ENVELOPE TIME",0) eeprom 168,("VOICE LEVELS",0) eeprom 181,("TONE FREQUENCY",0) eeprom 196,("NOISE FREQUENCY",0) eeprom 212,("HIT DOWN TO PLAY",0) ;********************** Main Program ********************** pgm: setfreq em64 ;64 MHz external resonator dirsA = %00001111 ;A.0-A.3 are outputs dirsB = %11111111 ;B.0-B.7 are outputs dirsC = %00000011 ;C.2-C.7 are inputs pwmout C.1,7,16 ;start AY clock at 2 MHz ; hsersetup B31250_64,%00001001 ;turn on MIDI input head = 0 ;initialize queue mode = mono ;mono mode by default base = 0 ;base channel for MIDI envType = AR ;attack/release at the outset toneA = fMin ;tone frequencies at minimum toneB = fMin toneC = fMin gosub init ;initialize AY and LCD gosub init2 ;repeat LCD for security gosub makeChrs ;create user-defined characters ;----- Sign-On Menu ----- menu0: gosub clr ;print heading col = 4 msg = 0 gosub printMsg row = 1 col = 3 msg = 9 ;and the bottom row gosub printMsg do ;wait, can only move right gosub getKey loop while arrow != right ;----- MIDI Mode Menu ----- menu1: gosub clr ;print heading col = 3 msg = 20 gosub printMsg menu1b: select case mode ;print current mode case mono msg = 30 case omni msg = 35 case noMIDI msg = 40 end select gosub clrLine2 gosub printMsg gosub getKey ;read switches if arrow = left then goto menu0 ;go back if arrow = right then goto menu2 ;go to next menu if arrow = up then ;change mode dec mode else inc mode endif if mode < mono then ;circle around mode = noMIDI elseif mode > noMIDI then mode = mono endif goto menu1b ;update new selection ;----- MIDI Channel Menu ----- menu2: gosub clr ;print heading col = 2 msg = 44 gosub printMsg menu2b: for i = 0 to 3 ;four channels used row = 2 col = 4*i gosub locate char = "A" + i ;A, B, C and G if char = "D" then ;change D to G (for gates) char = "G" endif gosub sendChr ;print the label numW = base+i+1 ;MIDI starts channels at zero gosub printNum2 ;print associated channel number next i gosub getKey ;read switches if arrow = left then goto menu1 if arrow = right then goto menu3 if arrow = up then inc base ;augment base channel else dec base ;reduce base channel endif if base > 200 then ;keep in range (200 is negative) base = 0 elseif base > 12 then ;12 is the highest possible base = 12 endif goto menu2b ;then update results ;----- Tone Enable Menu ----- menu3: gosub clr ;print heading col = 2 msg = 57 gosub printMsg check = tEnable ;pass in tone enable flags gosub checkBox tEnable = check ;update them if arrow = left then goto menu2 ;----- Noise Enable Menu ----- menu4: gosub clr ;similar to the tone enables col = 2 msg = 69 gosub printMsg check = nEnable ;pass in noise enable flags gosub checkBox nEnable = check ;update them if arrow = left then goto menu3 ;----- Envelope Enable Menu ----- menu5: gosub clr ;similar to the tone enables msg = 82 gosub printMsg check = eEnable ;pass in envelope enable flags gosub checkBox eEnable = check ;update them if arrow = left then goto menu4 ;----- Envelope Type Menu ----- menu6: if eEnable = 0 then ;no envelopes enabled (A, B or C) goto menu8 ;so skip all envelope stuff endif gosub clr ;otherwise print heading col = 1 msg = 98 gosub printMsg menu6b: select case envType ;print current envelope type case AR msg = 112 case perc msg = 127 case eRev msg = 138 case trem msg = 146 end select gosub clrLine2 gosub printMsg gosub getKey ;read switches if arrow = left then goto menu5 if arrow = right then goto menu7 if arrow = up then ;change envelope type dec envType else inc envType endif if envType < AR then ;circle around the choices envType = trem elseif envType > trem then envType = AR endif goto menu6b ;update new selection ;----- Envelope Time Menu ----- menu7: gosub clr ;print heading col = 2 msg = 154 gosub printMsg select case envType ;set the defaults case perc aTime = 0 ;percussive is 0 attack case eRev rTime = 0 ;reversed is 0 release case trem if aTime > rTime then ;tremolo has A = R rTime = aTime ;choose the larger of the two else aTime = rTime endif end select gosub printTimes ;print current times if envtype = perc then ;0 attack for percussive goto menu7c ;so go directly to release endif menu7b: ;do attack time col = 2 eTime = aTime ;pass in current time gosub getTime ;get attack time aTime = eTime ;and update it if arrow = left then ;back to previous menu goto menu6 endif if envType = eRev then ;skip release for reversed goto menu8 endif if envType = trem then ;tremolo mode:A = R rTime = aTime ;just copy attack time goto menu8 endif menu7c: ;do release time col = 12 eTime = rTime ;pass in current time gosub getTime ;get release time rTime = eTime ;and update it if arrow = right then ;go to next menu goto menu8 endif if envType = perc then ;skip attack for percussive goto menu6 else goto menu7 endif ;----- Voice Levels Menu ----- menu8: gosub clr ;print heading col = 2 msg = 168 gosub printMsg gosub printLevels ;print current levels menu8b: col = 2 ;do Voice A vLevel = aLevel gosub getLevel aLevel = vLevel if arrow = left then if eEnable = 0 then ;no envelopes enabled goto menu5 ;go back to envelope enable else goto menu7 ;else go back to envelope times endif endif menu8c: col = 8 ;do Voice B vLevel = bLevel gosub getLevel bLevel = vLevel if arrow = left then goto menu8b endif col = 14 ;do Voice C vLevel = cLevel gosub getLevel cLevel = vLevel if arrow = left then goto menu8c endif ;----- Tone Frequency Menus ----- menu9: gosub clr ;print the heading msg = 181 gosub printMsg menu9b: gosub printA ;do Voice A row = 1 col = 0 gosub locate toneP = toneA ;pass in old value gosub getFreq ;get new value toneA = toneP ;and update it if arrow = left then ;back to previous menu goto menu8 endif menu9c: gosub printB ;do Voice B row = 1 col = 0 gosub locate toneP = toneB ;pass in old value gosub getFreq ;get new value toneB = numW ;and update it if arrow = left then ;back to previous menu goto menu9b endif gosub printC ;do Voice C row = 1 col = 0 gosub locate toneP = toneC ;pass in old value gosub getFreq ;get new value toneC = numW ;and update it if arrow = left then ;back to previous menu goto menu9C endif ;----- Noise Frequency Menu ----- menu10: gosub clr ;print the heading msg = 196 gosub printMsg gosub clrLine2 ;print current value numW = nFreq gosub printNum2 col = 0 digits = 2 ;a two-digit number pMinW = nMin pMaxW = nMax gosub getNum ;get new value nFreq = numW ;update the frequency ;----- Play Menu ----- menu11: gosub clr ;display heading msg = 212 gosub printMsg menu11b: gosub getKey ;read the switches if arrow = left then goto menu10 ;previous menu endif if arrow = right then goto menu1 ;circle back to first endif goto menu11b ;ignore all others for now end ;end of main program ;************************************************************* ;* * ;* Initialize AY and LCD on power-up * ;* Input parameters: none * ;* Output parameters: none * ;* Local variables: none * ;* * ;************************************************************* init: pause mSec50 ;let LCD settle for 50 mS at power-up control = inactive ;clear BC1, BDIR ;set up the AY Port IOB for output control = latchAddr ;latch address to register 7 bus = Reg7 control = inactive bus = IOBOut ;make Port IOB all outputs pulsout BDIR,AYpulse init2: control = latchAddr ;latch address to register 15 bus = Reg15 control = inactive bus = %00100011 ;set to 8-bit mode pulsout BDIR,AYPulse bus = %00000011 pulsout BDIR,AYPulse pauseus uSec50 cmd = bus4 ;switch to 4-bit mode now gosub sendCmd pauseus uSec50 cmd = bus4 ;manufacturer recommends redundancy gosub sendCmd pauseus uSec50 cmd = lcdOn ;display on, no arrow gosub sendCmd pauseus uSec50 cmd = clrHome ;clear display gosub sendCmd pause mSec2 char = LtoR ;print left to right by default gosub sendCmd pauseus uSec50 char = mode2 ;two line mode gosub sendCmd pauseus uSec50 return ;************************************************************* ;* * ;* Send a Character to the LCD, RS must be high * ;* Input parameters: char * ;* Output parameters: none * ;* Local variables: temp * ;* * ;************************************************************* sendChr: control = latchAddr ;latch address mode bus = Reg15 ;access Port IOB control = inactive ;address now latched temp = char >> 4 ;shift high nibble right bus = temp | %00110000 ;Enable high (and RS) pulsout BDIR,AYpulse ;latch data pause LCDpulse ;keep high for 200 uS bus = temp | %00010000 ;Enable low, RS still high pulsout BDIR,AYpulse ;latch data temp = char & %00001111 ;grab low nibble bus = temp | %00110000 ;Enable high,RS high pulsout BDIR,AYPulse ;latch data pause LCDpulse bus = temp | %00010000 ;Enable low pulsout BDIR,AYPulse ;latch data return ;************************************************************* ;* * ;* Send a command to the LCD, RS must be low * ;* Input parameters: cmd * ;* Output parameters: none * ;* Local variables: temp * ;* * ;************************************************************* sendCmd: control = latchAddr ;latch address mode bus = Reg15 ;access Port IOB control = inactive ;address now latched temp = cmd >> 4 ;shift high nibble right bus = temp | %00100000 ;Enable high,RS low pulsout BDIR,AYpulse ;latch data pause LCDpulse bus = temp ;Enable low, RS still low pulsout BDIR,AYpulse ;latch data temp = char & %00001111 ;grab low nibble bus = temp | %00100000 ;Enable high,RS low pulsout BDIR,AYPulse ;latch data pause LCDpulse bus = temp ;Enable low, RS still low pulsout BDIR,AYPulse ;latch data pause mSec ;commands take longer return ;************************************************************* ;* * ;* Clear LCD and home cursor * ;* Input parameters: none * ;* Output parameters: row=0, col=0 * ;* Local variables: none * ;* * ;************************************************************* clr: cmd = clrHome ;clear display and home cursor gosub sendCmd pause mSec2 ;clear LCD takes longer to execute row = 0 col = 0 return ;************************************************************* ;* * ;* Clear line two only * ;* Input parameters: none * ;* Output parameters: row=1, col=0 * ;* Local variables: i * ;* * ;************************************************************* clrLine2: cmd = line2 ;put cursor on second row gosub sendCmd char = " " ;blank it out for i = 1 to 16 gosub sendChr next i row = 1 ;put cursor at start of row col = 0 gosub locate return ;************************************************************* ;* * ;* Create the two user-defined characters * ;* Input parameters: none * ;* Output parameters: none * ;* Local variables: i * ;* * ;************************************************************* makeChrs: cmd = uchar ;point to start of user character RAM gosub sendCmd char = %00000 ;unchecked box gosub sendChr char = %11111 gosub sendChr char = %10001 for i = 1 to 3 gosub sendChr next i char = %11111 gosub sendChr char = %00000 gosub sendChr gosub sendChr gosub sendChr ;checked box char = %11111 for i = 1 to 5 gosub sendChr next i char = %00000 gosub sendChr gosub sendChr return ;************************************************************* ;* * ;* Place the cursor in desired location * ;* Input parameters: row, col * ;* Output parameters: none * ;* Local variables: temp * ;* * ;************************************************************* locate: if row = 0 then ;choose the row temp = line1 else temp = line2 endif cmd = temp+col ;factor in the column gosub sendCmd return ;************************************************************* ;* * ;* Print message to the LCD * ;* Input parameters: msg, row, col * ;* Output parameters: none * ;* Local variables: none * ;* * ;************************************************************* printMsg: gosub locate read msg,char ;prime the loop do while char != 0 ;null terminates the string gosub sendChr inc msg read msg,char loop return ;************************************************************* ;* * ;* Print a two-digit number * ;* Input parameters: numW * ;* Output parameters: none * ;* Local variables: dig4, dig3, dig2, dig1, dig0 * ;* * ;************************************************************* printNum2: bintoASCII numW,dig4, dig3, dig2, dig1, dig0 goto printNum5c ;************************************************************* ;* * ;* Print a four-digit number * ;* Input parameters: numW * ;* Output parameters: none * ;* Local variables: dig4, dig3, dig2, dig1, dig0 * ;* * ;************************************************************* printNum4: bintoASCII numW,dig4, dig3, dig2, dig1, dig0 goto printNum5b ;************************************************************* ;* * ;* Print a five-digit number * ;* Input parameters: numW * ;* Output parameters: none * ;* Local variables: dig4, dig3, dig2, dig1, dig0 * ;* * ;************************************************************* printNum5: bintoASCII numW,dig4, dig3, dig2, dig1, dig0 char = dig4 gosub sendChr printNum5b: char = dig3 gosub sendChr char = dig2 gosub sendChr printNum5c: char = dig1 gosub sendChr char = dig0 gosub sendChr return ;************************************************************* ;* * ;* Print single envelope time * ;* Input parameters: eTime, char (A or R) * ;* Output parameters: none * ;* Local variables: numW * ;* * ;************************************************************* printTime: gosub sendChr ;print the letter label char = ":" gosub sendChr numW = eTime gosub printNum4 ;0000 to 7999 milliseconds return ;************************************************************* ;* * ;* Print both envelope times * ;* Input parameters: none * ;* Output parameters: none * ;* Local variables: eTime * ;* * ;************************************************************* printTimes: gosub clrLine2 ;print attack time char = "A" eTime = aTime gosub printTime col = 10 ;print release time gosub locate char = "R" eTime = rTime gosub printTime return ;************************************************************* ;* * ;* Get an envelope time * ;* Input parameters: eTime, col * ;* Output parameters: eTime, arrow (L/R only) * ;* Local variables: digits, numW, pMaxW, pMinW * ;* * ;************************************************************* getTime: gosub locate ;sit on leftmost digit getTime1: numW = eTime ;show current time gosub printNum4 ;print it digits = 4 ;four digit number input pMaxW = eMax ;max envelope time in mS pMinW = eMin ;min envelope time in mS gosub getNum ;fetch new number eTime = numW ;update new result return ;************************************************************* ;* * ;* Display Voice Levels * ;* Input parameters: none * ;* Output parameters: none * ;* Local variables: none * ;* * ;************************************************************* printLevels: gosub clrLine2 char = "A" gosub sendChr ;print the channel letter char = ":" gosub sendChr ;then a colon numW = aLevel gosub printNum2 ;and finally the level char = " " ;two spaces gosub sendChr gosub sendChr char = "B" ;repeat for B gosub sendChr char = ":" gosub sendChr numW = bLevel gosub printNum2 char = " " gosub sendChr gosub sendChr char = "C" ;and now C gosub sendChr char = ":" gosub sendChr numW = cLevel gosub printNum2 return ;************************************************************* ;* * ;* Get a Voice Level * ;* Input parameters: vLevel, row, col * ;* Output parameters: vLevel, arrow (L/R) * ;* Local variables: numW, digits, pMinW, pMaxW * ;* * ;************************************************************* getLevel: gosub locate ;locate on the tens digit cmd = block ;blink cursor gosub sendCmd numW = vLevel ;pass in current value digits = 2 ;a two-digit number only pMinW = levelMin pMaxW = levelMax gosub getNum ;get new value vLevel = numW ;update the level return ;************************************************************* ;* * ;* Get a Voice Frequency * ;* Input parameters: toneP, row, col * ;* Output parameters: toneP, arrow (L/R) * ;* Local variables: numW, digits, pMinW, pMaxW * ;* * ;************************************************************* getFreq: gosub clrLine2 ;print current value numW = toneP gosub printNum5 char = " " gosub sendChr char = "H" gosub sendChr char = "z" gosub sendChr col = 0 digits = 5 ;a five-digit number pMinW = fMin pMaxW = fMax gosub getNum ;get new value toneP = numW ;update the frequency return ;*************************************************************** ;* * ;* Get a decimal digit * ;* Input parameters: numW, col, digits, place, pMaxW, pMinW * ;* Output parameters: numW, arrow (L/R only) * ;* Local variables: powerW, i * ;* * ;*************************************************************** ; ;digits = how many digits in the number ;place = which digit to work on (1=units, 2=hundreds, etc.) ;col = position of leftmost digit in the number getDigit: colSave = col ;save start of number pointer getDigit2: col = col + digits - place gosub locate ;place cursor on digit powerW = 1 ;create power of ten i = place do while i > 1 powerW = 10 * powerW dec i loop gosub getKey if arrow = left then ;exit and go to previous goto getDigit3 endif if arrow = right then ;exit and go to next goto getDigit3 endif if arrow = up then ;else change number numW = numW + powerW else if numW >= powerW then ;safe to decrement numW = numW - powerW min pMinW endif endif if numW > pMaxW then ;got too big numW = numW - powerW ;so undo endif col = colSave ;restore column pointer gosub locate ;update the display if digits = 5 then gosub printNum5 elseif digits = 4 then gosub printNum4 else gosub printNum2 endif goto getDigit2 getDigit3: col = colSave return ;************************************************************* ;* * ;* Get a two, four or five digit number * ;* Input parameters: numW, col, digits, pMaxW, pMinW * ;* Output parameters: numW, arrow (L/R only) * ;* Local variables: place * ;* * ;************************************************************* getNum: cmd = block ;blink the cursor gosub sendCmd if digits = 4 then ;handle four digits goto getNum2 elseif digits = 2 then ;or two digits goto getNum4 endif ;otherwise five digits getNum1: place = 5 ;handle 10000s digit gosub getDigit if arrow = left then ;exit and go to previous menu goto getNum6 endif if arrow = right then ;go to next digit goto getNum2 endif goto getNum1 getNum2: place = 4 ;handle 1000s digit gosub getDigit if arrow = left then if digits = 5 then goto getNum1 ;5 digits, previous digit else goto getNum6 ;4 digits, previous menu endif endif if arrow = right then ;go to next digit goto getNum3 endif goto getNum2 getNum3: place = 3 ;handle 100s digit gosub getDigit if arrow = left then ;exit and go to previous digit goto getNum2 endif if arrow = right then ;go to next digit goto getNum4 endif goto getNum3 getNum4: place = 2 ;handle 10s digit gosub getDigit if arrow = left then if digits > 2 then goto getNum3 ;5 or 4 digits, previous digit else goto getNum6 ;2 digits, previous menu endif endif if arrow = right then ;go to next digit goto getNum5 endif goto getNum4 getNum5: place = 1 ;handle ones digit gosub getDigit if arrow = left then ;exit and go to previous digit goto getNum4 endif if arrow = right then ;go to next menu goto getNum6 endif goto getNum5 getNum6: cmd = curOff gosub sendCmd return ;************************************************************* ;* * ;* Do the checkboxes * ;* Input parameters: check * ;* Output parameters: check, arrow (L/R only) * ;* Local variables: ABC, temp * ;* * ;************************************************************* checkbox: ABC = BoxA checkbox2: row = 1 ;start with A col = 0 gosub locate temp = check & BoxA if temp = BoxA then char = checked else char = unchecked endif gosub sendChr ;print box char = "A" gosub sendChr col = 7 ;now do B gosub locate temp = check & BoxB if temp = BoxB then char = checked else char = unchecked endif gosub sendChr char = "B" gosub sendChr col = 14 ;then do C gosub locate temp = check & BoxC if temp = BoxC then char = checked else char = unchecked endif gosub sendChr char = "C" gosub sendChr select case ABC ;position the cursor case BoxA cmd = line2 case BoxB cmd = line2+7 case BoxC cmd = line2+14 end select gosub sendCmd ;and blink it cmd = block gosub sendCmd gosub getKey ;read the arrow keys select case arrow case up, down check = check xor ABC ;toggle the select bit case left ABC = ABC << 1 ;move to previous case right ABC = ABC >> 1 ;move to next end select if arrow = up then goto checkbox2 if arrow = down then goto checkbox2 if ABC > BoxA then goto checkbox3 ;change of menu if ABC < BoxC then goto checkbox3 ;ditto goto checkbox2 checkbox3: cmd = curOff ;turn off the cursor gosub sendCmd return ;************************************************************* ;* * ;* Wait for and fetch arrow keystroke * ;* Input parameters: none * ;* Output parameters: arrow * ;* Local variables: temp * ;* * ;************************************************************* getKey: temp = not buttons ;read switch port temp = temp >> 2 ;shift into lowest part of byte temp = temp & %00001111 ;mask off junk above select case temp ;covert to simple form case 1 arrow = up case 2 arrow = down case 4 arrow = left case 8 arrow = right else ;more than one or arrow = 0 ;no buttons pressed end select if arrow = 0 then ;loop until pressed goto getKey endif pause mSec50 ;pause for debounce do ;wait for open switches temp = not buttons ;read switch port temp = temp >> 2 ;shift into lowest part of byte temp = temp & %00011111 ;mask off junk above loop while temp != 0 return ;************************************************************* ;* * ;* Send Value to AY Register * ;* Input parameters: register, value * ;* Output parameters: none * ;* Local variables: none * ;* * ;************************************************************* store: control = inactive ;clear BC1, BDIR control = latchAddr ;latch address of register bus = register control = inactive bus = value ;get value and pulsout BDIR,AYPulse ;store it return ;************************************************************* ;* * ;* Print A, B or C Labels * ;* Input parameters: register, value * ;* Output parameters: none * ;* Local variables: temp * ;* * ;************************************************************* printA: chrSave = "A" goto printLetter printB: chrSave = "B" goto printLetter printC: chrSave = "C" printLetter: row = 0 col = 15 gosub locate char = chrSave gosub sendChr return