From 45fec70be249e1e76b79038d656b2f341b56fcce Mon Sep 17 00:00:00 2001 From: jth0mass0n Date: Mon, 17 Apr 2017 10:21:28 -0700 Subject: [PATCH] propeller terminal code --- .../6502_terminal.binary | Bin 0 -> 16344 bytes .../6502_terminal.spin | 680 +++++++++++++++++ .../Basic_I2C_Driver.spin | 272 +++++++ .../FullDuplexSerial256.spin | 336 +++++++++ .../FullDuplexSerial2562.spin | 336 +++++++++ .../6502_terminal_propeller/Keyboard.spin | Bin 0 -> 57812 bytes .../PockeTermV.905.binary | Bin 0 -> 16300 bytes .../PockeTermV.905.spin | 701 ++++++++++++++++++ .../VGA_1024v.905.spin | 647 ++++++++++++++++ .../VGA_HiRes_Text.spin | Bin 0 -> 53266 bytes software/6502_terminal_propeller/piano.wav | Bin 0 -> 5595 bytes 11 files changed, 2972 insertions(+) create mode 100644 software/6502_terminal_propeller/6502_terminal.binary create mode 100644 software/6502_terminal_propeller/6502_terminal.spin create mode 100644 software/6502_terminal_propeller/Basic_I2C_Driver.spin create mode 100644 software/6502_terminal_propeller/FullDuplexSerial256.spin create mode 100644 software/6502_terminal_propeller/FullDuplexSerial2562.spin create mode 100644 software/6502_terminal_propeller/Keyboard.spin create mode 100644 software/6502_terminal_propeller/PockeTermV.905.binary create mode 100644 software/6502_terminal_propeller/PockeTermV.905.spin create mode 100644 software/6502_terminal_propeller/VGA_1024v.905.spin create mode 100644 software/6502_terminal_propeller/VGA_HiRes_Text.spin create mode 100644 software/6502_terminal_propeller/piano.wav diff --git a/software/6502_terminal_propeller/6502_terminal.binary b/software/6502_terminal_propeller/6502_terminal.binary new file mode 100644 index 0000000000000000000000000000000000000000..e1b9b282848c5d63bfc1d0b140fad90173a59990 GIT binary patch literal 16344 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 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 0000000000000000000000000000000000000000..d8c197ed9a34a162cd4a3bd31e72f621d4680574 GIT binary patch literal 57812 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

9|e5ZDtsJp<|=%W^pxB=2U;3DL0<^?e$;X2 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 RZa& 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 0000000000000000000000000000000000000000..6bc4e9871366c18da995f4163b476a8fe451d9e1 GIT binary patch literal 53266 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 literal 0 HcmV?d00001 diff --git a/software/6502_terminal_propeller/piano.wav b/software/6502_terminal_propeller/piano.wav new file mode 100644 index 0000000000000000000000000000000000000000..0336fcab3f2d611d54a53315ee49ba7e1569e591 GIT binary patch literal 5595 zcmXX~S94qGd6w^Tm)v9~GnvG3?47mOYe{P@B`sB00RkWi5S?fwKy-i=B-lyxa&UUb zIp`q40)m}bk`g6xSF3f~c-D@c*vX}5lF4N9AM(k`U@*9O@V)Q%mgjlS(a5FJfBx$` zcZ@v-iDzozAO7mjojczFpYHG8`SbTXcmCpz%dy}%1{kE8LF?Jt;m^K(xwTjjBk{G&&6}5p*MDfQ_%h5qn#>8i-~Q|GZWyomUgy1^IzR5}y|0s*VX=%5Ki0K-~adP{ZdI3xEfsAdi5XQ z{^26GIDGfVKfZVG?%gNP?^{DVrKK0Ydr_cMcqE6e;K{>Z{qnb0Ow|1F-jD9yyZ=%5 zXB|r4ULkV$$2UhJCTt2&GPl`y_08|!HTY?D*VE3fXPsK<;Na{*Gu8Uzmv4mDz<+9YG;?BXp+OC`O=%;{`%*a<&d?zr}NW}r+vNmJ5V&r?f=u4mq)dH zo-Si4l4^hb%@?oAk+Gg<4?g**^O5{}AFi)O;>DLQ&ku?$h83V}650OZ-P

QJ3=B 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 E1=w}g2><{9 literal 0 HcmV?d00001