Auto boot with recovery and improved VT100 support (#45)

* Improve vt100 support to make vim work

* Fix home and add line clear

* Auto boot with recovery
This commit is contained in:
Terence Boldt 2021-11-25 18:45:56 -05:00 committed by GitHub
parent 453a644a0b
commit 5910d66fa2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 513 additions and 257 deletions

Binary file not shown.

View File

@ -16,6 +16,7 @@ OutputByte = $c08d+SLOT*$10
InputFlags = $c08b+SLOT*$10 InputFlags = $c08b+SLOT*$10
OutputFlags = $c087+SLOT*$10 OutputFlags = $c087+SLOT*$10
ResetCommand = $00
ReadBlockCommand = $01 ReadBlockCommand = $01
WriteBlockCommand = $02 WriteBlockCommand = $02
GetTimeCommand = $03 GetTimeCommand = $03
@ -29,6 +30,11 @@ Wait = $fca8
PrintChar = $fded PrintChar = $fded
Home = $fc58 Home = $fc58
ReadChar = $fd0c ReadChar = $fd0c
BasCalc = $fbc1
htab = $24
vtab = $25
BasL = $28
htab80 = $057b
.org SLOT*$100 + $C000 .org SLOT*$100 + $C000
;ID bytes for booting and drive detection ;ID bytes for booting and drive detection
@ -57,7 +63,10 @@ Start:
sta $36 sta $36
lda #$fd lda #$fd
sta $37 sta $37
jsr Home ;clear screen and show menu options ;jsr Home ;clear screen and show menu options
lda #$10
sta vtab
jsr BasCalc
ldy #$00 ldy #$00
PrintString: PrintString:
lda Text,y lda Text,y
@ -70,36 +79,36 @@ PrintString:
WaitForRPi: WaitForRPi:
lda InputFlags lda InputFlags
rol rol
bcs OK bcs Reset
lda #$ff lda #$ff
jsr Wait jsr Wait
lda #'.'+$80 lda #'.'+$80
jsr PrintChar jsr PrintChar
jmp WaitForRPi jmp WaitForRPi
OK: Reset:
jsr Home ;clear screen lda #'_'|$80
lda #MenuCommand ;request menu text from RPi
jsr SendByte
DumpOutput:
jsr GetByte
cmp #$00
beq GetChar
jsr PrintChar jsr PrintChar
clc lda #ResetCommand
bcc DumpOutput jsr SendByte
lda #$88
jsr PrintChar
lda #'.'|$80
jsr PrintChar
jsr GetByte
beq Ok
jmp Reset
GetChar: Ok:
jsr ReadChar lda #$8D
sec ;subtract ascii "1" to get 0 - 3 from "1" to "4" jsr PrintChar
sbc #$b1 lda #'O'|$80
asl ;put in top nibble as EPROM page jsr PrintChar
asl lda #'K'|$80
asl jsr PrintChar
asl
ora #$0f ;set all flags high Boot:
lda #$0f
jmp PageJump jmp PageJump
SendByte: SendByte:

View File

@ -20,6 +20,7 @@ Current file: MenuFirmware.asm
000000r 1 InputFlags = $c08b+SLOT*$10 000000r 1 InputFlags = $c08b+SLOT*$10
000000r 1 OutputFlags = $c087+SLOT*$10 000000r 1 OutputFlags = $c087+SLOT*$10
000000r 1 000000r 1
000000r 1 ResetCommand = $00
000000r 1 ReadBlockCommand = $01 000000r 1 ReadBlockCommand = $01
000000r 1 WriteBlockCommand = $02 000000r 1 WriteBlockCommand = $02
000000r 1 GetTimeCommand = $03 000000r 1 GetTimeCommand = $03
@ -33,6 +34,11 @@ Current file: MenuFirmware.asm
000000r 1 PrintChar = $fded 000000r 1 PrintChar = $fded
000000r 1 Home = $fc58 000000r 1 Home = $fc58
000000r 1 ReadChar = $fd0c 000000r 1 ReadChar = $fd0c
000000r 1 BasCalc = $fbc1
000000r 1 htab = $24
000000r 1 vtab = $25
000000r 1 BasL = $28
000000r 1 htab80 = $057b
000000r 1 000000r 1
000000r 1 .org SLOT*$100 + $C000 000000r 1 .org SLOT*$100 + $C000
00C700 1 ;ID bytes for booting and drive detection 00C700 1 ;ID bytes for booting and drive detection
@ -61,95 +67,94 @@ Current file: MenuFirmware.asm
00C71B 1 85 36 sta $36 00C71B 1 85 36 sta $36
00C71D 1 A9 FD lda #$fd 00C71D 1 A9 FD lda #$fd
00C71F 1 85 37 sta $37 00C71F 1 85 37 sta $37
00C721 1 20 58 FC jsr Home ;clear screen and show menu options 00C721 1 ;jsr Home ;clear screen and show menu options
00C724 1 A0 00 ldy #$00 00C721 1 A9 10 lda #$10
00C726 1 PrintString: 00C723 1 85 25 sta vtab
00C726 1 B9 BC C7 lda Text,y 00C725 1 20 C1 FB jsr BasCalc
00C729 1 F0 08 beq WaitForRPi 00C728 1 A0 00 ldy #$00
00C72B 1 09 80 ora #$80 00C72A 1 PrintString:
00C72D 1 20 ED FD jsr PrintChar 00C72A 1 B9 BC C7 lda Text,y
00C730 1 C8 iny 00C72D 1 F0 08 beq WaitForRPi
00C731 1 D0 F3 bne PrintString 00C72F 1 09 80 ora #$80
00C733 1 00C731 1 20 ED FD jsr PrintChar
00C733 1 WaitForRPi: 00C734 1 C8 iny
00C733 1 AD FB C0 lda InputFlags 00C735 1 D0 F3 bne PrintString
00C736 1 2A rol 00C737 1
00C737 1 B0 0D bcs OK 00C737 1 WaitForRPi:
00C739 1 A9 FF lda #$ff 00C737 1 AD FB C0 lda InputFlags
00C73B 1 20 A8 FC jsr Wait 00C73A 1 2A rol
00C73E 1 A9 AE lda #'.'+$80 00C73B 1 B0 0D bcs Reset
00C740 1 20 ED FD jsr PrintChar 00C73D 1 A9 FF lda #$ff
00C743 1 4C 33 C7 jmp WaitForRPi 00C73F 1 20 A8 FC jsr Wait
00C746 1 00C742 1 A9 AE lda #'.'+$80
00C746 1 OK: 00C744 1 20 ED FD jsr PrintChar
00C746 1 20 58 FC jsr Home ;clear screen 00C747 1 4C 37 C7 jmp WaitForRPi
00C749 1 00C74A 1
00C749 1 A9 08 lda #MenuCommand ;request menu text from RPi 00C74A 1 Reset:
00C74B 1 20 6A C7 jsr SendByte 00C74A 1 A9 DF lda #'_'|$80
00C74E 1 00C74C 1 20 ED FD jsr PrintChar
00C74E 1 DumpOutput: 00C74F 1 A9 00 lda #ResetCommand
00C74E 1 20 88 C7 jsr GetByte 00C751 1 20 7A C7 jsr SendByte
00C751 1 C9 00 cmp #$00 00C754 1 A9 88 lda #$88
00C753 1 F0 06 beq GetChar 00C756 1 20 ED FD jsr PrintChar
00C755 1 20 ED FD jsr PrintChar 00C759 1 A9 AE lda #'.'|$80
00C758 1 18 clc 00C75B 1 20 ED FD jsr PrintChar
00C759 1 90 F3 bcc DumpOutput 00C75E 1 20 98 C7 jsr GetByte
00C75B 1 00C761 1 F0 03 beq Ok
00C75B 1 GetChar: 00C763 1 4C 4A C7 jmp Reset
00C75B 1 20 0C FD jsr ReadChar 00C766 1
00C75E 1 38 sec ;subtract ascii "1" to get 0 - 3 from "1" to "4" 00C766 1 Ok:
00C75F 1 E9 B1 sbc #$b1 00C766 1 A9 8D lda #$8D
00C761 1 0A asl ;put in top nibble as EPROM page 00C768 1 20 ED FD jsr PrintChar
00C762 1 0A asl 00C76B 1 A9 CF lda #'O'|$80
00C763 1 0A asl 00C76D 1 20 ED FD jsr PrintChar
00C764 1 0A asl 00C770 1 A9 CB lda #'K'|$80
00C765 1 09 0F ora #$0f ;set all flags high 00C772 1 20 ED FD jsr PrintChar
00C767 1 4C 0E C7 jmp PageJump 00C775 1
00C76A 1 00C775 1 Boot:
00C76A 1 SendByte: 00C775 1 A9 0F lda #$0f
00C76A 1 48 pha 00C777 1 4C 0E C7 jmp PageJump
00C76B 1 waitWrite: 00C77A 1
00C76B 1 AD FB C0 lda InputFlags 00C77A 1 SendByte:
00C76E 1 2A rol 00C77A 1 48 pha
00C76F 1 2A rol 00C77B 1 waitWrite:
00C770 1 B0 F9 bcs waitWrite
00C772 1 68 pla
00C773 1 8D FD C0 sta OutputByte
00C776 1 A9 3E lda #$3e ; set bit 0 low to indicate write started
00C778 1 8D F7 C0 sta OutputFlags
00C77B 1 finishWrite:
00C77B 1 AD FB C0 lda InputFlags 00C77B 1 AD FB C0 lda InputFlags
00C77E 1 2A rol 00C77E 1 2A rol
00C77F 1 2A rol 00C77F 1 2A rol
00C780 1 90 F9 bcc finishWrite 00C780 1 B0 F9 bcs waitWrite
00C782 1 A9 3F lda #$3f 00C782 1 68 pla
00C784 1 8D F7 C0 sta OutputFlags 00C783 1 8D FD C0 sta OutputByte
00C787 1 60 rts 00C786 1 A9 3E lda #$3e ; set bit 0 low to indicate write started
00C788 1 00C788 1 8D F7 C0 sta OutputFlags
00C788 1 GetByte: 00C78B 1 finishWrite:
00C788 1 A9 3D lda #$3d ;set read flag low 00C78B 1 AD FB C0 lda InputFlags
00C78A 1 8D F7 C0 sta OutputFlags 00C78E 1 2A rol
00C78D 1 waitRead: 00C78F 1 2A rol
00C78D 1 AD FB C0 lda InputFlags 00C790 1 90 F9 bcc finishWrite
00C790 1 2A rol 00C792 1 A9 3F lda #$3f
00C791 1 B0 FA bcs waitRead 00C794 1 8D F7 C0 sta OutputFlags
00C793 1 AD FE C0 lda InputByte 00C797 1 60 rts
00C796 1 48 pha 00C798 1
00C797 1 A9 3F lda #$3f ;set all flags high 00C798 1 GetByte:
00C799 1 8D F7 C0 sta OutputFlags 00C798 1 A9 3D lda #$3d ;set read flag low
00C79C 1 finishRead: 00C79A 1 8D F7 C0 sta OutputFlags
00C79C 1 AD FB C0 lda InputFlags 00C79D 1 waitRead:
00C79F 1 2A rol 00C79D 1 AD FB C0 lda InputFlags
00C7A0 1 90 FA bcc finishRead 00C7A0 1 2A rol
00C7A2 1 68 pla 00C7A1 1 B0 FA bcs waitRead
00C7A3 1 end: 00C7A3 1 AD FE C0 lda InputByte
00C7A3 1 60 rts 00C7A6 1 48 pha
00C7A4 1 00C7A7 1 A9 3F lda #$3f ;set all flags high
00C7A4 1 00 00 00 00 .repeat 187-<end 00C7A9 1 8D F7 C0 sta OutputFlags
00C7A8 1 00 00 00 00 00C7AC 1 finishRead:
00C7AC 1 00 00 00 00 00C7AC 1 AD FB C0 lda InputFlags
00C7B0 1 00 00 00 00 00C7AF 1 2A rol
00C7B4 1 00 00 00 00 00C7B0 1 90 FA bcc finishRead
00C7B2 1 68 pla
00C7B3 1 end:
00C7B3 1 60 rts
00C7B4 1
00C7B4 1 00 00 00 00 .repeat 187-<end
00C7B8 1 00 00 00 00 00C7B8 1 00 00 00 00
00C7BC 1 .byte 0 00C7BC 1 .byte 0
00C7BC 1 .endrepeat 00C7BC 1 .endrepeat

View File

@ -37,8 +37,15 @@ ClearKeyboard = $c010
Home = $fc58 Home = $fc58
Wait = $fca8 Wait = $fca8
PromptChar = $33 PromptChar = $33
Read80Col = $c01f
TextPage1 = $c054
TextPage2 = $c055
htab = $24 htab = $24
vtab = $25 vtab = $25
BasL = $28
htab80 = $057b
BasCalc = $fbc1
ESC = $9b ESC = $9b
@ -56,6 +63,9 @@ DumpOutput:
bcs checkInput bcs checkInput
cmp #$00 cmp #$00
beq endOutput beq endOutput
pha
jsr InvertChar
pla
cmp #'H' cmp #'H'
beq setColumn beq setColumn
cmp #'V' cmp #'V'
@ -65,8 +75,11 @@ DumpOutput:
cmp #'T' cmp #'T'
beq setTop beq setTop
cmp #'B' cmp #'B'
beq setBottom beq setBottom
cmp #'U'
beq moveUp
jsr PrintChar jsr PrintChar
jsr InvertChar
jmp DumpOutput jmp DumpOutput
checkInput: checkInput:
bit Keyboard ;check for keypress bit Keyboard ;check for keypress
@ -80,25 +93,35 @@ endOutput:
rts rts
clearScreen: clearScreen:
jsr Home jsr Home
jsr InvertChar
jmp DumpOutput jmp DumpOutput
setColumn: setColumn:
jsr GetByte jsr GetByte
sta htab sta htab
sta $057B sta htab80
jsr InvertChar
jmp DumpOutput jmp DumpOutput
setRow: setRow:
jsr GetByte jsr GetByte
sta vtab sta vtab
jsr $fbc1 ; bascalc jsr BasCalc
sta $28 ;basl jsr InvertChar
jmp DumpOutput jmp DumpOutput
setTop: setTop:
jsr GetByte jsr GetByte
sta $22 sta $22
jsr InvertChar
jmp DumpOutput jmp DumpOutput
setBottom: setBottom:
jsr GetByte jsr GetByte
sta $23 sta $23
jsr InvertChar
jmp DumpOutput
moveUp:
dec vtab
lda vtab
jsr BasCalc
jsr InvertChar
jmp DumpOutput jmp DumpOutput
SendByte: SendByte:
@ -148,9 +171,26 @@ finishRead:
end: end:
rts rts
InvertChar:
lda htab80 ;get horizontal location / 2
lsr
tay
lda TextPage2
bcc invert
lda TextPage1
invert:
lda (BasL),y
eor #$80
sta (BasL),y
lda TextPage1
screen40:
rts
HelpCommand: HelpCommand:
.byte "a2help",$00 .byte "a2help",$00
PromptCommand: PromptCommand:
.byte "a2prompt",$00 .byte "a2prompt",$00
OldPromptChar: OldPromptChar:
.byte "]" .byte "]"
DrawCursor:
.byte $80

Binary file not shown.

View File

@ -41,8 +41,15 @@ Current file: Shell.asm
000000r 1 Home = $fc58 000000r 1 Home = $fc58
000000r 1 Wait = $fca8 000000r 1 Wait = $fca8
000000r 1 PromptChar = $33 000000r 1 PromptChar = $33
000000r 1 Read80Col = $c01f
000000r 1 TextPage1 = $c054
000000r 1 TextPage2 = $c055
000000r 1
000000r 1 htab = $24 000000r 1 htab = $24
000000r 1 vtab = $25 000000r 1 vtab = $25
000000r 1 BasL = $28
000000r 1 htab80 = $057b
000000r 1 BasCalc = $fbc1
000000r 1 000000r 1
000000r 1 ESC = $9b 000000r 1 ESC = $9b
000000r 1 000000r 1
@ -51,114 +58,147 @@ Current file: Shell.asm
002000 1 20 00 C3 jsr $c300 ; force 80 columns 002000 1 20 00 C3 jsr $c300 ; force 80 columns
002003 1 2C 10 C0 bit ClearKeyboard 002003 1 2C 10 C0 bit ClearKeyboard
002006 1 A9 09 lda #ShellCommand 002006 1 A9 09 lda #ShellCommand
002008 1 20 74 20 jsr SendByte 002008 1 20 9A 20 jsr SendByte
00200B 1 20 0F 20 jsr DumpOutput 00200B 1 20 0F 20 jsr DumpOutput
00200E 1 60 rts 00200E 1 60 rts
00200F 1 00200F 1
00200F 1 DumpOutput: 00200F 1 DumpOutput:
00200F 1 20 92 20 jsr GetByte 00200F 1 20 B8 20 jsr GetByte
002012 1 B0 1E bcs checkInput 002012 1 B0 2A bcs checkInput
002014 1 C9 00 cmp #$00 002014 1 C9 00 cmp #$00
002016 1 F0 2D beq endOutput 002016 1 F0 39 beq endOutput
002018 1 C9 48 cmp #'H' 002018 1 48 pha
00201A 1 F0 30 beq setColumn 002019 1 20 E1 20 jsr InvertChar
00201C 1 C9 56 cmp #'V' 00201C 1 68 pla
00201E 1 F0 37 beq setRow 00201D 1 C9 48 cmp #'H'
002020 1 C9 43 cmp #'C' 00201F 1 F0 3A beq setColumn
002022 1 F0 22 beq clearScreen 002021 1 C9 56 cmp #'V'
002024 1 C9 54 cmp #'T' 002023 1 F0 44 beq setRow
002026 1 F0 3C beq setTop 002025 1 C9 43 cmp #'C'
002028 1 C9 42 cmp #'B' 002027 1 F0 29 beq clearScreen
00202A 1 F0 40 beq setBottom 002029 1 C9 54 cmp #'T'
00202C 1 20 ED FD jsr PrintChar 00202B 1 F0 4A beq setTop
00202F 1 4C 0F 20 jmp DumpOutput 00202D 1 C9 42 cmp #'B'
002032 1 checkInput: 00202F 1 F0 51 beq setBottom
002032 1 2C 00 C0 bit Keyboard ;check for keypress 002031 1 C9 55 cmp #'U'
002035 1 10 D8 bpl DumpOutput ;keep dumping output if no keypress 002033 1 F0 58 beq moveUp
002037 1 AD 00 C0 lda Keyboard ;send keypress to RPi 002035 1 20 ED FD jsr PrintChar
00203A 1 29 7F and #$7f 002038 1 20 E1 20 jsr InvertChar
00203C 1 20 74 20 jsr SendByte 00203B 1 4C 0F 20 jmp DumpOutput
00203F 1 2C 10 C0 bit ClearKeyboard 00203E 1 checkInput:
002042 1 4C 0F 20 jmp DumpOutput 00203E 1 2C 00 C0 bit Keyboard ;check for keypress
002045 1 endOutput: 002041 1 10 CC bpl DumpOutput ;keep dumping output if no keypress
002045 1 60 rts 002043 1 AD 00 C0 lda Keyboard ;send keypress to RPi
002046 1 clearScreen: 002046 1 29 7F and #$7f
002046 1 20 58 FC jsr Home 002048 1 20 9A 20 jsr SendByte
002049 1 4C 0F 20 jmp DumpOutput 00204B 1 2C 10 C0 bit ClearKeyboard
00204C 1 setColumn: 00204E 1 4C 0F 20 jmp DumpOutput
00204C 1 20 92 20 jsr GetByte 002051 1 endOutput:
00204F 1 85 24 sta htab 002051 1 60 rts
002051 1 8D 7B 05 sta $057B 002052 1 clearScreen:
002054 1 4C 0F 20 jmp DumpOutput 002052 1 20 58 FC jsr Home
002057 1 setRow: 002055 1 20 E1 20 jsr InvertChar
002057 1 20 92 20 jsr GetByte 002058 1 4C 0F 20 jmp DumpOutput
00205A 1 85 25 sta vtab 00205B 1 setColumn:
00205C 1 20 C1 FB jsr $fbc1 ; bascalc 00205B 1 20 B8 20 jsr GetByte
00205F 1 85 28 sta $28 ;basl 00205E 1 85 24 sta htab
002061 1 4C 0F 20 jmp DumpOutput 002060 1 8D 7B 05 sta htab80
002064 1 setTop: 002063 1 20 E1 20 jsr InvertChar
002064 1 20 92 20 jsr GetByte 002066 1 4C 0F 20 jmp DumpOutput
002067 1 85 22 sta $22 002069 1 setRow:
002069 1 4C 0F 20 jmp DumpOutput 002069 1 20 B8 20 jsr GetByte
00206C 1 setBottom: 00206C 1 85 25 sta vtab
00206C 1 20 92 20 jsr GetByte 00206E 1 20 C1 FB jsr BasCalc
00206F 1 85 23 sta $23 002071 1 20 E1 20 jsr InvertChar
002071 1 4C 0F 20 jmp DumpOutput 002074 1 4C 0F 20 jmp DumpOutput
002074 1 002077 1 setTop:
002074 1 SendByte: 002077 1 20 B8 20 jsr GetByte
002074 1 48 pha 00207A 1 85 22 sta $22
002075 1 waitWrite: 00207C 1 20 E1 20 jsr InvertChar
002075 1 AD FB C0 lda InputFlags 00207F 1 4C 0F 20 jmp DumpOutput
002078 1 2A rol 002082 1 setBottom:
002079 1 2A rol 002082 1 20 B8 20 jsr GetByte
00207A 1 B0 F9 bcs waitWrite 002085 1 85 23 sta $23
00207C 1 68 pla 002087 1 20 E1 20 jsr InvertChar
00207D 1 8D FD C0 sta OutputByte 00208A 1 4C 0F 20 jmp DumpOutput
002080 1 A9 1E lda #$1e ; set bit 0 low to indicate write started 00208D 1 moveUp:
002082 1 8D F7 C0 sta OutputFlags 00208D 1 C6 25 dec vtab
002085 1 finishWrite: 00208F 1 A5 25 lda vtab
002085 1 AD FB C0 lda InputFlags 002091 1 20 C1 FB jsr BasCalc
002088 1 2A rol 002094 1 20 E1 20 jsr InvertChar
002089 1 2A rol 002097 1 4C 0F 20 jmp DumpOutput
00208A 1 90 F9 bcc finishWrite 00209A 1
00208C 1 A9 1F lda #$1f 00209A 1 SendByte:
00208E 1 8D F7 C0 sta OutputFlags 00209A 1 48 pha
002091 1 60 rts 00209B 1 waitWrite:
002092 1 00209B 1 AD FB C0 lda InputFlags
002092 1 GetByte: 00209E 1 2A rol
002092 1 A9 1D lda #$1d ;set read flag low 00209F 1 2A rol
002094 1 8D F7 C0 sta OutputFlags 0020A0 1 B0 F9 bcs waitWrite
002097 1 waitRead: 0020A2 1 68 pla
002097 1 AD FB C0 lda InputFlags 0020A3 1 8D FD C0 sta OutputByte
00209A 1 2A rol 0020A6 1 A9 1E lda #$1e ; set bit 0 low to indicate write started
00209B 1 90 0C bcc readByte 0020A8 1 8D F7 C0 sta OutputFlags
00209D 1 2C 00 C0 bit Keyboard ;keypress will abort waiting to read 0020AB 1 finishWrite:
0020A0 1 10 F5 bpl waitRead 0020AB 1 AD FB C0 lda InputFlags
0020A2 1 A9 1F lda #$1f ;set all flags high and exit 0020AE 1 2A rol
0020A4 1 8D F7 C0 sta OutputFlags 0020AF 1 2A rol
0020A7 1 38 sec ;failure 0020B0 1 90 F9 bcc finishWrite
0020A8 1 60 rts 0020B2 1 A9 1F lda #$1f
0020A9 1 readByte: 0020B4 1 8D F7 C0 sta OutputFlags
0020A9 1 AD FE C0 lda InputByte 0020B7 1 60 rts
0020AC 1 48 pha 0020B8 1
0020AD 1 A9 1F lda #$1f ;set all flags high 0020B8 1 GetByte:
0020AF 1 8D F7 C0 sta OutputFlags 0020B8 1 A9 1D lda #$1d ;set read flag low
0020B2 1 finishRead: 0020BA 1 8D F7 C0 sta OutputFlags
0020B2 1 AD FB C0 lda InputFlags 0020BD 1 waitRead:
0020B5 1 2A rol 0020BD 1 AD FB C0 lda InputFlags
0020B6 1 90 FA bcc finishRead 0020C0 1 2A rol
0020B8 1 68 pla 0020C1 1 90 0C bcc readByte
0020B9 1 18 clc ;success 0020C3 1 2C 00 C0 bit Keyboard ;keypress will abort waiting to read
0020BA 1 end: 0020C6 1 10 F5 bpl waitRead
0020BA 1 60 rts 0020C8 1 A9 1F lda #$1f ;set all flags high and exit
0020BB 1 0020CA 1 8D F7 C0 sta OutputFlags
0020BB 1 HelpCommand: 0020CD 1 38 sec ;failure
0020BB 1 61 32 68 65 .byte "a2help",$00 0020CE 1 60 rts
0020BF 1 6C 70 00 0020CF 1 readByte:
0020C2 1 PromptCommand: 0020CF 1 AD FE C0 lda InputByte
0020C2 1 61 32 70 72 .byte "a2prompt",$00 0020D2 1 48 pha
0020C6 1 6F 6D 70 74 0020D3 1 A9 1F lda #$1f ;set all flags high
0020CA 1 00 0020D5 1 8D F7 C0 sta OutputFlags
0020CB 1 OldPromptChar: 0020D8 1 finishRead:
0020CB 1 5D .byte "]" 0020D8 1 AD FB C0 lda InputFlags
0020CC 1 0020DB 1 2A rol
0020DC 1 90 FA bcc finishRead
0020DE 1 68 pla
0020DF 1 18 clc ;success
0020E0 1 end:
0020E0 1 60 rts
0020E1 1
0020E1 1 InvertChar:
0020E1 1 AD 7B 05 lda htab80 ;get horizontal location / 2
0020E4 1 4A lsr
0020E5 1 A8 tay
0020E6 1 AD 55 C0 lda TextPage2
0020E9 1 90 03 bcc invert
0020EB 1 AD 54 C0 lda TextPage1
0020EE 1 invert:
0020EE 1 B1 28 lda (BasL),y
0020F0 1 49 80 eor #$80
0020F2 1 91 28 sta (BasL),y
0020F4 1 AD 54 C0 lda TextPage1
0020F7 1 screen40:
0020F7 1 60 rts
0020F8 1
0020F8 1 HelpCommand:
0020F8 1 61 32 68 65 .byte "a2help",$00
0020FC 1 6C 70 00
0020FF 1 PromptCommand:
0020FF 1 61 32 70 72 .byte "a2prompt",$00
002103 1 6F 6D 70 74
002107 1 00
002108 1 OldPromptChar:
002108 1 5D .byte "]"
002109 1 DrawCursor:
002109 1 80 .byte $80
002109 1

Binary file not shown.

View File

@ -19,4 +19,5 @@ type A2Io interface {
ReadString() (string, error) ReadString() (string, error)
ReadBlock(buffer []byte) error ReadBlock(buffer []byte) error
SendCharacter(character byte) SendCharacter(character byte)
ReadCharacter() (string, error)
} }

