diff --git a/software/6502_terminal_propeller/6502_terminal.binary b/software/6502_terminal_propeller/6502_terminal.binary new file mode 100644 index 0000000..e1b9b28 Binary files /dev/null and b/software/6502_terminal_propeller/6502_terminal.binary differ diff --git a/software/6502_terminal_propeller/6502_terminal.spin b/software/6502_terminal_propeller/6502_terminal.spin new file mode 100644 index 0000000..be7a398 --- /dev/null +++ b/software/6502_terminal_propeller/6502_terminal.spin @@ -0,0 +1,680 @@ +'''''''''''''''''''''''''''''' +'' 6502 Terminal Program '' +'' Author: Jon Thomasson '' +'' 2016 The Reset Vector '' +'' '' +'''''''''''''''''''''''''''''' +'' +'' Current VT-100 Code list +'' +'' ESC[m Turn off character attributes +'' ESC[0m Turn off character attributes +'' ESC[1m Turn bold character on (reverse) +'' ESC[7m Turn reverse video on +'' ESC[nA Move cursor up n lines +'' ESC[nB Move cursor down n lines +'' ESC[nC Move cursor right n lines +'' ESC[nD Move cursor left n lines +'' ESC[H Move cursor to upper left corner +'' ESC[;H Move cursor to upper left corner +'' ESC[line;columnH Move cursor to screen location v,h +'' ESC[f Move cursor to upper left corner +'' ESC[;f Move cursor to upper left corner +'' ESC[line;columnf Move cursor to sceen location v,h +'' ESCD Move/scroll window up one line +'' ESC[D Move/scroll window up one line +'' ESCL Move/scroll window up one line (undocumented) +'' ESC[L Move/scroll window up one line (undocumented) +'' ESCM Move/scroll window down one line +'' ESCK Clear line from right +'' ESC[0K Clear line from right +'' ESC[1K Clear line from left +'' ESC[2K Clear entire line +'' ESC[J Clear screen from down +'' ESC[0J Clear screen from down +'' ESC[1J Clear screen from up +'' ESC[2J Clear entire screen +'' ESC[0c Terminal ID responds with [?1;0c for VT-100 no options +'' ESC[c Terminal ID responds with [?1;0c for VT-100 no options +'' Esc[value@ Insert one character +'' Esc[valueP Delete one character +'' +'' List of ignored codes +'' +'' ESC[xxh All of the ESC[20h thru ESC[?9h commands +'' ESC[xxl All of the ESC[20i thru ESC[?9i commands +'' ESC= Alternate keypad mode +'' ESC< Enter/Exit ANSI mode +'' ESC> Exit Alternate keypad mode +'' Esc5n Device status report DSR +'' Esc0n Response: terminal is OK DSR +'' Esc3n Response: terminal is not OK DSR +'' Esc6n Get position DSR +'' EscLine;ColumnR Response: is at v,h CPR +'' Esc#8 Screen alignment display DECALN +'' Esc[2;1y Confidence power up test DECTST +'' Esc[2;2y Confidence loopback test DECTST +'' Esc[2;9y Repeat power up test DECTST +'' Esc[2;10y Repeat loopback test DECTST +'' Esc[0q Turn off all four leds DECLL0 +'' Esc[1q Turn on LED #1 DECLL1 +'' Esc[2q Turn on LED #2 DECLL2 +'' Esc[3q Turn on LED #3 DECLL3 +'' Esc[4q Turn on LED #4 DECLL4 + + +CON + + _clkmode = xtal1 + pll16x + _xinfreq = 5_000_000 + + Cursor = 95 + VideoCls = 0 + NUM = %100 + CAPS = %010 + SCROLL = %001 + RepeatRate = 40 + video = 16 + backspace = $C8 + RESET = 5 'pin used to reset 6502 + RESET_PERIOD = 20_000_000 '1/2 second + +' VT-100 values + +'' Terminal Colors + TURQUOISE = $29 + BLUE = $27 + BABYBLUE = $95 + RED = $C1 + GREEN = $99 + GOLDBROWN = $A2 + AMBERDARK = $E2 + LAVENDER = $A5 + WHITE = $FF + HOTPINK = $C9 + GOLD = $D9 + PINK = $C5 + + + r1 = 31 'PC serial port receive line + t1 = 30 'PC serial port transmit line + r2 = 25 'Host device receive line + t2 = 24 'Host device transmit line + + EEPROMAddr = %1010_0000 + EEPROM_Base = $7FE0 + i2cSCL = 28 + +'' Sound Variables + + right = 10 + left = 11 + +OBJ + + text: "VGA_1024v.905" ' VGA Terminal Driver + kb: "keyboard" ' Keyboard driver + ser: "FullDuplexSerial256" ' Full Duplex Serial Controller + ser2: "FullDuplexSerial2562" ' 2nd Full Duplex Serial Controller + i2c: "basic_i2c_driver" +VAR + + word key + Byte Index + Byte Rx + Byte rxbyte +' Long Stack[100] + Byte temp + Byte serdata + Long Baud + Byte termcolor + Long BR[8] + Long CLR[11] + long i2cAddress, i2cSlaveCounter + Byte pcport + Byte ascii + Byte curset + word eepromLocation + Byte CR + Byte LNM +PUB main | i,j,k,remote,remote2,record,vt100,byte2,byte3,byte1,byte4,byte5,byte6,byte7,loop,var1,col,row,temp2,tempbaud,source + + + + + CTRA:= %00110 << 26 + 0<<9 + right + CTRB:= %00110 << 26 + 0<<9 + left + DIRA[right]~~ 'Set Right Pin to output + DIRA[left]~~ 'Set Left Pin to output + source:=@PIANO + LNM := 0 'CR only sent + i2c.Initialize(i2cSCL) + tempbaud:=5 + CR := 0 '0= OFF 1 = CR AND LF + ascii := 0 '0=no 1=yes + pcport := 1 '1=pc port off, 2=on + termcolor:=5 + curset := 5 + BR[0]:=300 + BR[1]:=1200 + BR[2]:=2400 + BR[3]:=4800 + BR[4]:=9600 + BR[5]:=19200 + BR[6]:=38400 + BR[7]:=57600 + BR[8]:=115200 + CLR[1]:=TURQUOISE + CLR[2]:=BLUE + CLR[3]:=BABYBLUE + CLR[4]:=RED + CLR[5]:=GREEN + CLR[6]:=GOLDBROWN + CLR[7]:=WHITE + CLR[8]:=HOTPINK + CLR[9]:=GOLD + CLR[10]:=PINK + CLR[11]:=AMBERDARK + +'' Determine if previous settings are stored in EEPROM, if so, retrive for user + eepromLocation := EEPROM_Base 'Point i2c to EEPROM storage + temp2 := i2c.ReadByte(i2cSCL, EEPROMAddr, eepromLocation) 'read test byte to see if data stored + if temp2 == 55 'we have previously recorded settings, so restore them + eepromLocation +=4 'increase to next location + tempbaud := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read Baud as temp + eepromLocation +=4 + termcolor := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read terminal color + eepromLocation +=4 + pcport := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read pcport on/off setting + eepromLocation +=4 + ascii := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read force 7bit setting + eepromLocation +=4 + curset := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read type + eepromLocation +=4 + CR := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read CR W/LF ON/OFF + waitcnt(clkfreq/200 + cnt) + + + + + Baud:=BR[tempbaud] + text.start(video) + text.color(CLR[termcolor]) + kb.startx(26, 27, NUM, RepeatRate) 'Start Keyboard Driver + ser.start(r1,t1,0,baud) 'Start Port2 to PC + ser2.start(r2,t2,0,baud) 'Start Port1 to main device + Baud:=tempbaud + text.cls(Baud,termcolor,pcport,ascii,CR) +' text.clsupdate(Baud,termcolor,pcport,ascii,CR) + text.inv(0) + text.cursorset(curset) + vt100:=0 + +' send reset to 6502 + outa[RESET] := 0 + dira[RESET] := 1 'set reset pin as output + waitcnt(RESET_PERIOD + cnt) + outa[RESET] := 1 + dira[RESET] := 1 + waitcnt(RESET_PERIOD + cnt) + dira[RESET] := 0 'set reset pin as input (this makes it so the pin isn't held low forever) + + repeat + key := kb.key 'Go get keystroke, then return here + + if key == 194 'up arrow + ser2.str(string(27,"[A")) + if key == 195 'down arrow + ser2.str(string(27,"[B")) + 'ser2.out($0A) + if key == 193 'right arrow + ser2.str(string(27,"[C")) + if key == 192 'left arrow + ser2.str(string(27,"[D")) + + if key >576 + if key <603 + key:=key-576 + if key > 608 and key < 635 'Is it a control character? + key:=key-608 + 'if key >0 + ' text.dec(key) + if key == 200 + key:=08 + if key == 203 'Is it upper code for ESC key? + key:= 27 'Yes, convert to standard ASCII value + if key == 720 + Baud++ 'is ESC then + then increase baud or roll over + if Baud > 8 + Baud:=0 + temp:=Baud + Baud:=BR[temp] + ser.stop + ser2.stop + ser.start(r1,t1,0,baud) 'ready port for PC + ser2.start(r2,t2,0,baud) 'ready port for HOST + Baud:=temp + text.clsupdate(Baud,termcolor,pcport,ascii,CR) + EEPROM + if key == 721 + if ++termcolor > 11 + termcolor:=1 + text.color(CLR[termcolor]) + 'text.clsupdate(Baud,termcolor,pcport,ascii) + EEPROM + if key == 722 + if pcport == 1 + pcport := 0 + else + pcport := 1 + text.clsupdate(Baud,termcolor,pcport,ascii,CR) + EEPROM + if key == 723 + if ascii == 0 + ascii := 1 + else + ascii :=0 + text.clsupdate(Baud,termcolor,pcport,ascii,CR) + EEPROM + if key == 724 + curset++ + if curset > 7 + curset := 1 + text.cursorset(curset) + EEPROM + if key == 725 'F6 + if CR == 1 + CR := 0 + else + CR := 1 + text.clsupdate(Baud,termcolor,pcport,ascii,CR) + EEPROM + if key <128 and key > 0 'Is the keystroke PocketTerm compatible? was 96 + ser2.tx(key) 'Yes, so send it + if key == 13 + 'this probably needs to be if CR == 1 + if LNM == 1 or CR == 1'send both CR and LF? + ser2.tx(10) 'yes, set by LNM ESC command, send LF also + + + +'' END keyboard console routine + + + +'LOOK FOR SERIAL INPUT HERE + if pcport == 0 'Is PC turned on at console for checking? + remote2 := ser.rxcheck 'Yes, look at the port for data + if (remote2 > -1) 'remote = -1 if no data + ser2.tx(remote2) 'Send the data out to the host device + waitcnt(clkfreq/200 + cnt) 'Added to attempt eliminate dropped characters + remote := ser2.rxcheck 'Look at host device port for data + if (remote > -1) + if ascii == 1 'yes force 7 bit ascii + if (remote > 127) + remote := remote -128 + if pcport == 0 + ser.tx(remote) +'Start of VT100 code + if remote == 27 'vt100 ESC code is being sent + vt100:=1 + byte1:=0 + byte2:=0 + byte3:=0 + byte4:=0 + byte5:=0 + byte6:=0 + byte7:=0 + remote:=0 + temp2:=0 'Don't display the ESC code + if remote == 99 and vt100 == 1 'ESC c + remote:=0 + vt100:=0 + text.inv(0) + text.cls(Baud,termcolor,pcport,ascii,CR) + text.home + + if remote == 61 and vt100 == 1 'lool for ESC= + vt100:= remote := 0 + + + 'put ESC D and ESC M here + if remote == 77 and vt100 == 1 'AKA ESC M + text.scrollM + vt100 := 0 + if remote == 68 and vt100 == 1 'AKA ESC D + if byte2 <> 91 and byte3 <> 91 and byte4 <> 91 'not esc[D + 'text.scrollD + vt100 := 0 + if remote == 76 and vt100 == 1 'AKA ESC L + if remote == 91 and vt100 == 1 'look for open bracket [ + vt100:=2 'start recording code + if remote == 62 and vt100 == 1 or remote == 60 and vt100 == 1 'look for < & > + vt100:=0 ' not sure why this is coming up, can't find in spec. + if vt100==2 ''Check checking for VT100 emulation codes + if remote > 10 + byte7:=byte6 + byte6:=byte5 ' My VTCode Mini Buffer + byte5:=byte4 + byte4:=byte3 + byte3:=byte2 'Record the last 7 bytes + byte2:=byte1 + byte1:=remote + + if remote == 109 'look for lowercase m + if byte2 == 91 'if [m turn off to normal set + text.inv(0) + vt100:=0 + if byte2 == 49 and vt100 > 0 'is it ESC[1m BOLD + 'text.inv(1) + vt100 := 0 + if byte2 == 55 and vt100 > 0 'is it ESC[7m? + text.inv(1) + vt100 := 0 + if byte2 == 48 and vt100 > 0 '0 is back to normal + text.inv(0) + vt100:=0 + if byte2 == 52 and vt100 > 0 'is it ESC[4m underline? + vt100:=0 'yes ignore + if byte2 == 50 and vt100 >0 'is it ESC[2m dim text + vt100:=0 'yes ignore + if remote == 64 'look for ESC[value@ @=64 insert value spaces + if byte4 == 91 'two digit value + byte3:=byte3-48 'Grab 10's + byte2:=byte2-48 'Grab 1's + byte3:=byte3*10 'Multiply 10's + byte3:=byte3+byte2 'Add 1's + text.insertat(byte3) + if byte3 == 91 'single digit value + byte2:=byte2-48 + text.insertat(byte2) + vt100 :=0 + if remote == 80 'look for ESC[valueP P=64 delete value spaces + if byte4 == 91 'two digit value + byte3:=byte3-48 'Grab 10's + byte2:=byte2-48 'Grab 1's + byte3:=byte3*10 'Multiply 10's + byte3:=byte3+byte2 'Add 1's + text.delp(byte3) + if byte3 == 91 'single digit value + byte2:=byte2-48 + text.delp(byte2) + vt100 :=0 + if remote == 104 'look for lowercase h set CR/LF mode + if byte2 == 48 'if character before h is 0 maybe command is 20h + if byte3 == 50 'if byte3 then it is for sure 20h + LNM := 0 + vt100:=0 + + if remote == 61 'lool for = + vt100:=0 + + if remote == 114 'look for lowercase r + vt100:=0 + + if remote == 108 'look for lowercase l + if byte2 == 48 'if character before l is 0 maybe command is 20l + if byte3 == 50 'if byte3 then it is for sure 20l + LNM := 1 '0 means CR/LF in CR mode only + vt100:=0 + + if remote == 62 'look for > + vt100:=0 + if remote == 77 'ESC M look for obscure scroll window code + text.scrollM + vt100:=0 + if remote == 68 or remote == 76 ' look for ESC D or ESC L + text.scrollD + vt100:=0 + if remote == 72 or remote == 102 ' HOME CURSOR (uppercase H or lowercase f) + if byte2==91 or byte2==59 'look for [H or [;f + text.home + vt100:=0 + '' Check for X & Y with [H or ;f - Esc[Line;ColumnH + + else 'here remote is either H or f + if byte4 == 59 'is col is greater than 9 ; ALWAYS if byte4=59 + byte3:=byte3-48 'Grab 10's + byte2:=byte2-48 'Grab 1's + byte3:=byte3*10 'Multiply 10's + byte3:=byte3+byte2 'Add 1's + col:=byte3 'Set cols + + if byte7 == 91 'Assume row number is greater than 9 if ; at byte 4 and [ at byte 7 greater than 9 + byte6:=byte6-48 'Grab 10's + byte5:=byte5-48 'Grab 1's + byte6:=byte6*10 'Multiply 10's + byte6:=byte6+byte5 'Add 1's + row:=byte6 + + if byte6 == 91 'Assume row number is less than 10 + byte5:=byte5 - 48 'Grab 1's + row:=byte5 + + if byte3 == 59 ' Assume that col is less an 10 + byte2:=byte2-48 'Grab 1's + col:=byte2 'set cols + + if byte6 == 91 'Assume row number is greater than 9 + byte5:=byte5-48 'Grab 10's + byte4:=byte4-48 'Grab 1's + byte5:=byte5*10 'Multiply 10's + byte5:=byte5+byte4 'Add 1's + row:=byte5 + if byte5 == 91 'Assume that col is greater than 10 + byte4:=byte4-48 'Grab 1's + row:=byte4 + + col:=col-1 + if row == -459 + row:=1 + if col == -40 ' Patches a bug I havn't found. *yet* + col := 58 ' A Microsoft approach to the problem. :) + if row == -449 + row := 2 ' Appears to be an issue with reading + if row == -439 ' single digit rows. + row := 3 + if row == -429 ' This patch checks for the bug and replaces + row := 4 ' the faulty calculation. + if row == -419 + row := 5 ' Add to list to find the source of bug later. + if row == -409 + row := 6 + if row == -399 + row := 7 + if row == -389 + row := 8 + if row == -379 + row := 9 + row-- + + + if row < 0 + row:=0 + if col < 0 + col:=0 + if row > 35 + row :=35 + if col > 79 + col := 79 + text.cursloc(col,row) + vt100:=0 + if remote == 114 'ESCr + + text.out(126) + if remote == 74 '' CLEAR SCREEN + if byte2==91 '' look for [J '' clear screen from cursor to 25 + text.clsfromcursordown + 'vt100:=0 + if byte2==50 '' look for [2J '' clear screen + text.cls(Baud,termcolor,pcport,ascii,CR) + if byte2==49 'look for [1J + text.clstocursor + if byte2==48 'look for [0J + text.clsfromcursordown + vt100:=0 + if remote == 66 '' CURSOR DOWN Esc[ValueB + if byte4 == 91 '' Assume number over 10 + byte3:=byte3-48 + byte2:=byte2-48 + byte3:=byte3*10 + byte3:=byte3+byte2 + var1:=byte3 + if byte3 == 91 '' Assume number is less 10 + byte2:=byte2-48 + var1:=byte2 + if byte2 == 91 ''ESC[B no numbers move down one + 'text.out($C3) + var1 := 1 + loop:=0 + repeat until loop == var1 + loop++ + text.out($C3) + + vt100:=0 + + + if remote == 65 '' CURSOR UP Esc[ValueA + if byte4 == 91 '' Assume number over 10 + byte3:=byte3-48 + byte2:=byte2-48 + byte3:=byte3*10 + byte3:=byte3+byte2 + var1:=byte3 + if byte3 == 91 '' Assume number is less 10 + byte2:=byte2-48 + var1:=byte2 + if byte2 == 91 ''ESC[A no numbers move down one + + var1 := 1 + loop:=0 + repeat until loop == var1 + text.out($C2) + loop++ + vt100:=0 + + + if remote == 67 '' CURSOR RIGHT Esc[ValueC + if byte4 == 91 '' Assume number over 10 + byte3:=byte3-48 + byte2:=byte2-48 + byte3:=byte3*10 + byte3:=byte3+byte2 + var1:=byte3 + if byte3 == 91 '' Assume number is less 10 + byte2:=byte2-48 + var1:=byte2 + if byte2 == 91 ''ESC[C no numbers move RIGHT one + + var1 := 1 + loop:=0 + repeat until loop == var1 + text.out($C1) + loop++ + vt100:=0 + + if remote == 68 '' CURSOR LEFT Esc[ValueD OR ESC[D + if byte4 == 91 '' Assume number over 10 + byte3:=byte3-48 + byte2:=byte2-48 + byte3:=byte3*10 + byte3:=byte3+byte2 + var1:=byte3 + if byte3 == 91 '' Assume number is less 10 + byte2:=byte2-48 + var1:=byte2 + if byte2 == 91 ''ESC[D no numbers move LEFT one + + var1 := 1 + loop:=0 + repeat until loop == var1 + text.out($C0) 'was $C0 + loop++ + vt100:=0 + + if remote == 75 '' Clear line Esc[K + if byte2 == 91 '' Look for [ + text.clearlinefromcursor + + vt100:=0 + if byte2 == 48 ' look for [0K + if byte3 == 91 + text.clearlinefromcursor + + vt100:=0 + if byte2 == 49 ' look for [1K + if byte3 == 91 + text.clearlinetocursor + vt100 := 0 + if byte2 == 50 ' look for [2K + if byte3 == 91 + text.clearline + + vt100 := 0 + + if remote == 99 ' look for [0c or [c ESC [ ? 1 ; Ps c Ps=0 for VT-100 no options + if byte2 == 91 '' Look for [ + ser2.str(string(27,"[?1;0c")) + vt100 := 0 + if byte2 == 48 + if byte3 == 91 + ser2.str(string(27,"[?1;0c")) + vt100 := 0 + remote:=0 '' hide all codes from the VGA output. + + if record == 13 and remote == 13 ''LF CHECK + if CR == 1 + text.out(remote) + remote :=0 + if remote == 08 + remote := $C0 'now backspace just moves cursor, doesn't clear character + if remote == 7 + sound(source, 4500) + ' if remote == 10 + ' text.out($0A) + if remote > 8 + text.out(remote) + record:=remote ''record last byte + + +PUB EEPROM | eepromData + eepromLocation := EEPROM_Base + + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, 55) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, Baud) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, termcolor) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, pcport) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, ascii) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, curset) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, CR) + waitcnt(clkfreq/200 + cnt) + + + +PUB Sound (pWav,speed):bOK|n,i,nextCnt,rate,dcnt,wait + + pWav+=44 + + i:=0 + NextCnt:=cnt '+15000 + + 'Play loop + repeat i from 0 to 1200 + NextCnt+=speed + waitcnt(NextCnt) + FRQA:=(byte[pWav+i])<<24 + FRQB:=FRQA + +PUB forever | i + repeat i from 0 to 1000 + waitcnt(i*32767) +DAT + +PIANO +File "piano.wav" ' <--- put your 8-bit PCM mono 8000 sample/second WAV \ No newline at end of file diff --git a/software/6502_terminal_propeller/Basic_I2C_Driver.spin b/software/6502_terminal_propeller/Basic_I2C_Driver.spin new file mode 100644 index 0000000..4a7ef67 --- /dev/null +++ b/software/6502_terminal_propeller/Basic_I2C_Driver.spin @@ -0,0 +1,272 @@ +'' Basic I2C Routines Version 1.1 +'' Written by Michael Green and copyright (©) 2007 +'' Permission is given to use this in any program for the Parallax +'' Propeller processor as long as this copyright notice is included. + +'' This is a minimal version of an I2C driver in SPIN. It assumes +'' that the SDA pin is one higher than the SCL pin. It assumes that +'' neither the SDA nor the SCL pins have pullups, so drives both. + +'' These routines are primarily intended for reading and writing EEPROMs. +'' The low level I2C are provided for use with other devices, but the +'' read/write byte routines assume a standard I2C serial EEPROM with a +'' 16 bit device address register, paged writes, and acknowledge polling. + +'' All of these read/write routines accept an EEPROM address up to 19 +'' bits (512K) even though the EEPROM addressing scheme normally allows +'' for only 16 bits of addressing. The upper 3 bits are used as part of +'' the device select code and these routines will take the upper 3 bits +'' of the address and "or" it with the supplied device select code bits +'' 3-1 which are used to select a particular EEPROM on an I2C bus. There +'' are two schemes for selecting 64K "banks" in 128Kx8 EEPROMs. Atmel's +'' 24LC1024 EEPROMs allow simple linear addressing up to 256Kx8 ($00000 +'' to $3FFFF). Microchip's 24LC1025 allows for up to 512Kx8, but in two +'' areas: $00000 to $3FFFF and $40000 to $7FFFF. Each EEPROM provides +'' a 64K "bank" in each area. See the device datasheets for details. + +'' This will work with the boot EEPROM and does not require a pull-up +'' resistor on the SCL line (but does on the SDA line ... about 4.7K to +'' +3.3V). According to the Philips I2C specification, both pull-ups +'' are required. Many devices will tolerate the absence of a pull-up +'' on SCL. Some may tolerate the absence of a pull-up on SDA as well. + +'' Initialize may have to be called once at the beginning of your +'' program. Sometimes an I2C device is left in an invalid state. This +'' will reset the device to a known state so it will respond to the I2C +'' start transition (sent out by the i2cStart routine). + +'' To read from or write to an EEPROM on pins 28/29 like the boot EEPROM: + +'' CON +'' eepromAddress = $7000 + +'' VAR +'' byte buffer[32] + +'' OBJ +'' i2c : "Minimal_I2C_Driver" + +'' PRI readIt +'' if i2c.ReadPage(i2c#BootPin, i2c#EEPROM, eepromAddress, @buffer, 32) +'' abort ' an error occurred during the read + +'' PRI writeIt | startTime +'' if i2c.WritePage(i2c#BootPin, i2c#EEPROM, eepromAddress, @buffer, 32) +'' abort ' an error occured during the write +'' startTime := cnt ' prepare to check for a timeout +'' repeat while i2c.WriteWait(i2c#BootPin, i2c#EEPROM, eepromAddress) +'' if cnt - startTime > clkfreq / 10 +'' abort ' waited more than a 1/10 second for the write to finish + +'' Note that the read and write use something called paged reads/writes. +'' This means that any read using ReadPage must fit entirely in one +'' EEPROM if you have several attached to one set of pins. For writes, +'' any write using i2cWritePage must fit entirely within a page of the +'' EEPROM. Usually these pages are either 32, 64, 128 or 256 bytes in +'' size depending on the manufacturer and device type. 32 bytes is a +'' good limit for the number of bytes to be written at a time if you +'' don't know the specific page size (and the write must fit completely +'' within a multiple of the page size). The WriteWait waits for the +'' write operation to complete. Alternatively, you could wait for 5ms +'' since currently produced EEPROMs will finish within that time. + +CON + ACK = 0 ' I2C Acknowledge + NAK = 1 ' I2C No Acknowledge + Xmit = 0 ' I2C Direction Transmit + Recv = 1 ' I2C Direction Receive + BootPin = 28 ' I2C Boot EEPROM SCL Pin + EEPROM = $A0 ' I2C EEPROM Device Address + +PUB Initialize(SCL) | SDA ' An I2C device may be left in an + SDA := SCL + 1 ' invalid state and may need to be + outa[SCL] := 1 ' reinitialized. Drive SCL high. + dira[SCL] := 1 + dira[SDA] := 0 ' Set SDA as input + repeat 9 + outa[SCL] := 0 ' Put out up to 9 clock pulses + outa[SCL] := 1 + if ina[SDA] ' Repeat if SDA not driven high + quit ' by the EEPROM + +PUB Start(SCL) | SDA ' SDA goes HIGH to LOW with SCL HIGH + SDA := SCL + 1 + outa[SCL]~~ ' Initially drive SCL HIGH + dira[SCL]~~ + outa[SDA]~~ ' Initially drive SDA HIGH + dira[SDA]~~ + outa[SDA]~ ' Now drive SDA LOW + outa[SCL]~ ' Leave SCL LOW + +PUB Stop(SCL) | SDA ' SDA goes LOW to HIGH with SCL High + SDA := SCL + 1 + outa[SCL]~~ ' Drive SCL HIGH + outa[SDA]~~ ' then SDA HIGH + dira[SCL]~ ' Now let them float + dira[SDA]~ ' If pullups present, they'll stay HIGH + +PUB Write(SCL, data) : ackbit | SDA +'' Write i2c data. Data byte is output MSB first, SDA data line is valid +'' only while the SCL line is HIGH. Data is always 8 bits (+ ACK/NAK). +'' SDA is assumed LOW and SCL and SDA are both left in the LOW state. + SDA := SCL + 1 + ackbit := 0 + data <<= 24 + repeat 8 ' Output data to SDA + outa[SDA] := (data <-= 1) & 1 + outa[SCL]~~ ' Toggle SCL from LOW to HIGH to LOW + outa[SCL]~ + dira[SDA]~ ' Set SDA to input for ACK/NAK + outa[SCL]~~ + ackbit := ina[SDA] ' Sample SDA when SCL is HIGH + outa[SCL]~ + outa[SDA]~ ' Leave SDA driven LOW + dira[SDA]~~ + +PUB Read(SCL, ackbit): data | SDA +'' Read in i2c data, Data byte is output MSB first, SDA data line is +'' valid only while the SCL line is HIGH. SCL and SDA left in LOW state. + SDA := SCL + 1 + data := 0 + dira[SDA]~ ' Make SDA an input + repeat 8 ' Receive data from SDA + outa[SCL]~~ ' Sample SDA when SCL is HIGH + data := (data << 1) | ina[SDA] + outa[SCL]~ + outa[SDA] := ackbit ' Output ACK/NAK to SDA + dira[SDA]~~ + outa[SCL]~~ ' Toggle SCL from LOW to HIGH to LOW + outa[SCL]~ + outa[SDA]~ ' Leave SDA driven LOW + +PUB ReadPage(SCL, devSel, addrReg, dataPtr, count) : ackbit +'' Read in a block of i2c data. Device select code is devSel. Device starting +'' address is addrReg. Data address is at dataPtr. Number of bytes is count. +'' The device select code is modified using the upper 3 bits of the 19 bit addrReg. +'' Return zero if no errors or the acknowledge bits if an error occurred. + devSel |= addrReg >> 15 & %1110 + Start(SCL) ' Select the device & send address + ackbit := Write(SCL, devSel | Xmit) + ackbit := (ackbit << 1) | Write(SCL, addrReg >> 8 & $FF) + ackbit := (ackbit << 1) | Write(SCL, addrReg & $FF) + Start(SCL) ' Reselect the device for reading + ackbit := (ackbit << 1) | Write(SCL, devSel | Recv) + repeat count - 1 + byte[dataPtr++] := Read(SCL, ACK) + byte[dataPtr++] := Read(SCL, NAK) + Stop(SCL) + return ackbit + +PUB ReadByte(SCL, devSel, addrReg) : data +'' Read in a single byte of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. + if ReadPage(SCL, devSel, addrReg, @data, 1) + return -1 + +PUB ReadWord(SCL, devSel, addrReg) : data +'' Read in a single word of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. + if ReadPage(SCL, devSel, addrReg, @data, 2) + return -1 + +PUB ReadLong(SCL, devSel, addrReg) : data +'' Read in a single long of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. +'' Note that you can't distinguish between a return value of -1 and true error. + if ReadPage(SCL, devSel, addrReg, @data, 4) + return -1 + +PUB WritePage(SCL, devSel, addrReg, dataPtr, count) : ackbit +'' Write out a block of i2c data. Device select code is devSel. Device starting +'' address is addrReg. Data address is at dataPtr. Number of bytes is count. +'' The device select code is modified using the upper 3 bits of the 19 bit addrReg. +'' Most devices have a page size of at least 32 bytes, some as large as 256 bytes. +'' Return zero if no errors or the acknowledge bits if an error occurred. If +'' more than 31 bytes are transmitted, the sign bit is "sticky" and is the +'' logical "or" of the acknowledge bits of any bytes past the 31st. + devSel |= addrReg >> 15 & %1110 + Start(SCL) ' Select the device & send address + ackbit := Write(SCL, devSel | Xmit) + ackbit := (ackbit << 1) | Write(SCL, addrReg >> 8 & $FF) + ackbit := (ackbit << 1) | Write(SCL, addrReg & $FF) + repeat count ' Now send the data + ackbit := ackbit << 1 | ackbit & $80000000 ' "Sticky" sign bit + ackbit |= Write(SCL, byte[dataPtr++]) + Stop(SCL) + return ackbit + +PUB WriteByte(SCL, devSel, addrReg, data) +'' Write out a single byte of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. + if WritePage(SCL, devSel, addrReg, @data, 1) + return true + ' james edit - wait for 5ms for page write to complete (80_000 * 5 = 400_000) + waitcnt(400_000 + cnt) + return false + +PUB WriteWord(SCL, devSel, addrReg, data) +'' Write out a single word of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. +'' Note that the word value may not span an EEPROM page boundary. + if WritePage(SCL, devSel, addrReg, @data, 2) + return true + ' james edit - wait for 5ms for page write to complete (80_000 * 5 = 400_000) + waitcnt(400_000 + cnt) + return false + +PUB WriteLong(SCL, devSel, addrReg, data) +'' Write out a single long of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. +'' Note that the long word value may not span an EEPROM page boundary. + if WritePage(SCL, devSel, addrReg, @data, 4) + return true + ' james edit - wait for 5ms for page write to complete (80_000 * 5 = 400_000) + waitcnt(400_000 + cnt) + return false + +PUB WriteWait(SCL, devSel, addrReg) : ackbit +'' Wait for a previous write to complete. Device select code is devSel. Device +'' starting address is addrReg. The device will not respond if it is busy. +'' The device select code is modified using the upper 3 bits of the 18 bit addrReg. +'' This returns zero if no error occurred or one if the device didn't respond. + devSel |= addrReg >> 15 & %1110 + Start(SCL) + ackbit := Write(SCL, devSel | Xmit) + Stop(SCL) + return ackbit + + +' *************** JAMES'S Extra BITS ********************* + +PUB devicePresent(SCL,deviceAddress) : ackbit + ' send the deviceAddress and listen for the ACK + Start(SCL) + ackbit := Write(SCL,deviceAddress | 0) + Stop(SCL) + if ackbit == ACK + return true + else + return false + +PUB writeLocation(SCL,device_address, register, value) + start(SCL) + write(SCL,device_address) + write(SCL,register) + write(SCL,value) + stop (SCL) + +PUB readLocation(SCL,device_address, register) : value + start(SCL) + write(SCL,device_address | 0) + write(SCL,register) + start(SCL) + write(SCL,device_address | 1) + value := read(SCL,NAK) + stop(SCL) + return value \ No newline at end of file diff --git a/software/6502_terminal_propeller/FullDuplexSerial256.spin b/software/6502_terminal_propeller/FullDuplexSerial256.spin new file mode 100644 index 0000000..f4be86b --- /dev/null +++ b/software/6502_terminal_propeller/FullDuplexSerial256.spin @@ -0,0 +1,336 @@ +''************************************ +''* Full-Duplex Serial Driver v1.1 * +''* (C) 2006 Parallax, Inc. * +''************************************ +'' +'' +'' Added Notes from: Mike Green, lifted from: http://forums.parallax.com/forums/default.aspx?f=25 +'' +'' "FullDuplexSerial" is a full duplex serial driver. It uses only one cog to both transmit and receive. +'' You only need to call the start routine once to set up both directions. To use pin 0 for transmit and +'' pin 1 for receive at 9600 Baud you'd call "serial.start(1,0,%0000,9600)". That implies Rx not inverted, +'' Tx not inverted, not open drain on transmit, and no ignore echo on receive. This assumes that you declare +'' 'OBJ serial : "FullDuplexSerial"'. +'' +'' The return value is true if the driver was started ok, false if there were no free cogs available (rarely happens). +'' +'' FullDuplexSerial is intended to provide a buffered high speed serial communications channel in both directions +'' at once using a single cog. +'' +'' The actual UART function in the FullDuplexSerial object resides in a cog (for each full duplex channel). This +'' does the actual "bit-banging" and does the manipulation of the I/O pins. It communicates with the "interface" +'' routines written in SPIN by means of transmit and receive buffers declared in the FullDuplexSerial object. +'' The interface routines (like .tx, .rx, .rxcheck) can be called from any cog running SPIN although, if you try +'' to receive or transmit from more than one cog at a time, you'll get into trouble since both cogs will try to +'' put data into or get data out of the same buffer at the same time. The fix for this is to use the semaphores +'' (LOCKxxx). It would be unusual to have to do this. Normally, only one cog would make use of any one full duplex +'' channel. +'' +'' The FullDuplexSerial routines should work to at least 384 kB +'' +'' +VAR + + long cog 'cog flag/id + + long rx_head '9 contiguous longs + long rx_tail + long tx_head + long tx_tail + long rx_pin + long tx_pin + long rxtx_mode + long bit_ticks + long buffer_ptr + + + ' transmit and receive buffers + ' buffers need to be a power of 2; ie: 16 32 64 128 256 512 + ' Note: looks like the maximum size of the buffer can only be 512 bytes. + + byte rx_buffer[256] ' <----------- Change Buffer Size Here + byte tx_buffer[256] ' <----------- Change Buffer Size Here + + +PUB start(rxpin, txpin, mode, baudrate) : okay + +'' Start serial driver - starts a cog +'' returns false if no cog available +'' +'' mode bit 0 = invert rx +'' mode bit 1 = invert tx +'' mode bit 2 = open-drain/source tx +'' mode bit 3 = ignore tx echo on rx + + stop ' stop stops any existing running serial driver if say you reinitialized + ' your program without previously stopping it. + + longfill(@rx_head, 0, 4) ' The longfill initializes the first 4 longs to zero + ' (rx_head through tx_tail) + + longmove(@rx_pin, @rxpin, 3) ' The longmove copies the 4 parameters to start to the next 4 longs in + ' the table (rx_pin through bit_ticks) + + bit_ticks := clkfreq / baudrate ' The assignment to bit_ticks computes the number of clock ticks for + ' the Baud requested. + + buffer_ptr := @rx_buffer ' The assignment to buffer_ptr passes the address + ' of the receive buffer (and the transmit buffer XX bytes further). + + okay := cog := cognew(@entry, @rx_head) + 1 ' The cognew starts the assembly driver and passes to it the starting + ' address of this whole table which it uses to refer to the various + ' items in the table (rx_head through buffer_ptr). + + +PUB stop + +'' Stop serial driver - frees a cog + + if cog + cogstop(cog~ - 1) + 'longfill(@rx_head, 0, 9) + + +PUB rxflush + +'' Flush receive buffer + + repeat while rxcheck => 0 + + +PUB rxcheck : rxbyte + +'' Check if byte received (never waits) +'' returns -1 if no byte received, $00..$FF if byte + + rxbyte-- + if rx_tail <> rx_head + rxbyte := rx_buffer[rx_tail] + rx_tail := (rx_tail + 1) & $FF ' <----------- Change Buffer Size Here + + +PUB rxtime(ms) : rxbyte | t + +'' Wait ms milliseconds for a byte to be received +'' returns -1 if no byte received, $00..$FF if byte + + t := cnt + repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms + + +PUB rx : rxbyte + +'' Receive byte (may wait for byte) +'' returns $00..$FF + + repeat while (rxbyte := rxcheck) < 0 + + +PUB tx(txbyte) + +'' Send byte (may wait for room in buffer) + + repeat until (tx_tail <> (tx_head + 1) & $FF) ' <----------- Change Buffer Size Here + tx_buffer[tx_head] := txbyte + tx_head := (tx_head + 1) & $FF ' <----------- Change Buffer Size Here + + if rxtx_mode & %1000 + rx + + +PUB str(stringptr) + +'' Send string + + repeat strsize(stringptr) + tx(byte[stringptr++]) + +PUB dec(value) | i + +'' Print a decimal number + + if value < 0 + -value + tx("-") + + i := 1_000_000_000 + + repeat 10 + if value => i + tx(value / i + "0") + value //= i + result~~ + elseif result or i == 1 + tx("0") + i /= 10 + + +PUB hex(value, digits) + +'' Print a hexadecimal number + + value <<= (8 - digits) << 2 + repeat digits + tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F")) + + +PUB bin(value, digits) + +'' Print a binary number + + value <<= 32 - digits + repeat digits + tx((value <-= 1) & 1 + "0") + + +DAT + +'*********************************** +'* Assembly language serial driver * +'*********************************** + + org +' +' +' Entry +' +entry mov t1,par 'get structure address + add t1,#4 << 2 'skip past heads and tails + + rdlong t2,t1 'get rx_pin + mov rxmask,#1 + shl rxmask,t2 + + add t1,#4 'get tx_pin + rdlong t2,t1 + mov txmask,#1 + shl txmask,t2 + + add t1,#4 'get rxtx_mode + rdlong rxtxmode,t1 + + add t1,#4 'get bit_ticks + rdlong bitticks,t1 + + add t1,#4 'get buffer_ptr + rdlong rxbuff,t1 + mov txbuff,rxbuff + add txbuff,#256 ' <----------- Change Buffer Size Here + + test rxtxmode,#%100 wz 'init tx pin according to mode + test rxtxmode,#%010 wc + if_z_ne_c or outa,txmask + if_z or dira,txmask + + mov txcode,#transmit 'initialize ping-pong multitasking +' +' +' Receive +' +receive jmpret rxcode,txcode 'run a chunk of transmit code, then return + + test rxtxmode,#%001 wz 'wait for start bit on rx pin + test rxmask,ina wc + if_z_eq_c jmp #receive + + mov rxbits,#9 'ready to receive byte + mov rxcnt,bitticks + shr rxcnt,#1 + add rxcnt,cnt + +:bit add rxcnt,bitticks 'ready next bit period + +:wait jmpret rxcode,txcode 'run a chuck of transmit code, then return + + mov t1,rxcnt 'check if bit receive period done + sub t1,cnt + cmps t1,#0 wc + if_nc jmp #:wait + + test rxmask,ina wc 'receive bit on rx pin + rcr rxdata,#1 + djnz rxbits,#:bit + + shr rxdata,#32-9 'justify and trim received byte + and rxdata,#$FF + test rxtxmode,#%001 wz 'if rx inverted, invert byte + if_nz xor rxdata,#$FF + + rdlong t2,par 'save received byte and inc head + add t2,rxbuff + wrbyte rxdata,t2 + sub t2,rxbuff + add t2,#1 + and t2,#$FF ' <----------- Change Buffer Size Here + wrlong t2,par + + jmp #receive 'byte done, receive next byte +' +' +' Transmit +' +transmit jmpret txcode,rxcode 'run a chunk of receive code, then return + + mov t1,par 'check for head <> tail + add t1,#2 << 2 + rdlong t2,t1 + add t1,#1 << 2 + rdlong t3,t1 + cmp t2,t3 wz + if_z jmp #transmit + + add t3,txbuff 'get byte and inc tail + rdbyte txdata,t3 + sub t3,txbuff + add t3,#1 + and t3,#$FF ' <----------- Change Buffer Size Here + wrlong t3,t1 + + or txdata,#$100 'ready byte to transmit + shl txdata,#2 + or txdata,#1 + mov txbits,#11 + mov txcnt,cnt + +:bit test rxtxmode,#%100 wz 'output bit on tx pin according to mode + test rxtxmode,#%010 wc + if_z_and_c xor txdata,#1 + shr txdata,#1 wc + if_z muxc outa,txmask + if_nz muxnc dira,txmask + add txcnt,bitticks 'ready next cnt + +:wait jmpret txcode,rxcode 'run a chunk of receive code, then return + + mov t1,txcnt 'check if bit transmit period done + sub t1,cnt + cmps t1,#0 wc + if_nc jmp #:wait + + djnz txbits,#:bit 'another bit to transmit? + + jmp #transmit 'byte done, transmit next byte +' +' +' Uninitialized data +' +t1 res 1 +t2 res 1 +t3 res 1 + +rxtxmode res 1 +bitticks res 1 + +rxmask res 1 +rxbuff res 1 +rxdata res 1 +rxbits res 1 +rxcnt res 1 +rxcode res 1 + +txmask res 1 +txbuff res 1 +txdata res 1 +txbits res 1 +txcnt res 1 +txcode res 1 \ No newline at end of file diff --git a/software/6502_terminal_propeller/FullDuplexSerial2562.spin b/software/6502_terminal_propeller/FullDuplexSerial2562.spin new file mode 100644 index 0000000..f4be86b --- /dev/null +++ b/software/6502_terminal_propeller/FullDuplexSerial2562.spin @@ -0,0 +1,336 @@ +''************************************ +''* Full-Duplex Serial Driver v1.1 * +''* (C) 2006 Parallax, Inc. * +''************************************ +'' +'' +'' Added Notes from: Mike Green, lifted from: http://forums.parallax.com/forums/default.aspx?f=25 +'' +'' "FullDuplexSerial" is a full duplex serial driver. It uses only one cog to both transmit and receive. +'' You only need to call the start routine once to set up both directions. To use pin 0 for transmit and +'' pin 1 for receive at 9600 Baud you'd call "serial.start(1,0,%0000,9600)". That implies Rx not inverted, +'' Tx not inverted, not open drain on transmit, and no ignore echo on receive. This assumes that you declare +'' 'OBJ serial : "FullDuplexSerial"'. +'' +'' The return value is true if the driver was started ok, false if there were no free cogs available (rarely happens). +'' +'' FullDuplexSerial is intended to provide a buffered high speed serial communications channel in both directions +'' at once using a single cog. +'' +'' The actual UART function in the FullDuplexSerial object resides in a cog (for each full duplex channel). This +'' does the actual "bit-banging" and does the manipulation of the I/O pins. It communicates with the "interface" +'' routines written in SPIN by means of transmit and receive buffers declared in the FullDuplexSerial object. +'' The interface routines (like .tx, .rx, .rxcheck) can be called from any cog running SPIN although, if you try +'' to receive or transmit from more than one cog at a time, you'll get into trouble since both cogs will try to +'' put data into or get data out of the same buffer at the same time. The fix for this is to use the semaphores +'' (LOCKxxx). It would be unusual to have to do this. Normally, only one cog would make use of any one full duplex +'' channel. +'' +'' The FullDuplexSerial routines should work to at least 384 kB +'' +'' +VAR + + long cog 'cog flag/id + + long rx_head '9 contiguous longs + long rx_tail + long tx_head + long tx_tail + long rx_pin + long tx_pin + long rxtx_mode + long bit_ticks + long buffer_ptr + + + ' transmit and receive buffers + ' buffers need to be a power of 2; ie: 16 32 64 128 256 512 + ' Note: looks like the maximum size of the buffer can only be 512 bytes. + + byte rx_buffer[256] ' <----------- Change Buffer Size Here + byte tx_buffer[256] ' <----------- Change Buffer Size Here + + +PUB start(rxpin, txpin, mode, baudrate) : okay + +'' Start serial driver - starts a cog +'' returns false if no cog available +'' +'' mode bit 0 = invert rx +'' mode bit 1 = invert tx +'' mode bit 2 = open-drain/source tx +'' mode bit 3 = ignore tx echo on rx + + stop ' stop stops any existing running serial driver if say you reinitialized + ' your program without previously stopping it. + + longfill(@rx_head, 0, 4) ' The longfill initializes the first 4 longs to zero + ' (rx_head through tx_tail) + + longmove(@rx_pin, @rxpin, 3) ' The longmove copies the 4 parameters to start to the next 4 longs in + ' the table (rx_pin through bit_ticks) + + bit_ticks := clkfreq / baudrate ' The assignment to bit_ticks computes the number of clock ticks for + ' the Baud requested. + + buffer_ptr := @rx_buffer ' The assignment to buffer_ptr passes the address + ' of the receive buffer (and the transmit buffer XX bytes further). + + okay := cog := cognew(@entry, @rx_head) + 1 ' The cognew starts the assembly driver and passes to it the starting + ' address of this whole table which it uses to refer to the various + ' items in the table (rx_head through buffer_ptr). + + +PUB stop + +'' Stop serial driver - frees a cog + + if cog + cogstop(cog~ - 1) + 'longfill(@rx_head, 0, 9) + + +PUB rxflush + +'' Flush receive buffer + + repeat while rxcheck => 0 + + +PUB rxcheck : rxbyte + +'' Check if byte received (never waits) +'' returns -1 if no byte received, $00..$FF if byte + + rxbyte-- + if rx_tail <> rx_head + rxbyte := rx_buffer[rx_tail] + rx_tail := (rx_tail + 1) & $FF ' <----------- Change Buffer Size Here + + +PUB rxtime(ms) : rxbyte | t + +'' Wait ms milliseconds for a byte to be received +'' returns -1 if no byte received, $00..$FF if byte + + t := cnt + repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms + + +PUB rx : rxbyte + +'' Receive byte (may wait for byte) +'' returns $00..$FF + + repeat while (rxbyte := rxcheck) < 0 + + +PUB tx(txbyte) + +'' Send byte (may wait for room in buffer) + + repeat until (tx_tail <> (tx_head + 1) & $FF) ' <----------- Change Buffer Size Here + tx_buffer[tx_head] := txbyte + tx_head := (tx_head + 1) & $FF ' <----------- Change Buffer Size Here + + if rxtx_mode & %1000 + rx + + +PUB str(stringptr) + +'' Send string + + repeat strsize(stringptr) + tx(byte[stringptr++]) + +PUB dec(value) | i + +'' Print a decimal number + + if value < 0 + -value + tx("-") + + i := 1_000_000_000 + + repeat 10 + if value => i + tx(value / i + "0") + value //= i + result~~ + elseif result or i == 1 + tx("0") + i /= 10 + + +PUB hex(value, digits) + +'' Print a hexadecimal number + + value <<= (8 - digits) << 2 + repeat digits + tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F")) + + +PUB bin(value, digits) + +'' Print a binary number + + value <<= 32 - digits + repeat digits + tx((value <-= 1) & 1 + "0") + + +DAT + +'*********************************** +'* Assembly language serial driver * +'*********************************** + + org +' +' +' Entry +' +entry mov t1,par 'get structure address + add t1,#4 << 2 'skip past heads and tails + + rdlong t2,t1 'get rx_pin + mov rxmask,#1 + shl rxmask,t2 + + add t1,#4 'get tx_pin + rdlong t2,t1 + mov txmask,#1 + shl txmask,t2 + + add t1,#4 'get rxtx_mode + rdlong rxtxmode,t1 + + add t1,#4 'get bit_ticks + rdlong bitticks,t1 + + add t1,#4 'get buffer_ptr + rdlong rxbuff,t1 + mov txbuff,rxbuff + add txbuff,#256 ' <----------- Change Buffer Size Here + + test rxtxmode,#%100 wz 'init tx pin according to mode + test rxtxmode,#%010 wc + if_z_ne_c or outa,txmask + if_z or dira,txmask + + mov txcode,#transmit 'initialize ping-pong multitasking +' +' +' Receive +' +receive jmpret rxcode,txcode 'run a chunk of transmit code, then return + + test rxtxmode,#%001 wz 'wait for start bit on rx pin + test rxmask,ina wc + if_z_eq_c jmp #receive + + mov rxbits,#9 'ready to receive byte + mov rxcnt,bitticks + shr rxcnt,#1 + add rxcnt,cnt + +:bit add rxcnt,bitticks 'ready next bit period + +:wait jmpret rxcode,txcode 'run a chuck of transmit code, then return + + mov t1,rxcnt 'check if bit receive period done + sub t1,cnt + cmps t1,#0 wc + if_nc jmp #:wait + + test rxmask,ina wc 'receive bit on rx pin + rcr rxdata,#1 + djnz rxbits,#:bit + + shr rxdata,#32-9 'justify and trim received byte + and rxdata,#$FF + test rxtxmode,#%001 wz 'if rx inverted, invert byte + if_nz xor rxdata,#$FF + + rdlong t2,par 'save received byte and inc head + add t2,rxbuff + wrbyte rxdata,t2 + sub t2,rxbuff + add t2,#1 + and t2,#$FF ' <----------- Change Buffer Size Here + wrlong t2,par + + jmp #receive 'byte done, receive next byte +' +' +' Transmit +' +transmit jmpret txcode,rxcode 'run a chunk of receive code, then return + + mov t1,par 'check for head <> tail + add t1,#2 << 2 + rdlong t2,t1 + add t1,#1 << 2 + rdlong t3,t1 + cmp t2,t3 wz + if_z jmp #transmit + + add t3,txbuff 'get byte and inc tail + rdbyte txdata,t3 + sub t3,txbuff + add t3,#1 + and t3,#$FF ' <----------- Change Buffer Size Here + wrlong t3,t1 + + or txdata,#$100 'ready byte to transmit + shl txdata,#2 + or txdata,#1 + mov txbits,#11 + mov txcnt,cnt + +:bit test rxtxmode,#%100 wz 'output bit on tx pin according to mode + test rxtxmode,#%010 wc + if_z_and_c xor txdata,#1 + shr txdata,#1 wc + if_z muxc outa,txmask + if_nz muxnc dira,txmask + add txcnt,bitticks 'ready next cnt + +:wait jmpret txcode,rxcode 'run a chunk of receive code, then return + + mov t1,txcnt 'check if bit transmit period done + sub t1,cnt + cmps t1,#0 wc + if_nc jmp #:wait + + djnz txbits,#:bit 'another bit to transmit? + + jmp #transmit 'byte done, transmit next byte +' +' +' Uninitialized data +' +t1 res 1 +t2 res 1 +t3 res 1 + +rxtxmode res 1 +bitticks res 1 + +rxmask res 1 +rxbuff res 1 +rxdata res 1 +rxbits res 1 +rxcnt res 1 +rxcode res 1 + +txmask res 1 +txbuff res 1 +txdata res 1 +txbits res 1 +txcnt res 1 +txcode res 1 \ No newline at end of file diff --git a/software/6502_terminal_propeller/Keyboard.spin b/software/6502_terminal_propeller/Keyboard.spin new file mode 100644 index 0000000..d8c197e Binary files /dev/null and b/software/6502_terminal_propeller/Keyboard.spin differ diff --git a/software/6502_terminal_propeller/PockeTermV.905.binary b/software/6502_terminal_propeller/PockeTermV.905.binary new file mode 100644 index 0000000..03d2d0d Binary files /dev/null and b/software/6502_terminal_propeller/PockeTermV.905.binary differ diff --git a/software/6502_terminal_propeller/PockeTermV.905.spin b/software/6502_terminal_propeller/PockeTermV.905.spin new file mode 100644 index 0000000..203e8b8 --- /dev/null +++ b/software/6502_terminal_propeller/PockeTermV.905.spin @@ -0,0 +1,701 @@ +'''''''''''''''''''''''''''''' +'' PockeTerm '' +'' Author: Vince Briel '' +'' 2009 Briel Computers '' +'' '' +'''''''''''''''''''''''''''''' +' +'' Big thanks to Jeff Ledger on the VT100 code +' +' +' Start of RAW code for testing December 19,2008 +' Jan 10th added INVERSE mode +' Jan 13 revised code for .04 working duel serial ports +' Jan 15 fixed so xmodem could work by allowing data 0 up to be sent not 1 and up +' Jan 21 added PC port on/off 7 bit ascii on/off +' V.71 cls to cursor fixed +' V.72 clsfrom cursor down working +' V.73 fixed EEPROM read/write issue and no serial port functioning +' V.74 ESC D and ESC L commands added, only 2 commands remaining +' V.80 VT100 majority codes finished +' V.81 Fixed cursor home to 0,0 and CLS to leave cursor where it is at after CLS +' V.82 Made Function control keys CTRL-Fx to avoid accidental changes +' V.83 Added CTRL-G beep sound effect +' V.84 Added ESC[c and ESC[0c terminal ID command +' V.85 Fixed scroll issue if beyond 36th line +' V.86 Fixed terminal ID, now working added 300 & 115200 Baud rates +' V.90 Added CTRL-F6 option for Carriage return to add line feed YES or NO +' V.901 Fixed ESC[A-D so they work if no value is added +' V.902 Modified so CR just does a Carriage Return and LF just does a linefeed +' V.903 More adjustments to CR adjusted command +' V.905 Fixed clear from cursor up ESC[1J did not clear line above cursor +'' Current VT-100 Code list +'' +'' ESC[m Turn off character attributes +'' ESC[0m Turn off character attributes +'' ESC[1m Turn bold character on (reverse) +'' ESC[7m Turn reverse video on +'' ESC[nA Move cursor up n lines +'' ESC[nB Move cursor down n lines +'' ESC[nC Move cursor right n lines +'' ESC[nD Move cursor left n lines +'' ESC[H Move cursor to upper left corner +'' ESC[;H Move cursor to upper left corner +'' ESC[line;columnH Move cursor to screen location v,h +'' ESC[f Move cursor to upper left corner +'' ESC[;f Move cursor to upper left corner +'' ESC[line;columnf Move cursor to sceen location v,h +'' ESCD Move/scroll window up one line +'' ESC[D Move/scroll window up one line +'' ESCL Move/scroll window up one line (undocumented) +'' ESC[L Move/scroll window up one line (undocumented) +'' ESCM Move/scroll window down one line +'' ESCK Clear line from cursor right +'' ESC[0K Clear line from cursor right +'' ESC[1K Clear line from cursor left +'' ESC[2K Clear entire line +'' ESC[J Clear screen from cursor down +'' ESC[0J Clear screen from cursor down +'' ESC[1J Clear screen from cursor up +'' ESC[2J Clear entire screen +'' ESC[0c Terminal ID responds with [?1;0c for VT-100 no options +'' ESC[c Terminal ID responds with [?1;0c for VT-100 no options +'' Esc[value@ Insert one character +'' Esc[valueP Delete one character +'' +'' List of ignored codes +'' +'' ESC[xxh All of the ESC[20h thru ESC[?9h commands +'' ESC[xxl All of the ESC[20i thru ESC[?9i commands +'' ESC= Alternate keypad mode +'' ESC< Enter/Exit ANSI mode +'' ESC> Exit Alternate keypad mode +'' Esc5n Device status report DSR +'' Esc0n Response: terminal is OK DSR +'' Esc3n Response: terminal is not OK DSR +'' Esc6n Get cursor position DSR +'' EscLine;ColumnR Response: cursor is at v,h CPR +'' Esc#8 Screen alignment display DECALN +'' Esc[2;1y Confidence power up test DECTST +'' Esc[2;2y Confidence loopback test DECTST +'' Esc[2;9y Repeat power up test DECTST +'' Esc[2;10y Repeat loopback test DECTST +'' Esc[0q Turn off all four leds DECLL0 +'' Esc[1q Turn on LED #1 DECLL1 +'' Esc[2q Turn on LED #2 DECLL2 +'' Esc[3q Turn on LED #3 DECLL3 +'' Esc[4q Turn on LED #4 DECLL4 + + +'' IN DEVELOPMENT + + + +' Please report any bugs to vbriel@yahoo.com + + +CON + + _clkmode = xtal1 + pll16x + _xinfreq = 5_000_000 + + Cursor = 95 + VideoCls = 0 + NUM = %100 + CAPS = %010 + SCROLL = %001 + RepeatRate = 40 + video = 16 + backspace = $C8 +' semi = 59 +' rowsnow = 36 + +' VT-100 values + +'' Terminal Colors + TURQUOISE = $29 + BLUE = $27 + BABYBLUE = $95 + RED = $C1 + GREEN = $99 + GOLDBROWN = $A2 + AMBERDARK = $E2 + LAVENDER = $A5 + WHITE = $FF + HOTPINK = $C9 + GOLD = $D9 + PINK = $C5 + + + r1 = 31 'PC serial port receive line + t1 = 30 'PC serial port transmit line + r2 = 25 'Host device receive line + t2 = 24 'Host device transmit line + + EEPROMAddr = %1010_0000 + EEPROM_Base = $7FE0 + i2cSCL = 28 + +'' Sound Variables + + right = 10 + left = 11 + +OBJ + + text: "VGA_1024v.905" ' VGA Terminal Driver + kb: "keyboard" ' Keyboard driver + ser: "FullDuplexSerial256" ' Full Duplex Serial Controller + ser2: "FullDuplexSerial2562" ' 2nd Full Duplex Serial Controller + i2c: "basic_i2c_driver" +VAR + + word key + Byte Index + Byte Rx + Byte rxbyte +' Long Stack[100] + Byte temp + Byte serdata + Long Baud + Byte termcolor + Long BR[8] + Long CLR[11] + long i2cAddress, i2cSlaveCounter + Byte pcport + Byte ascii + Byte curset + word eepromLocation + Byte CR + Byte LNM +PUB main | i,j,k,remote,remote2,record,vt100,byte2,byte3,byte1,byte4,byte5,byte6,byte7,loop,var1,col,row,temp2,tempbaud,source + + + + + CTRA:= %00110 << 26 + 0<<9 + right + CTRB:= %00110 << 26 + 0<<9 + left + DIRA[right]~~ 'Set Right Pin to output + DIRA[left]~~ 'Set Left Pin to output + source:=@PIANO + LNM := 0 'CR only sent + i2c.Initialize(i2cSCL) + tempbaud:=4 + CR := 0 '0= OFF 1 = CR AND LF + ascii := 0 '0=no 1=yes + pcport := 1 '1=pc port off, 2=on + termcolor:=5 + curset := 5 + BR[0]:=300 + BR[1]:=1200 + BR[2]:=2400 + BR[3]:=4800 + BR[4]:=9600 + BR[5]:=19200 + BR[6]:=38400 + BR[7]:=57600 + BR[8]:=115200 + CLR[1]:=TURQUOISE + CLR[2]:=BLUE + CLR[3]:=BABYBLUE + CLR[4]:=RED + CLR[5]:=GREEN + CLR[6]:=GOLDBROWN + CLR[7]:=WHITE + CLR[8]:=HOTPINK + CLR[9]:=GOLD + CLR[10]:=PINK + CLR[11]:=AMBERDARK + +'' Determine if previous settings are stored in EEPROM, if so, retrive for user + eepromLocation := EEPROM_Base 'Point i2c to EEPROM storage + temp2 := i2c.ReadByte(i2cSCL, EEPROMAddr, eepromLocation) 'read test byte to see if data stored + if temp2 == 55 'we have previously recorded settings, so restore them + eepromLocation +=4 'increase to next location + tempbaud := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read Baud as temp + eepromLocation +=4 + termcolor := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read terminal color + eepromLocation +=4 + pcport := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read pcport on/off setting + eepromLocation +=4 + ascii := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read force 7bit setting + eepromLocation +=4 + curset := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read cursor type + eepromLocation +=4 + CR := i2c.ReadLong(i2cSCL, EEPROMAddr, eepromLocation) 'read CR W/LF ON/OFF + waitcnt(clkfreq/200 + cnt) + + + + + Baud:=BR[tempbaud] + text.start(video) + text.color(CLR[termcolor]) + kb.startx(26, 27, NUM, RepeatRate) 'Start Keyboard Driver + ser.start(r1,t1,0,baud) 'Start Port2 to PC + ser2.start(r2,t2,0,baud) 'Start Port1 to main device + Baud:=tempbaud + text.cls(Baud,termcolor,pcport,ascii,CR) +' text.clsupdate(Baud,termcolor,pcport,ascii,CR) + text.inv(0) + text.cursorset(curset) + vt100:=0 + repeat + key := kb.key 'Go get keystroke, then return here + + if key == 194 'up arrow + ser2.str(string(27,"[A")) + if key == 195 'down arrow + ser2.str(string(27,"[B")) + 'ser2.out($0A) + if key == 193 'right arrow + ser2.str(string(27,"[C")) + if key == 192 'left arrow + ser2.str(string(27,"[D")) + + if key >576 + if key <603 + key:=key-576 + if key > 608 and key < 635 'Is it a control character? + key:=key-608 + 'if key >0 + ' text.dec(key) + if key == 200 + key:=08 + if key == 203 'Is it upper code for ESC key? + key:= 27 'Yes, convert to standard ASCII value + if key == 720 + Baud++ 'is ESC then + then increase baud or roll over + if Baud > 8 + Baud:=0 + temp:=Baud + Baud:=BR[temp] + ser.stop + ser2.stop + ser.start(r1,t1,0,baud) 'ready port for PC + ser2.start(r2,t2,0,baud) 'ready port for HOST + Baud:=temp + text.clsupdate(Baud,termcolor,pcport,ascii,CR) + EEPROM + if key == 721 + if ++termcolor > 11 + termcolor:=1 + text.color(CLR[termcolor]) + 'text.clsupdate(Baud,termcolor,pcport,ascii) + EEPROM + if key == 722 + if pcport == 1 + pcport := 0 + else + pcport := 1 + text.clsupdate(Baud,termcolor,pcport,ascii,CR) + EEPROM + if key == 723 + if ascii == 0 + ascii := 1 + else + ascii :=0 + text.clsupdate(Baud,termcolor,pcport,ascii,CR) + EEPROM + if key == 724 + curset++ + if curset > 7 + curset := 1 + text.cursorset(curset) + EEPROM + if key == 725 'F6 + if CR == 1 + CR := 0 + else + CR := 1 + text.clsupdate(Baud,termcolor,pcport,ascii,CR) + EEPROM + if key <128 and key > 0 'Is the keystroke PocketTerm compatible? was 96 + ser2.tx(key) 'Yes, so send it + if key == 13 + 'this probably needs to be if CR == 1 + if LNM == 1 or CR == 1'send both CR and LF? + ser2.tx(10) 'yes, set by LNM ESC command, send LF also + + + +'' END keyboard console routine + + + +'LOOK FOR SERIAL INPUT HERE + if pcport == 0 'Is PC turned on at console for checking? + remote2 := ser.rxcheck 'Yes, look at the port for data + if (remote2 > -1) 'remote = -1 if no data + ser2.tx(remote2) 'Send the data out to the host device + waitcnt(clkfreq/200 + cnt) 'Added to attempt eliminate dropped characters + remote := ser2.rxcheck 'Look at host device port for data + if (remote > -1) + if ascii == 1 'yes force 7 bit ascii + if (remote > 127) + remote := remote -128 + if pcport == 0 + ser.tx(remote) +'Start of VT100 code + if remote == 27 'vt100 ESC code is being sent + vt100:=1 + byte1:=0 + byte2:=0 + byte3:=0 + byte4:=0 + byte5:=0 + byte6:=0 + byte7:=0 + remote:=0 + temp2:=0 'Don't display the ESC code + if remote == 99 and vt100 == 1 'ESC c + remote:=0 + vt100:=0 + text.inv(0) + text.cls(Baud,termcolor,pcport,ascii,CR) + text.home + + if remote == 61 and vt100 == 1 'lool for ESC= + vt100:= remote := 0 + + + 'put ESC D and ESC M here + if remote == 77 and vt100 == 1 'AKA ESC M + text.scrollM + vt100 := 0 + if remote == 68 and vt100 == 1 'AKA ESC D + if byte2 <> 91 and byte3 <> 91 and byte4 <> 91 'not esc[D + 'text.scrollD + vt100 := 0 + if remote == 76 and vt100 == 1 'AKA ESC L + if remote == 91 and vt100 == 1 'look for open bracket [ + vt100:=2 'start recording code + if remote == 62 and vt100 == 1 or remote == 60 and vt100 == 1 'look for < & > + vt100:=0 ' not sure why this is coming up, can't find in spec. + if vt100==2 ''Check checking for VT100 emulation codes + if remote > 10 + byte7:=byte6 + byte6:=byte5 ' My VTCode Mini Buffer + byte5:=byte4 + byte4:=byte3 + byte3:=byte2 'Record the last 7 bytes + byte2:=byte1 + byte1:=remote + + if remote == 109 'look for lowercase m + if byte2 == 91 'if [m turn off to normal set + text.inv(0) + vt100:=0 + if byte2 == 49 and vt100 > 0 'is it ESC[1m BOLD + 'text.inv(1) + vt100 := 0 + if byte2 == 55 and vt100 > 0 'is it ESC[7m? + text.inv(1) + vt100 := 0 + if byte2 == 48 and vt100 > 0 '0 is back to normal + text.inv(0) + vt100:=0 + if byte2 == 52 and vt100 > 0 'is it ESC[4m underline? + vt100:=0 'yes ignore + if byte2 == 50 and vt100 >0 'is it ESC[2m dim text + vt100:=0 'yes ignore + if remote == 64 'look for ESC[value@ @=64 insert value spaces + if byte4 == 91 'two digit value + byte3:=byte3-48 'Grab 10's + byte2:=byte2-48 'Grab 1's + byte3:=byte3*10 'Multiply 10's + byte3:=byte3+byte2 'Add 1's + text.insertat(byte3) + if byte3 == 91 'single digit value + byte2:=byte2-48 + text.insertat(byte2) + vt100 :=0 + if remote == 80 'look for ESC[valueP P=64 delete value spaces + if byte4 == 91 'two digit value + byte3:=byte3-48 'Grab 10's + byte2:=byte2-48 'Grab 1's + byte3:=byte3*10 'Multiply 10's + byte3:=byte3+byte2 'Add 1's + text.delp(byte3) + if byte3 == 91 'single digit value + byte2:=byte2-48 + text.delp(byte2) + vt100 :=0 + if remote == 104 'look for lowercase h set CR/LF mode + if byte2 == 48 'if character before h is 0 maybe command is 20h + if byte3 == 50 'if byte3 then it is for sure 20h + LNM := 0 + vt100:=0 + + if remote == 61 'lool for = + vt100:=0 + + if remote == 114 'look for lowercase r + vt100:=0 + + if remote == 108 'look for lowercase l + if byte2 == 48 'if character before l is 0 maybe command is 20l + if byte3 == 50 'if byte3 then it is for sure 20l + LNM := 1 '0 means CR/LF in CR mode only + vt100:=0 + + if remote == 62 'look for > + vt100:=0 + if remote == 77 'ESC M look for obscure scroll window code + text.scrollM + vt100:=0 + if remote == 68 or remote == 76 ' look for ESC D or ESC L + text.scrollD + vt100:=0 + if remote == 72 or remote == 102 ' HOME CURSOR (uppercase H or lowercase f) + if byte2==91 or byte2==59 'look for [H or [;f + text.home + vt100:=0 + '' Check for X & Y with [H or ;f - Esc[Line;ColumnH + + else 'here remote is either H or f + if byte4 == 59 'is col is greater than 9 ; ALWAYS if byte4=59 + byte3:=byte3-48 'Grab 10's + byte2:=byte2-48 'Grab 1's + byte3:=byte3*10 'Multiply 10's + byte3:=byte3+byte2 'Add 1's + col:=byte3 'Set cols + + if byte7 == 91 'Assume row number is greater than 9 if ; at byte 4 and [ at byte 7 greater than 9 + byte6:=byte6-48 'Grab 10's + byte5:=byte5-48 'Grab 1's + byte6:=byte6*10 'Multiply 10's + byte6:=byte6+byte5 'Add 1's + row:=byte6 + + if byte6 == 91 'Assume row number is less than 10 + byte5:=byte5 - 48 'Grab 1's + row:=byte5 + + if byte3 == 59 ' Assume that col is less an 10 + byte2:=byte2-48 'Grab 1's + col:=byte2 'set cols + + if byte6 == 91 'Assume row number is greater than 9 + byte5:=byte5-48 'Grab 10's + byte4:=byte4-48 'Grab 1's + byte5:=byte5*10 'Multiply 10's + byte5:=byte5+byte4 'Add 1's + row:=byte5 + if byte5 == 91 'Assume that col is greater than 10 + byte4:=byte4-48 'Grab 1's + row:=byte4 + + col:=col-1 + if row == -459 + row:=1 + if col == -40 ' Patches a bug I havn't found. *yet* + col := 58 ' A Microsoft approach to the problem. :) + if row == -449 + row := 2 ' Appears to be an issue with reading + if row == -439 ' single digit rows. + row := 3 + if row == -429 ' This patch checks for the bug and replaces + row := 4 ' the faulty calculation. + if row == -419 + row := 5 ' Add to list to find the source of bug later. + if row == -409 + row := 6 + if row == -399 + row := 7 + if row == -389 + row := 8 + if row == -379 + row := 9 + row-- + + + if row < 0 + row:=0 + if col < 0 + col:=0 + if row > 35 + row :=35 + if col > 79 + col := 79 + text.cursloc(col,row) + vt100:=0 + if remote == 114 'ESCr + + text.out(126) + if remote == 74 '' CLEAR SCREEN + if byte2==91 '' look for [J '' clear screen from cursor to 25 + text.clsfromcursordown + 'vt100:=0 + if byte2==50 '' look for [2J '' clear screen + text.cls(Baud,termcolor,pcport,ascii,CR) + if byte2==49 'look for [1J + text.clstocursor + if byte2==48 'look for [0J + text.clsfromcursordown + vt100:=0 + if remote == 66 '' CURSOR DOWN Esc[ValueB + if byte4 == 91 '' Assume number over 10 + byte3:=byte3-48 + byte2:=byte2-48 + byte3:=byte3*10 + byte3:=byte3+byte2 + var1:=byte3 + if byte3 == 91 '' Assume number is less 10 + byte2:=byte2-48 + var1:=byte2 + if byte2 == 91 ''ESC[B no numbers move down one + 'text.out($C3) + var1 := 1 + loop:=0 + repeat until loop == var1 + loop++ + text.out($C3) + + vt100:=0 + + + if remote == 65 '' CURSOR UP Esc[ValueA + if byte4 == 91 '' Assume number over 10 + byte3:=byte3-48 + byte2:=byte2-48 + byte3:=byte3*10 + byte3:=byte3+byte2 + var1:=byte3 + if byte3 == 91 '' Assume number is less 10 + byte2:=byte2-48 + var1:=byte2 + if byte2 == 91 ''ESC[A no numbers move down one + + var1 := 1 + loop:=0 + repeat until loop == var1 + text.out($C2) + loop++ + vt100:=0 + + + if remote == 67 '' CURSOR RIGHT Esc[ValueC + if byte4 == 91 '' Assume number over 10 + byte3:=byte3-48 + byte2:=byte2-48 + byte3:=byte3*10 + byte3:=byte3+byte2 + var1:=byte3 + if byte3 == 91 '' Assume number is less 10 + byte2:=byte2-48 + var1:=byte2 + if byte2 == 91 ''ESC[C no numbers move RIGHT one + + var1 := 1 + loop:=0 + repeat until loop == var1 + text.out($C1) + loop++ + vt100:=0 + + if remote == 68 '' CURSOR LEFT Esc[ValueD OR ESC[D + if byte4 == 91 '' Assume number over 10 + byte3:=byte3-48 + byte2:=byte2-48 + byte3:=byte3*10 + byte3:=byte3+byte2 + var1:=byte3 + if byte3 == 91 '' Assume number is less 10 + byte2:=byte2-48 + var1:=byte2 + if byte2 == 91 ''ESC[D no numbers move LEFT one + + var1 := 1 + loop:=0 + repeat until loop == var1 + text.out($C0) 'was $C0 + loop++ + vt100:=0 + + if remote == 75 '' Clear line Esc[K + if byte2 == 91 '' Look for [ + text.clearlinefromcursor + + vt100:=0 + if byte2 == 48 ' look for [0K + if byte3 == 91 + text.clearlinefromcursor + + vt100:=0 + if byte2 == 49 ' look for [1K + if byte3 == 91 + text.clearlinetocursor + vt100 := 0 + if byte2 == 50 ' look for [2K + if byte3 == 91 + text.clearline + + vt100 := 0 + + if remote == 99 ' look for [0c or [c ESC [ ? 1 ; Ps c Ps=0 for VT-100 no options + if byte2 == 91 '' Look for [ + ser2.str(string(27,"[?1;0c")) + vt100 := 0 + if byte2 == 48 + if byte3 == 91 + ser2.str(string(27,"[?1;0c")) + vt100 := 0 + remote:=0 '' hide all codes from the VGA output. + + if record == 13 and remote == 13 ''LF CHECK + if CR == 1 + text.out(remote) + remote :=0 + if remote == 08 + remote := $C0 'now backspace just moves cursor, doesn't clear character + if remote == 7 + sound(source, 4500) + ' if remote == 10 + ' text.out($0A) + if remote > 8 + text.out(remote) + record:=remote ''record last byte + + +PUB EEPROM | eepromData + eepromLocation := EEPROM_Base + + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, 55) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, Baud) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, termcolor) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, pcport) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, ascii) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, curset) + eepromLocation +=4 + i2c.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, CR) + waitcnt(clkfreq/200 + cnt) + + + +PUB Sound (pWav,speed):bOK|n,i,nextCnt,rate,dcnt,wait + + pWav+=44 + + i:=0 + NextCnt:=cnt '+15000 + + 'Play loop + repeat i from 0 to 1200 + NextCnt+=speed + waitcnt(NextCnt) + FRQA:=(byte[pWav+i])<<24 + FRQB:=FRQA + +PUB forever | i + repeat i from 0 to 1000 + waitcnt(i*32767) +DAT + +PIANO +File "piano.wav" ' <--- put your 8-bit PCM mono 8000 sample/second WAV \ No newline at end of file diff --git a/software/6502_terminal_propeller/VGA_1024v.905.spin b/software/6502_terminal_propeller/VGA_1024v.905.spin new file mode 100644 index 0000000..f842fce --- /dev/null +++ b/software/6502_terminal_propeller/VGA_1024v.905.spin @@ -0,0 +1,647 @@ +'' VGA_1024.spin +'' +'' MODIFIED BY VINCE BRIEL FOR POCKETERM FEATURES +'' MODIIFED BY JEFF LEDGER / AKA OLDBITCOLLECTOR +'' + +CON + cols = 128 '128 ' number of screen columns + rows = 64 '64 ' number of screen rows + chars = rows*cols ' number of screen characters + esc = $CB ' keyboard esc char + rowsnow = 36 ' adjusted for split screen effect + chars1 = rowsnow*cols ' adjusted value for split screen effect + cols1 = 81 ' adjusted value for 80th character + TURQUOISE = $29 + +OBJ + vga : "vga_Hires_Text" + +VAR + byte screen[chars] ' screen character buffer + word colors[rows] ' color specs for each screen row (see ColorPtr description above) + byte cursor[6] ' cursor info array (see CursorPtr description above) + long sync, loc, xloc, yloc ' sync used by VGA routine, others are local screen pointers + long kbdreq ' global val of kbdflag + long BR[8] + long Brate + byte inverse + byte invs +PUB start(BasePin) | i, char + + +''start vga + vga.start(BasePin, @screen, @colors, @cursor, @sync) + waitcnt(clkfreq * 1 + cnt) 'wait 1 second for cogs to start + +''init screen colors to gold on blue + repeat i from 0 to rows - 1 + colors[i] := $08F0 '$2804 (if you want cyan on blue) + +''init cursor attributes + cursor[2] := %110 ' init cursor to underscore with slow blink + BR[0]:=300 + BR[1]:=1200 + BR[2]:=2400 + BR[3]:=4800 + BR[4]:=9600 + BR[5]:=19200 + BR[6]:=38400 + BR[7]:=57600 + BR[8]:=115200 + xloc := cursor[0] := 0 + yloc := cursor[1] := 0 + loc := xloc + yloc*cols + +PUB inv(c) + inverse:=c +PUB cursorset(c) | i + i:=%000 + if c == 1 + i:= %001 + if c == 2 + i:= %010 + if c == 3 + i:= %011 + if c == 4 + i:= %101 + if c == 5 + i:= %110 + if c == 6 + i:= %111 + if c == 7 + i:= %000 + cursor[2] := i +PUB bin(value, digits) + +'' Print a binary number, specify number of digits + + repeat while digits > 32 + out("0") + digits-- + + value <<= 32 - digits + + repeat digits + out((value <-= 1) & 1 + "0") + +'PUB binFP(value) | bitnum, bit, bitval +'' Prints FP long in special Binary format: sign, exp, mantissa + +' repeat bitnum from 31 to 0 +' bit := 1 << bitnum ' create mask bit +' bitval := (bit & value) >> bitnum ' extract bit and shift back to bit 0 + +' bin(bitval, 1) ' display one bit + +' case bitnum +' 27,20,16,12,8,4: out($20) ' space after every 4 in group +' 31,23: str(string(" ")) ' two after sign and exponent + +PUB insertat(amount) | i,j,len + len := (cols - xloc) - amount + i := @screen 'starting location + i := i + loc + j := i + amount 'new location which is plus 1? + bytemove(j,i, len) ' move chars over one + bytefill(i, $20,amount) + +PUB delp(amount) | i,j,len + + len := (cols - xloc) - amount + i := @screen 'starting location + i := i + loc + j := i + amount 'new location which is plus 1? + bytemove(i,j, len) ' move chars over one + 'bytefill(j, $20,amount) + +PUB cls(c,screencolor,pcport,ascii,CR) | i,x,y + + + x :=xloc + y := yloc + invs := inverse + clrbtm(TURQUOISE) + longfill(@screen, $20202020, chars/4) + xloc := 0 + yloc :=0 + loc := xloc + yloc*cols + repeat 80 + out(32) + xloc := 0 + yloc :=36 + loc := xloc + yloc*cols + inverse := 1 + str(string(" 6502 SATCOM V1.2 ")) + inverse := 0 + str(string("Baud Rate: ")) + i:= BR[c] + dec(i) + str(string(" ")) + xloc := 18 + loc := xloc + yloc*cols + str(string("Color ")) + str(string("PC Port: ")) + if pcport == 1 + str(string("OFF ")) + if pcport == 0 + str(string("ON ")) + str(string(" Force 7 bit: ")) + if ascii == 0 + str(string("NO ")) + if ascii == 1 + str(string("YES ")) + str(string(" Cursor CR W/LF: ")) + if CR == 1 + str(string("YES")) + if CR == 0 + str(string("NO ")) + out(13) + out(10) + + inverse:=1 + xloc := 6 + loc := xloc + yloc*cols + str(string("F1")) + xloc := 19 + loc := xloc + yloc*cols + str(string("F2")) + xloc := 30 + loc := xloc + yloc*cols + str(string("F3")) + xloc := 46 + loc := xloc + yloc*cols + str(string("F4")) + xloc := 58 + loc := xloc + yloc*cols + str(string("F5")) + xloc := 70 + loc := xloc + yloc*cols + str(string("F6")) + inverse := invs + xloc := cursor[0] := x 'right & left was 0 + yloc := cursor[1] := y 'from top was 1 + loc := xloc + yloc*cols + +PUB clsupdate(c,screencolor,PCPORT,ascii,CR) | i,x,y,locold + + invs := inverse + locold := loc + x := xloc + y := yloc + clrbtm(TURQUOISE) + xloc := 0 + yloc :=36 + loc := xloc + yloc*cols + inverse := 1 + str(string(" PockeTerm V.905 ")) + inverse := 0 + xloc := 0 + yloc :=37 + loc := xloc + yloc*cols + str(string("Baud Rate: ")) + i:= BR[c] + dec(i) + str(string(" ")) + xloc := 18 + loc := xloc + yloc*cols + + str(string("Color ")) + str(string("PC Port: ")) + if pcport == 1 + str(string("OFF ")) + if pcport == 0 + str(string("ON ")) + str(string(" Force 7 bit: ")) + if ascii == 0 + str(string("NO ")) + if ascii == 1 + str(string("YES ")) + str(string(" Cursor CR W/LF: ")) + if CR == 1 + str(string("YES")) + if CR == 0 + str(string("NO ")) + xloc := 0 + yloc :=38 + loc := xloc + yloc*cols + inverse:=1 + xloc := 6 + loc := xloc + yloc*cols + str(string("F1")) + xloc := 19 + loc := xloc + yloc*cols + str(string("F2")) + xloc := 30 + loc := xloc + yloc*cols + str(string("F3")) + xloc := 46 + loc := xloc + yloc*cols + str(string("F4")) + xloc := 58 + loc := xloc + yloc*cols + str(string("F5")) + xloc := 70 + loc := xloc + yloc*cols + str(string("F6")) + inverse := invs + xloc := cursor[0] := x + yloc := cursor[1] := y +' loc := xloc + yloc*cols + loc := locold + +PUB clearlinefromcursor | x,xx,y, loop + + y := cursor[1] 'yloc + x := cursor[0] 'xloc + xx := cursor[0] 'xloc + + repeat until xx == 80 + out(32) + xx++ + + yloc := cursor[1] := y + xloc := cursor[0] := x + loc := xloc + yloc*cols + +PUB clearlinetocursor | x,y,loop + + x := xloc + xloc := loop := 0 + loc := xloc + yloc*cols + repeat until loop == x + out(32) + loop++ + xloc := x + loc := xloc + yloc*cols + +PUB clearline | x,y + + x := xloc + xloc := 0 + loc := xloc + yloc*cols + repeat 80 + out(32) + xloc := x + loc := xloc + yloc*cols + +PUB clsfromcursordown | x,y,loop,i + x:=xloc + y:=yloc + + i := rowsnow - y + i-- + 'xloc :=0 + loop := 0 + 'loc := xloc + yloc*cols + repeat until xloc == 80 + out(32) + xloc := 0 + yloc++ + loc := xloc + yloc*cols + loop := yloc + repeat until loop == rowsnow + str(string(" ")) + loop++ + xloc := cursor[0] := x + yloc := cursor[1] := y + loc := xloc + yloc*cols + +PUB clstocursor | x,y,z,loop 'working correctly now + y := yloc + x := xloc + xloc :=0 + loc := xloc + yloc*cols + repeat until xloc == x + out(32) + yloc := 0 + z:=0 + 'repeat until z == y-1 + repeat until z == y + yloc := z + xloc :=0 + loc := xloc + yloc*cols + str(string(" ")) + z:= z + 1 +' yloc-- +' repeat until yloc <= 0 +' xloc :=0 +' loc := xloc + yloc*cols +' repeat 80 +' out(65) +' yloc-- +' xloc := 0 +' loc := xloc + yloc*cols +' repeat 80 +' out(32) + xloc := cursor[0] := x + yloc := cursor[1] := y + loc := xloc + yloc*cols + +PUB home + + xloc := cursor[0] := 0 'right & left + yloc := cursor[1] := 0 'from top 'was 1 + loc := xloc + yloc*cols + +PUB color(ColorVal) | i +''reset screen colors + repeat i from 0 to rowsnow - 1 + colors[i] := $0000 + ColorVal + +PUB clrbtm(ColorVal) | i + repeat i from 36 to rows - 1 'was 35 + colors[i] := $0000 + ColorVal +PUB rowcolor(ColorVal, row) +'' reset row color to colorval + if row > rows-1 + row := rows-1 + + colors[row] := $0000 + ColorVal + + +PUB cursloc(x, y) + +'' move cursor to x, y position + +'my code fix for y axis 1 is actually 0 +' y-- + + + xloc := cursor[0] := x + yloc := cursor[1] := y + loc := xloc + yloc*cols +PUB cursrow(y) + +'' move cursor to y position + +' xloc := cursor[0] := x + yloc := cursor[1] := y + loc := xloc + yloc*cols +PUB dec(value) | i + +'' Print a decimal number + + if value < 0 + -value + out("-") + + i := 1_000_000_000 + + repeat 10 + if value => i + out(value/i + "0") + value //= i + result~~ + elseif result or i == 1 + out("0") + i /= 10 + +PUB hex(value, digits) + +'' Print a hexadecimal number, specify number of digits + + repeat while digits > 8 + out("0") + digits-- + + value <<= (8 - digits) << 2 + + repeat digits + out(lookupz((value <-= 4) & $f : "0".."9", "A".."F")) + +PUB scrollD | i,len,y,dest,source + + y := yloc * cols + i := @screen + dest := i + y + source := dest + cols + len := (chars1-y-80)/4 + longmove(source, dest, len) + longfill(dest,$20202020, cols/4) + + + +PUB scrollM | i,y,dest,source,len + 'longmove(dest,source,length) + y := yloc * cols + i := @screen + dest := i + y + 'len := (chars1-y)/4 + len := (chars1-y-80)/4 + source := dest + cols + longmove(dest,source,len) + + +PRI newline | i, j, len + if ++yloc == rowsnow ' if last line on screen, shift all up was just rows now says rowsnow + yloc-- ' reset yloc it at bottom of screen + i := @screen + i += cols + len := (chars1 - cols)/4 'was chars now rowsnow*cols (rowsnow*cols) + longmove(@screen, i, len) ' shift screen up one line + + i := @screen + i += ((rowsnow*cols) - cols) ' set "i" for use below WAS CHARS NOW ROWSNOW*COLS + + else ' if not last line, shift lines down + i := @screen + i += (rowsnow - 2)*cols ' init ptr to start of next-to-last line was -2 now -1 + + 'if yloc < rows - 1 + ' repeat j from rows - 2 to yloc + ' longmove(i + cols, i, cols/4) ' shift one line down + ' i -= cols ' move i up one line + + i += cols ' point to start of last line moved + + longfill(i, $20202020, cols/4) ' clear the last line moved + + + j := i - cols + xloc ' point to original cursor location + bytemove(i, j, cols - xloc) ' move chars from cursor pos down to start of next line + + bytefill(j, $20, cols - xloc) ' clear original part of line that was moved + + xloc := cursor[0] := 0 ' reset xloc, loc and cursor position + cursor[1] := yloc + loc := yloc*cols +PRI linefeed | i, j, len + if ++yloc == rowsnow ' if last line on screen, shift all up was just rows now says rowsnow + yloc-- ' reset yloc it at bottom of screen + i := @screen + + + i += cols + + len := (chars1 - cols)/4 'was chars now rowsnow*cols (rowsnow*cols) + longmove(@screen, i, len) ' shift screen up one line + + i := @screen + i += ((rowsnow*cols) - cols) ' set "i" for use below WAS CHARS NOW ROWSNOW*COLS + + else ' if not last line, shift lines down + i := @screen + i += (rowsnow - 2)*cols ' init ptr to start of next-to-last line was -2 now -1 + i += cols ' point to start of last line moved + longfill(i, $20202020, cols/4) ' clear the last line moved + 'j := i - cols + xloc ' point to original cursor location + j := i + xloc + bytemove(i, j, cols - xloc) ' move chars from cursor pos down to start of next line + + bytefill(j, $20, cols - xloc) ' clear original part of line that was moved + + cursor[1] := yloc + cursor[0] := xloc + loc := xloc + (yloc*cols) +PUB out(c) | i, j +'' Print a character +'' +'' $09 = tab +'' $0A = Linefeed +'' $0D = return -> CR +'' $20..$7E = display character +'' $7F = skip +'' $C0 left arrow +'' $C1 = right arrow +'' $C2 = up arrow +'' $C3 = down arrow +'' $C4 = home key - go to beginning of line +'' $C5 = end key - go past last char on line +'' $C6 = page up key - skip this key +'' $C7 = page down key - skip this key +'' $C8 = backspace key +'' $C9 = delete key +'' $CA = insert key - skip this key +'' $CB = esc - skip this key +'' $CC = left arrow don't scroll up + case c + $09: ' tab command + repeat + out($C1) ' recursive call to out( ) + while xloc & 7 ' tab to multiples of 8 + 'while xloc & 3 ' tab to multiples of 4 + $0A: + linefeed + $0D: ' CR, return to start of line + if xloc + repeat + out($C0) ' recursive call to shift left until at leftmost edge + while xloc + $20..$7E: ' character + + if inverse==1 'check for inverse character mode + c:=c + $80 'add for inverse + if ++xloc == cols1 + xloc := xloc - 1 + newline + xloc := cursor[0] := 1 + screen[loc++] := c ' output the character + cursor[0] := xloc + cursor[1] := yloc + + + + $C0: ' left arrow + if loc ' skip this if at upper left screen + loc-- + if xloc + xloc-- + else + xloc := cols - 1 + yloc-- + cursor[0] := xloc + cursor[1] := yloc + + + + $C1: ' right arrow + if loc <> chars1 - 1 ' skip if at lower right of screen + loc++ + if xloc <> cols - 1 + xloc++ + else + xloc := 0 + yloc++ + cursor[0] := xloc + cursor[1] := yloc + + $C2: ' up arrow + if yloc ' skip if yloc at top of screen + yloc-- ' move yloc up one row + loc -= cols ' move loc var back one row + cursor[1] := yloc ' reset 'y' cursor position + + $C3: ' down arrow + if yloc <> rowsnow - 1 ' skip if at bottom of screen + yloc++ ' move yloc dowm one row + loc += cols ' move loc var down one row + cursor[1] := yloc + + $C4: ' home key - move to 1st char of line + xloc := cursor[0] := 0 + loc := xloc + yloc*cols + + $C5: ' end key - move to last char of line + if xloc <> cols - 1 + repeat xloc from cols - 1 to 0 + loc := xloc + yloc*cols + if screen[loc] <> $20 ' continue until first non-space char + if xloc <> cols - 1 + xloc++ ' move past non-blank char + loc++ + quit + + cursor[0] := xloc ' loc is already reset from above + + $C8: ' backspace + if loc ' skip if at upper left of screen + if xloc ' do 'else' if at start of line + xloc-- ' xloc left one space + loc-- + + i := @screen ' calculate + i += xloc + yloc*cols ' destination for shift left one + bytemove(i, i+1, cols - xloc - 1) + screen[cols - 1 + yloc*cols] := $20 + + else ' here if xloc == 0 + if screen[loc-1] == $20 ' last char on prev line + yloc-- + + i := @screen ' calculate + i += loc - 1 ' destination for shift left one + + repeat while screen[--loc] == $20 + bytemove(i, i+1, cols) ' move one row's worth of chars + i-- ' dec "i" to correspond to --loc + + screen[loc + cols] := $20 ' clear old char + + if ++xloc == cols ' use xloc as counter here, 0..., don't move > 1 row + loc-- ' make as if loc had been bumped above B4 we quit + quit + + loc++ ' bump loc to space char + xloc := loc - yloc*cols ' re-calculate xloc from loc and yloc + + cursor[0] := xloc ' reset cursor loc + cursor[1] := yloc + + $C9: ' delete + if xloc == cols - 1 + screen[loc] := $20 ' if at last char on line, clear it and exit + + else + repeat i from xloc to cols - 2 + j := i + yloc*cols + screen[j] := screen[j+1] + + screen[j+1] := $20 ' clear last char on line after shift left + +PUB str(string_ptr) + +'' Print a zero terminated string + + repeat strsize(string_ptr) + out(byte[string_ptr++]) \ No newline at end of file diff --git a/software/6502_terminal_propeller/VGA_HiRes_Text.spin b/software/6502_terminal_propeller/VGA_HiRes_Text.spin new file mode 100644 index 0000000..6bc4e98 Binary files /dev/null and b/software/6502_terminal_propeller/VGA_HiRes_Text.spin differ diff --git a/software/6502_terminal_propeller/piano.wav b/software/6502_terminal_propeller/piano.wav new file mode 100644 index 0000000..0336fca Binary files /dev/null and b/software/6502_terminal_propeller/piano.wav differ