mirror of
https://github.com/Klaus2m5/6502_EhBASIC_V2.22.git
synced 2024-06-11 07:29:33 +00:00
229c744455
fixed can't continue error on 1st statement after direct mode fixed syntax error after "Redo from start" when INPUT is the first run mode statement changed INPUT to throw "break in line ##" on empty line input
193 lines
7.9 KiB
Plaintext
193 lines
7.9 KiB
Plaintext
EhBASIC 2.22 has a few bugs and quirks that you should know about.
|
|
|
|
1. The interrupt system is severely broken.
|
|
|
|
When an IRQ occurs and IRQ_vec is called in min_mon.asm the interrupt is only
|
|
registered with IRQbase but the interrupt source is not serviced nor is the
|
|
interrupt disable bit set at RTI. As a consequence the interrupt is immediately
|
|
called again and again and IRQbase is trashed until the interrupt is serviced
|
|
by the ON IRQ handler in basic.
|
|
|
|
The problem is discussed in http://forum.6502.org/viewtopic.php?f=5&t=2411
|
|
How I solved the problem for my emulator:
|
|
https://github.com/Klaus2m5/AVR_emulated_6502_4SBC/tree/master/EhBASIC
|
|
|
|
However, you should keep in mind that the interrupt service capacity in EhBASIC
|
|
is very limited. In a 2MHz system more than 100 interrupts per second or
|
|
interrupts requiring less than 10ms service time should be handled in machine
|
|
language. The numbers are worse if the interrupt handler gets more complex.
|
|
|
|
Of course, a hybrid solution is always possible. You could service the interrupt
|
|
in machine language and flag an interrupt to basic only after a buffer is
|
|
filled/emptied or a count is reached.
|
|
|
|
|
|
2. String handling when the string is in the input buffer.
|
|
|
|
When a string is entered via the input buffer (Ibuffs - Ibuffe) in Ehbasic it
|
|
is transient because it gets overwritten by the next input. In this case it
|
|
needs to be copied to the string area. In all other cases the string remains in
|
|
place and only a pointer needs to be set to the string location.
|
|
|
|
There is a bug in EhBASIC to determine where the string is.
|
|
|
|
LAB_20DC
|
|
STX Sendh ; save string end high byte
|
|
LDA ssptr_h ; get string start high byte
|
|
CMP #>Ram_base ; compare with start of program memory
|
|
BCS LAB_RTST ; branch if not in utility area
|
|
This does not work, if RAM_base is below the input buffer or EhBASIC itself is
|
|
below RAM_base. The fix requires the input buffer not to cross a page boundary:
|
|
|
|
LAB_20DC
|
|
STX Sendh ; save string end high byte
|
|
LDA ssptr_h ; get string start high byte
|
|
; *** begin RAM above code / Ibuff above EhBASIC patch ***
|
|
; *** replace
|
|
; CMP #>Ram_base ; compare with start of program memory
|
|
; BCS LAB_RTST ; branch if not in utility area
|
|
; *** with
|
|
CMP #>Ibuffs ; compare with location of input buffer page
|
|
BNE LAB_RTST ; branch if not in utility area
|
|
; *** end RAM above code / Ibuff above EhBASIC patch ***
|
|
|
|
|
|
3. Output of some functions limited to integers is negative.
|
|
|
|
This is not a bug but documented behavior.
|
|
|
|
Affected functions FRE(), SADD(), VARPTR(), DEEK()
|
|
|
|
If you want to use FRE() with large RAM you must write:
|
|
|
|
? FRE(0)-(FRE(0)<0)*$10000
|
|
|
|
If you really want to deviate from the beaten path, you can add a routine to
|
|
convert unsigned integers and jump to it from the functions that you want to
|
|
respond with an unsigned number. It replaces LAB_AYFC for these functions.
|
|
|
|
; save and convert unsigned integer AY to FAC1
|
|
LAB_UAYFC
|
|
LSR Dtypef ; clear data type flag, $FF=string, $00=numeric
|
|
STA FAC1_1 ; save FAC1 mantissa1
|
|
STY FAC1_2 ; save FAC1 mantissa2
|
|
LDX #$90 ; set exponent=2^16 (integer)
|
|
SEC ; always positive
|
|
JMP LAB_STFA ; set exp=X, clear FAC1_3, normalise and return
|
|
|
|
You cannot apply this routine to operators which also use LAB_AYFC (=, OR, AND
|
|
EOR <<, >>) as they require signed integers. The value -1 is asigned to a
|
|
comparison evaluating as TRUE. Therefore logical operators must be able to
|
|
evaluate -1 correctly.
|
|
|
|
|
|
4. Use of decimal mode and invalid BCD
|
|
|
|
There is only one place in EhBASIC where decimal mode is used. HEX$() uses
|
|
invalid BCD to convert a number to a hexadecimal string. Some processors do not
|
|
support decimal mode and emulators most of the time will not support invalid
|
|
BCD (nibbles in the range of $A - $F).
|
|
|
|
LAB_AL2X
|
|
CMP #$0A ; set carry for +1 if >9
|
|
ADC #'0' ; add ASCII "0"
|
|
STA (str_pl),Y ; save to temp string
|
|
DEY ; decrement counter
|
|
RTS
|
|
|
|
A patch is available to disable use of decimal mode in EhBASIC.
|
|
|
|
LAB_AL2X
|
|
CMP #$0A ; set carry for +1 if >9
|
|
; *** begin disable decimal mode patch ***
|
|
; *** insert
|
|
BCC LAB_AL20 ; skip adjust if <= 9
|
|
ADC #$06 ; adjust for A to F
|
|
LAB_AL20
|
|
; *** end disable decimal mode patch ***
|
|
ADC #'0' ; add ASCII "0"
|
|
STA (str_pl),Y ; save to temp string
|
|
DEY ; decrement counter
|
|
RTS
|
|
|
|
At the same time you must disable SED & CLD at the HEX$() function.
|
|
|
|
LAB_HEXS
|
|
CPX #$07 ; max + 1
|
|
BCS BinFErr ; exit if too big ( > or = )
|
|
|
|
STX TempB ; save # of characters
|
|
|
|
LDA #$06 ; need 6 bytes for string
|
|
JSR LAB_MSSP ; make string space A bytes long
|
|
LDY #$05 ; set string index
|
|
|
|
; *** disable decimal mode patch - comment next line ***
|
|
; SED ; need decimal mode for nibble convert
|
|
LDA nums_3 ; get lowest byte
|
|
JSR LAB_A2HX ; convert A to ASCII hex byte and output
|
|
LDA nums_2 ; get middle byte
|
|
JSR LAB_A2HX ; convert A to ASCII hex byte and output
|
|
LDA nums_1 ; get highest byte
|
|
JSR LAB_A2HX ; convert A to ASCII hex byte and output
|
|
; *** disable decimal mode patch - comment next line ***
|
|
; CLD ; back to binary
|
|
|
|
|
|
5. Ibuffs located at $xx00
|
|
|
|
If the input buffer is located at the beginning of a page then any direct
|
|
statement (RUN, LIST, ...) is read from Ibuffs-$100 resulting in unexpected
|
|
behavior of EhBASIC.
|
|
|
|
A patch is available from Daryl Rictor. I took the freedom to add conditional
|
|
assembly.
|
|
|
|
LAB_142A
|
|
INY ; increment pointer
|
|
INY ; increment pointer (makes it next line pointer high byte)
|
|
STA Ibuffs,Y ; save [EOL] (marks [EOT] in immediate mode)
|
|
INY ; adjust for line copy
|
|
INY ; adjust for line copy
|
|
INY ; adjust for line copy
|
|
; *** begin patch for when Ibuffs is $xx00 - Daryl Rictor ***
|
|
; *** insert
|
|
.IF Ibuffs&$FF==0
|
|
LDA Bpntrl ; test for $00
|
|
BNE LAB_142P ; not $00
|
|
DEC Bpntrh ; allow for increment when $xx00
|
|
LAB_142P
|
|
.ENDIF
|
|
; *** end patch for when Ibuffs is $xx00 - Daryl Rictor ***
|
|
; end of patch
|
|
DEC Bpntrl ; allow for increment
|
|
RTS
|
|
|
|
The conditional in the patch abover requires Ibuffs to be known at path 1 during
|
|
assembly. The standard definition of Ibuffs does not satisfy this requirement.
|
|
We need to replace it like below:
|
|
|
|
; Ibuffs can now be anywhere in RAM, ensure that the max length is < $80,
|
|
; the input buffer must not cross a page boundary and must not overlap with
|
|
; program RAM pages!
|
|
|
|
;Ibuffs = IRQ_vec+$14
|
|
Ibuffs = VEC_SV+$16
|
|
; start of input buffer after IRQ/NMI code
|
|
Ibuffe = Ibuffs+$47; end of input buffer
|
|
|
|
|
|
6. First statement after direct mode does not set the continue pointer
|
|
|
|
After a RUN or GOTO in direct mode CONT does not work for the first statement in
|
|
run mode. It throws a "Can't continue error". If that first statement is INPUT
|
|
then "Redo from start" causes a subsequent syntax error.
|
|
|
|
It is actually a hen and egg problem as the continue pointer (Cpntrh/l) is saved
|
|
during the inner loop if not in direct mode, but direct mode (Clineh = $FF) is
|
|
only cleared later in the same loop.
|
|
|
|
The fix is in the patched folder (version 2.22p2). The continue counter is now
|
|
always saved and the decission to continue is postponed until the CONT statement
|
|
is executed and based on the fact that the continue pointer must not point to
|
|
the input buffer in run mode. |