View File

@ -318,3 +318,8 @@ func (a2 A2Gpio) WriteBuffer(buffer []byte) error {
func (a2 A2Gpio) SendCharacter(character byte) { func (a2 A2Gpio) SendCharacter(character byte) {
sendCharacter(a2, character) sendCharacter(a2, character)
} }
// ReadCharacter is a pass-through to vt100 implementation
func (a2 A2Gpio) ReadCharacter() (string, error) {
return readCharacter(a2)
}

View File

@ -105,3 +105,8 @@ func (mockIo MockIo) ReadBlock(buffer []byte) error {
func (mockIo MockIo) SendCharacter(character byte) { func (mockIo MockIo) SendCharacter(character byte) {
sendCharacter(mockIo, character) sendCharacter(mockIo, character)
} }
// ReadCharacter is a pass-through to vt100 implementation
func (mockIo MockIo) ReadCharacter() (string, error) {
return readCharacter(mockIo)
}

View File

@ -82,3 +82,8 @@ func (userIo UserIo) ReadBlock(buffer []byte) error {
func (userIo UserIo) SendCharacter(character byte) { func (userIo UserIo) SendCharacter(character byte) {
sendCharacter(userIo, character) sendCharacter(userIo, character)
} }
// ReadCharacter is a pass-through to vt100 implementation
func (userIo UserIo) ReadCharacter() (string, error) {
return readCharacter(userIo)
}

View File

@ -12,22 +12,50 @@ import (
) )
var escapeSequence string var escapeSequence string
var operatingSystemSequence bool
var htab, vtab, savedHtab, savedVtab int var htab, vtab, savedHtab, savedVtab int
var applicationMode bool var applicationMode bool
var windowTop int var windowTop int
var windowBottom = 22 var windowBottom = 23
func sendCharacter(comm A2Io, b byte) { func sendCharacter(comm A2Io, b byte) {
if b == 0x1b { if b == 0x1b {
escapeSequence = "^[" escapeSequence = "^["
return return
} }
if b == 13 {
fmt.Printf("CR\n")
comm.WriteByte('H')
comm.WriteByte(0)
return
}
if b > 13 && b < 32 {
fmt.Printf("Control code: %02X\n", b)
return
}
if len(escapeSequence) == 0 {
fmt.Printf("%c", b)
}
if len(escapeSequence) > 0 { if len(escapeSequence) > 0 {
escapeSequence += string(b) escapeSequence += string(b)
if escapeSequence == "^[]" {
fmt.Printf("Start operating system sequence\n")
operatingSystemSequence = true
return
}
if operatingSystemSequence {
if b == 0x07 {
fmt.Printf("Operating system sequence: %s\n", escapeSequence)
operatingSystemSequence = false
escapeSequence = ""
}
return
}
// save cursor // save cursor
if escapeSequence == "^[7" { if escapeSequence == "^[7" {
savedHtab = htab savedHtab = htab
savedVtab = vtab savedVtab = vtab
fmt.Printf("Save Cursor (%d, %d): %s\n", htab, vtab, escapeSequence)
escapeSequence = "" escapeSequence = ""
} }
// restore cursor // restore cursor
@ -38,21 +66,34 @@ func sendCharacter(comm A2Io, b byte) {
comm.WriteByte(byte(htab)) comm.WriteByte(byte(htab))
comm.WriteByte('V') comm.WriteByte('V')
comm.WriteByte(byte(vtab)) comm.WriteByte(byte(vtab))
fmt.Printf("Restore Cursor (%d, %d): %s\n", htab, vtab, escapeSequence)
escapeSequence = "" escapeSequence = ""
} }
if (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') { if (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') {
switch b { switch b {
// Set cursor location // Set cursor location
case 'H', 'f': case 'H', 'f':
var ignore string if escapeSequence == "^[[H" || escapeSequence == "^[[;H" {
fmt.Sscanf(escapeSequence, "^[[%d;%d%s", &vtab, &htab, &ignore) htab = 0
htab-- vtab = 0
vtab-- comm.WriteByte(0x19) // ^Y moves to home position
comm.WriteByte('H') fmt.Printf("Home: %s\n", escapeSequence)
comm.WriteByte(byte(htab)) escapeSequence = ""
comm.WriteByte('V') } else {
comm.WriteByte(byte(vtab)) var ignore string
escapeSequence = "" fmt.Sscanf(escapeSequence, "^[[%d;%d%s", &vtab, &htab, &ignore)
htab--
vtab--
if htab < 0 {
htab = 0
}
comm.WriteByte('H')
comm.WriteByte(byte(htab))
comm.WriteByte('V')
comm.WriteByte(byte(vtab))
fmt.Printf("Set Cursor (%d, %d): %s\n", htab, vtab, escapeSequence)
escapeSequence = ""
}
case 'r': case 'r':
fmt.Sscanf(escapeSequence, "^[[%d;%dr", &windowTop, &windowBottom) fmt.Sscanf(escapeSequence, "^[[%d;%dr", &windowTop, &windowBottom)
windowTop-- windowTop--
@ -61,13 +102,68 @@ func sendCharacter(comm A2Io, b byte) {
comm.WriteByte(byte(windowTop)) comm.WriteByte(byte(windowTop))
comm.WriteByte('B') comm.WriteByte('B')
comm.WriteByte(byte(windowBottom)) comm.WriteByte(byte(windowBottom))
fmt.Printf("Set Window (%d, %d): %s\n", windowTop, windowBottom, escapeSequence)
escapeSequence = ""
case 'A':
if escapeSequence == "^[[A" || escapeSequence == "^[A" {
vtab--
comm.WriteByte('U')
fmt.Printf("Up: %s\n", escapeSequence)
} else {
var up int
fmt.Sscanf(escapeSequence, "^[[%dA", &up)
vtab -= up
for i := 0; i < up; i++ {
comm.WriteByte('U')
}
fmt.Printf("Up (%d): %s\n", up, escapeSequence)
}
escapeSequence = ""
case 'B':
if escapeSequence == "^[(B" || escapeSequence == "^[)B" || escapeSequence == "^[B" {
escapeSequence = ""
} else if escapeSequence == "^[[B" {
vtab++
comm.WriteByte(0x0a)
fmt.Printf("Down: %s\n", escapeSequence)
} else {
var down int
fmt.Sscanf(escapeSequence, "^[[%dB", &down)
vtab += down
for i := 0; i < down; i++ {
comm.WriteByte(0x0a)
}
fmt.Printf("Down (%d): %s\n", down, escapeSequence)
}
escapeSequence = "" escapeSequence = ""
case 'C': case 'C':
var right int if escapeSequence == "^[[C" || escapeSequence == "^[C" {
fmt.Sscanf(escapeSequence, "^[[%dC", &right) htab++
htab -= right comm.WriteByte(0x1c)
for i := 0; i < right; i++ { fmt.Printf("Right: %s\n", escapeSequence)
} else {
var right int
fmt.Sscanf(escapeSequence, "^[[%dC", &right)
htab += right
for i := 0; i < right; i++ {
comm.WriteByte(0x1c)
}
fmt.Printf("Right (%d): %s\n", right, escapeSequence)
}
escapeSequence = ""
case 'D':
if escapeSequence == "^[[D" || escapeSequence == "^[D" {
htab--
comm.WriteByte(0x08) comm.WriteByte(0x08)
fmt.Printf("Left: %s\n", escapeSequence)
} else {
var left int
fmt.Sscanf(escapeSequence, "^[[%dD", &left)
htab -= left
for i := 0; i < left; i++ {
comm.WriteByte(0x08)
}
fmt.Printf("Left (%d): %s\n", left, escapeSequence)
} }
escapeSequence = "" escapeSequence = ""
} }
@ -76,6 +172,7 @@ func sendCharacter(comm A2Io, b byte) {
case "^[[?1h": case "^[[?1h":
applicationMode = true applicationMode = true
comm.WriteByte(0x0c) // ^L clears the screen comm.WriteByte(0x0c) // ^L clears the screen
fmt.Printf("Start application mode: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
case "^[[?1l": case "^[[?1l":
applicationMode = false applicationMode = false
@ -84,54 +181,65 @@ func sendCharacter(comm A2Io, b byte) {
comm.WriteByte('B') comm.WriteByte('B')
comm.WriteByte(0x18) comm.WriteByte(0x18)
comm.WriteByte(0x0c) // ^L clears the screen comm.WriteByte(0x0c) // ^L clears the screen
fmt.Printf("End application mode: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
// Tab to home position // Tab to home position
case "^[[H", "^[[;H", "^[[f", "^[[;f": case "^[[f", "^[[;f":
htab = 0 htab = 0
vtab = 0 vtab = 0
comm.WriteByte(0x19) // ^Y moves to home position comm.WriteByte(0x19) // ^Y moves to home position
fmt.Printf("Home: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
// Clear screen // Clear screen
case "^[[2J", "^[[c": case "^[[2J", "^[[c":
htab = 0 htab = 0
vtab = 0 vtab = 0
comm.WriteByte(0x0c) // ^L clears the screen comm.WriteByte(0x0c) // ^L clears the screen
fmt.Printf("Clear screen: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
// Move down one line
case "^[E": case "^[E":
comm.WriteByte(0x0A) // ^J moves cursor down comm.WriteByte(0x0A) // ^J moves cursor down
fmt.Printf("Move down: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
case "^[D": case "^[D":
comm.WriteByte(0x17) // ^W scrolls up comm.WriteByte(0x17) // ^W scrolls up
fmt.Printf("Scroll up: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
// Clear line to the right
case "^[[K", "^[[0K": case "^[[K", "^[[0K":
comm.WriteByte(0x1d) // ^] clears to end of line comm.WriteByte(0x1d) // ^] clears to end of line
fmt.Printf("Clear line right: %s\n", escapeSequence)
escapeSequence = ""
case "^[[2K":
comm.WriteByte(0x1a) // ^Z clears line
fmt.Printf("Clear line: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
case "^[M": case "^[M":
comm.WriteByte(0x16) // ^V scrolls down comm.WriteByte(0x16) // ^V scrolls down
fmt.Printf("Scroll down: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
// Clear screen below cursor
case "^[[J": case "^[[J":
comm.WriteByte(0x0b) // ^K clears to end of screen comm.WriteByte(0x0b) // ^K clears to end of screen
fmt.Printf("Clear below cursor: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
case "^[[7m": case "^[[7m":
comm.WriteByte(0x0f) // ^O inverse video comm.WriteByte(0x0f) // ^O inverse video
fmt.Printf("Inverse: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
case "^[[m", "^[[0m": case "^[[m", "^[[0m":
comm.WriteByte(0x0e) // ^N normal video //comm.WriteByte(0x0e) // ^N normal video
fmt.Printf("Normal: %s\n", escapeSequence)
escapeSequence = "" escapeSequence = ""
} }
if len(escapeSequence) > 0 { if len(escapeSequence) > 0 {
fmt.Printf("\nUnhandled escape sequence: %s\n", escapeSequence) fmt.Printf("Unhandled escape sequence: %s\n", escapeSequence)
} }
escapeSequence = "" escapeSequence = ""
return return
} }
return return
} }
fmt.Print(string(b)) //fmt.Print(string(b))
htabIncrement := 0 htabIncrement := 0
switch b { switch b {
// convert LF to CR for Apple II compatiblity // convert LF to CR for Apple II compatiblity
@ -158,7 +266,7 @@ func sendCharacter(comm A2Io, b byte) {
default: default:
htabIncrement = 1 htabIncrement = 1
} }
if !applicationMode || htab < 78 { if !applicationMode || htab < 79 {
updateTabs(comm) updateTabs(comm)
b |= 0x80 b |= 0x80
htab += htabIncrement htab += htabIncrement
@ -171,6 +279,26 @@ func sendCharacter(comm A2Io, b byte) {
} }
} }
func readCharacter(comm A2Io) (string, error) {
b, err := comm.ReadByte()
var s = string(b)
if err == nil {
switch b {
case 0x0b: // up
s = "\033[A"
case 0x0a: // down
s = "\033[B"
case 0x15: // right
s = "\033[C"
case 0x08: // left
s = "\033[D"
case 0x0d: // return
s = string(byte(0x0a))
}
}
return s, err
}
func updateTabs(comm A2Io) { func updateTabs(comm A2Io) {
if htab >= 80 { if htab >= 80 {
htab = 0 htab = 0

View File

@ -18,6 +18,7 @@ import (
"github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/handlers" "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/handlers"
) )
const resetCommand = 0
const readBlockCommand = 1 const readBlockCommand = 1
const writeBlockCommand = 2 const writeBlockCommand = 2
const getTimeCommand = 3 const getTimeCommand = 3
@ -40,11 +41,16 @@ func main() {
lastCommandTime := time.Now() lastCommandTime := time.Now()
// In case Apple II is waiting, send 0 byte to start
comm.WriteByte(0)
for { for {
command, err := comm.ReadByte() command, err := comm.ReadByte()
if err == nil { if err == nil {
lastCommandTime = time.Now() lastCommandTime = time.Now()
switch command { switch command {
case resetCommand:
handlers.ResetCommand()
case readBlockCommand: case readBlockCommand:
handlers.ReadBlockCommand(drive1, drive2) handlers.ReadBlockCommand(drive1, drive2)
case writeBlockCommand: case writeBlockCommand:

View File

@ -117,7 +117,6 @@ func execCommand(linuxCommand string, workingDirectory string) {
return return
case <-userCancelled: case <-userCancelled:
userCancelled <- true userCancelled <- true
comm.WriteString("^C\r")
cmd.Process.Kill() cmd.Process.Kill()
return return
case <-inputComplete: case <-inputComplete:
@ -132,6 +131,7 @@ func getStdout(stdout io.ReadCloser, outputComplete chan bool, userCancelled cha
for { for {
select { select {
case <-userCancelled: case <-userCancelled:
fmt.Printf("User Cancelled stdout\n")
stdout.Close() stdout.Close()
return return
default: default:
@ -158,22 +158,15 @@ func getStdin(stdin io.WriteCloser, done chan bool, inputComplete chan bool, use
inputComplete <- true inputComplete <- true
return return
default: default:
b, err := comm.ReadByte() s, err := comm.ReadCharacter()
if err == nil { if err == nil {
if b == 0x03 { if s == string(byte(0x00)) {
stdin.Close() stdin.Close()
userCancelled <- true userCancelled <- true
fmt.Printf("\nUser cancelled stdin\n")
return return
} }
if b == 0x0d { io.WriteString(stdin, string(s))
b = 0x0a
}
if b == 0x0b {
b = 'k'
}
fmt.Printf("%c", b)
io.WriteString(stdin, string(b))
} }
} }
} }

View File

@ -0,0 +1,18 @@
// Copyright Terence J. Boldt (c)2020-2021
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
// This file is contains the handler for displaying the menu of choices on
// the Apple II
package handlers
import (
"fmt"
)
// ResetCommand responds with zero
func ResetCommand() {
fmt.Printf("Reset request\n")
comm.WriteByte(0)
}

View File

@ -7,6 +7,7 @@
package handlers package handlers
import ( import (
"fmt"
"os" "os"
"os/exec" "os/exec"
@ -41,14 +42,14 @@ func ShellCommand() {
for { for {
select { select {
case <-outputComplete: case <-outputComplete:
outputComplete <- true ptmx.Close()
cmd.Wait()
comm.WriteByte(0) comm.WriteByte(0)
return return
case <-userCancelled: case <-userCancelled:
userCancelled <- true fmt.Printf("User cancelled, killing process\n")
comm.WriteString("^C\r") ptmx.Close()
cmd.Process.Kill() cmd.Process.Kill()
comm.WriteByte(0)
return return
case <-inputComplete: case <-inputComplete:
cmd.Wait() cmd.Wait()