-
Content Count
94 -
Joined
-
Last visited
Posts posted by geek504
-
-
My all-time favorite was the Apple ][+ with the 16K Language Card for 80-columns and a 20MB Apple Cider external hard disk. Most of my friends had a C64 and I loved the games but the overall user experience was definitely better with the Apple.
I was then saving for a Commodore 128 but ended having enough for an Amiga 500. I loved it but now, in retrospect, I'd have preferred the Apple Macintosh IIfx if money was not an issue!
But of course, the Commander X16 will trump them all... maybe not the IIfx but I like my memory map small... 64KB for the win!
-
-
27 minutes ago, Ender said:I believe "NYI" means "not yet implemented".
Thanks for looking at the code @Ender. A speaker beep shouldn't be too hard to do
I suppose a TAB should be every 8 position (Apple BASIC)... or 10 (C64) as the "," do in the PRINT statement.
-
I've been scratching my head on these new control characters, more specifically TAB ($09) and BELL ($7). How does one use it in a PRINT CHR$() command? I even tried "activating" by enabling CHARSET ISO ON/OFF ($F).
I am trying to figure out the "tab" or "," or actually print 10 spaces in my PRINT function or I need to make use of the KERNAL PLOT routine.
QuoteNew Control Characters
This is the set of all supported PETSCII control characters. Descriptions in bold indicate new codes compared to the C64:
Code Code $00 NULL - $80 $01 SWAP COLORS COLOR: ORANGE $81 $02 - $82 $03 STOP/RUN $83 $04 ATTRIBUTES: UNDERLINE HELP $84 $05 COLOR: WHITE F1 $85 $06 ATTRIBUTES: BOLD F3 $86 $07 BELL F5 $87 $08 BACKSPACE F7 $88 $09 TAB F2 $89 $0A LF F4 $8A $0B ATTRIBUTES: ITALICS F6 $8B $0C ATTRIBUTES: OUTLINE F8 $8C $0D REGULAR/SHIFTED RETURN $8D $0E CHARSET: LOWER/UPPER CASE $8E $0F CHARSET: ISO ON/OFF $8F -
13 hours ago, desertfish said:It makes the code generator itself a lot simpler however the generated code is quite inefficient in terms of 6502 assembly....
@desertfish I started coding my compiler without a stack and while I can say it was efficient, it was just too slow (edit: to code and finish the compiler) and prone to bugs... I decided to implement the stack midway just to get the compiler ready and then re-implement the non-stack improvements later if at all. I'm guessing a rough 10-15% speed improvement and am not sure if it is worth the effort right now. 6502 assembly is inefficient by nature (but very simple to implement) especially if we write proper assembly code to preserve A, X, and Y, wasting bytes and cycles with PHA, PHX, PHY, and PLY, PLX, PLA prior to every subroutine. I do feel that this is still more efficient than cc65's C-stack implementation though.
I am not worrying too much about maximum efficiency (I don't think we will ever get close to super tight assembly code) because I hope one day in the future we will be able to crank up the X16's MHz to GHz range!
At least in the emulator scene, we can implement the following 6502 JIT-core to x64 which could bring to a realistic 12GHz!
https://scarybeastsecurity.blogspot.com/2020/04/clocking-6502-to-15ghz.html?m=1
-
1 hour ago, desertfish said:It no longer uses the software-eval-stack for that.
Hi! Is this "software-eval-stack" you mention a software-based stack used for mathematical computations based on a RPN-type stack? E.g. 2+3 becomes 2, PUSH, 3, PUSH, +? This is what I am using for my BASIC compiler. If so, it does do a lot of function calling and can be greatly optimized if one bypasses the stack entirely but involves major compiler modifications as you mentioned. This is a sample code from my compiler using macros that greatly improves readability:
Quote
10 REM ASSIGNMENT
20 AX = 3 : REM NEED TO OPTIMIZE
30 V = ABS(AX + 2)
35 Q = 1 + 2 * 6 / 3
40 PRINT "THE END"
50 ENDstart
line
10
comment REM ASSIGNMENT
line
20
assignment
AX
3
comment REM NEED TO OPTIMIZE
line
30
assignment
V
abs
add_exp
AX
+
2
line
35
assignment
Q
add_exp
1
+
mul_exp
mul_exp
2
*
6
/
3
line
40
print "THE END"
line
50
endTree('start', [Tree('line', [Token('INT', '10'), Tree('comment', [Token('COMMENT', 'REM ASSIGNMENT')])]), Tree('line', [Token('INT', '20'), Tree('assignment', [Token('VAR_ID', 'AX'), Token('INT', '3')]), Tree('comment', [Token('COMMENT', 'REM NEED TO OPTIMIZE')])]), Tree('line', [Token('INT', '30'), Tree('assignment', [Token('VAR_ID', 'V'), Tree('abs', [Tree('add_exp', [Token('VAR_ID', 'AX'), Token('ADD_OP', '+'), Token('INT', '2')])])])]), Tree('line', [Token('INT', '35'), Tree('assignment', [Token('VAR_ID', 'Q'), Tree('add_exp', [Token('INT', '1'), Token('ADD_OP', '+'), Tree('mul_exp', [Tree('mul_exp', [Token('INT', '2'), Token('MUL_OP', '*'), Token('INT', '6')]), Token('MUL_OP', '/'), Token('INT', '3')])])])]), Tree('line', [Token('INT', '40'), Tree('print', [Token('STRING', '"THE END"')])]), Tree('line', [Token('INT', '50'), Tree('end', [])])])
.include "macros.inc"
.include "header.inc"
.codeL10: ; REM ASSIGNMENT
L20: PushInt 3
PullVar AX
; REM NEED TO OPTIMIZE
L30: PushVar AX
PushInt 2
jsr ADD
jsr ABS
PullVar V
L35: PushInt 1
PushInt 2
PushInt 6
jsr UMUL
PushInt 3
jsr UDIV
jsr ADD
PullVar Q
L40: LoadAddress S0 ; to r0
jsr PrString
L50: rtsS0: .asciiz "the end"
AX: .res 2
V: .res 2
Q: .res 2.include "io.asm"
.include "math.asm"
As you can see, line 20 does a PUSH and a PULL to/from stack for a simple AX=3. It could have simply copied over the INT 3 directly into VAR AX. I'm planning in writing a post-compiler optimizer much later. Note that I couldn't use VAR A since A is a reserved keyword in ca65!
-
On 11/3/2020 at 1:00 AM, Getafix said:Instead of .org $22 just use .zeropage.
Out of curiosity, where does ".zeropage" start reserving space? Hopefully not starting from address $0000 since it is prone to corruption of important areas. For X16 it should start at $0022. I assumed it did but now am worried I may have ZP data corruption.
-
3 minutes ago, JimmyDansbo said:LSR A is just to make the commands look alike.
That's what I figured too... but that would only make sense if we could do LSR X or LSR Y
-
1
-
-
Which one is correct? They both seem to be the same, i.e. they operate on the accumulator.
LSR
or
LSR A
Is the first one used in 6502-proper and the latter in 65C02?
-
I am trying to setup a few variables in ZEROPAGE using ca65 and the following does not seem to work...
Quote.org $22 ; start of user ZP
FPSP: .byte 0 ; stack pointer = 0
FPTEMP: .res 4 ; FP temp
SFL: .res FPSTACKSIZE
SFH: .res FPSTACKSIZE
SIL: .res FPSTACKSIZE
SIH: .res FPSTACKSIZE.org $0801
.byte $0C, $08
.byte $0A, $00
.byte $9E
.byte $20
.byte $32, $30, $36, $34
.byte $00
.byte $00, $00
.byte $00, $00 ; Padding so code starts at $0810StoreImm $11ff, r0
jsr PUSH
StoreImm $2233, r0
jsr PUSH
StoreImm $5599, r0
jsr PUSH
StoreImm $6677, r0
jsr PUSH
StoreImm $2345, r0
jsr PUSHjsr ADD
jsr ADD
jsr ADD
jsr ADD
jsr PULL
jsr PrHex16
PrintNewlineStoreImm msg, r0
jsr PrString
END: rts
msg: .asciiz "the end!"<snipped math routines>
It seems multiple ".org" doesn't work?
-
On 10/28/2020 at 5:57 PM, geek504 said:After checking Microsoft's implmentation as well as Woz's and third-party, I decided to use 16.16 Fixed-Point since most of the INTEGER part is done.
For those who are curious:
e = exponent, s = sign, m=mantissa, i = integer (used in fixed-point)
Microsoft (5-bytes): eeee.eeee | smmm.mmmm | mmmm.mmmm | mmmm.mmmm | mmmm.mmmm
Woz (4-bytes): seee.eeee | smmm.mmmm | mmmm.mmmm | mmmm.mmmm
Bishop (4-bytes): siii.iiii | mmmm.mmmm | mmmm.mmmm | mmmm.mmmm
My version (4-bytes): siii.iiii | iiii.iiii | mmmm.mmmm | mmmm.mmmm
32-bit float has a 7 significant digits precision
16-bit float has a 3 significant digits precision
16-bit fixed mantissa has a 5 s.d.p. plus the significant digits from the INT
The only major drawback of 16.16 fixed-point: it cannot do very very large or very very small numbers. Use ROM float-math for that!
Bishop's version is very interesting because the INT part is only -128 to +127 only, BUT any number larger than +127 the fractional part starts to become negligible, i.e. ~0.78% error margin. In order to take advantage of that requires constant checking for the INT value to determine when to use the Bishop float or normal 16-bit INT. Bishop's fixed-point was used to generate fast mandelbrots in the Apple ][.
-
10 minutes ago, desertfish said:Can't you just perform the division using FDIV rom routine?
The compiler is for Integer BASIC using 16-bit SIGNED INTs. After checking Microsoft's implmentation as well as Woz's and third-party, I decided to use 16.16 Fixed-Point since most of the INTEGER part is done. I just have to integrate the 16-bit MANTISSA part into my FP routines. This "integration" might cost a few execution cycles more but it should work well. Considering that fixed-point is faster to compute than floating-point, it's a small sacrifice. GPUs work like this as well, i.e. they use integer math along with fixed-point math with just the fractional part.
When the compiler is done, I'll add the use of the ROM's floating-point math for serious work!
My goal is to have a compiler that produces fast math at the expense of accuracy. It also uses 8-bit sine/cosine tables with 6% error margin. PI will be just 22/7 for fast computations. Let's see what this Frankenstein will look like in the end! In true Woz spirit, it is designed for game creation!
-
1
-
-
2 hours ago, geek504 said:On another topic, does anyone have a handy algorithm to convert a fraction into a floating-point mantissa (binary form), for example:
N=7, D=3 ==> N/D = 7/3 = 2R1
I want to convert R/D (always less than 1) to the fractional part (mantissa) of a floating/fixed point number:
R/D = 1/3 = 0.3333 ==> Result in Binary : 0.01010101
After spending the afternoon going over binary division just for fun, I probably re-invented the wheel. In any case, here is the algorithm in Python form:
Quote# Q16 factor for mantissa
N = 1
D = 7
Q = []print("Binary Division: (N) " + "{0:b}".format(N) + "/" + "{0:b}".format(D) + " (D)")
for i in range(16):
N = N<<1
print("Can D=" + "{0:b}".format(D) + " go into N=" + "{0:b}".format(N) + "?")
if D>N:
print("No")
Q.append("0")
else:
print("Yes")
Q.append("1")
N = N - D
if N == 0:
breakprint("N={0:b}".format(N))
print("Result: ", *Q)
F = 0.0
for i in range(16):
if Q.pop(0) == '1':
F = F + (1/(2**(i+1)))print("Fraction: ", F)
Feel free to comment! Now I have to convert this to 6502 assembly
Sample run on 1/7 (which happens to be the remainder of the cheap PI value 22/7 = 3.14):
QuoteBinary Division: (N) 1/111 (D)
Can D=111 go into N=10?
No
N=10
Can D=111 go into N=100?
No
N=100
Can D=111 go into N=1000?
Yes
N=1
Can D=111 go into N=10?
No
N=10
Can D=111 go into N=100?
No
N=100
Can D=111 go into N=1000?
Yes
N=1
Can D=111 go into N=10?
No
N=10
Can D=111 go into N=100?
No
N=100
Can D=111 go into N=1000?
Yes
N=1
Can D=111 go into N=10?
No
N=10
Can D=111 go into N=100?
No
N=100
Can D=111 go into N=1000?
Yes
N=1
Can D=111 go into N=10?
No
N=10
Can D=111 go into N=100?
No
N=100
Can D=111 go into N=1000?
Yes
N=1
Can D=111 go into N=10?
No
N=10
Result: 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0
Fraction: 0.142852783203125 -
48 minutes ago, SlithyMatt said:BCD is generally faster, and a more scalable process. Also, you can have a running counter that stays in BCD all the time, like a score, that can be quickly rendered as text on screen.
Faster? A statement like var++ would be a simply matter of using INC and ADC for large numbers. BCD would require checking for the 9 digit and moving to 0 digit instead of A. Of course, 6502 does native BCD and that might be just as fast? BCD also uses more memory but I can see that BCD to string is much easier!
On another topic, does anyone have a handy algorithm to convert a fraction into a floating-point mantissa (binary form), for example:
N=7, D=3 ==> N/D = 7/3 = 2R1
I want to convert R/D (always less than 1) to the fractional part (mantissa) of a floating/fixed point number:
R/D = 1/3 = 0.3333 ==> Result in Binary : 0.01010101
-
7 hours ago, Stefan said:If I understand your code it's a repeated subtraction method.
I've found some other interesting methods, which have worked nicely.
Thanks for the links... I am always looking for cool 6502 algorithms to include in my support library!
But, I just wanted to print Hex2Dec for the PRINT function... you're suggesting to first convert hex to BCD and then use BCD to print each digit? Would that be substantially faster than repeated subtraction?
I confess, I never used BCD in my life. Can anyone illuminate the usefulness of BCD?
-
2 minutes ago, SlithyMatt said:I see it as no different than having a static variable inside a function in C. If you want to be evil, you can put executable instructions in there and call them, but it's not the greatest idea.
I remember putting a shell code inside a string array...
-
1
-
-
1 hour ago, SlithyMatt said:It's perfectly OK to declare variables in the code segment, as long as it's outside the path of execution, as it appears here. RAM is RAM, and everything has to go somewhere.
LOL! As I was reading more webpages on algorithms for integer math and fixed-point math, I came across a text that mentioned that keeping data inside your code is in the realms of "self-modifying code"... woooo... makes us look like uber virus/worm programmers! Not that I ever wrote one during the 80s...
-
1 hour ago, Ender said:I don't think you can declare variables in the middle of your code like that, at least not with cc65, unless you use segments. The "PrDec16Tens" and "pad" declarations should be at the end. From what I can tell, when pad is written to, it's overwriting the first command of PrHex8, changing it from PHA to "BMI $8fd". Therefore, when you PLA later on the stack gets screwed up. If you move those declarations to the end it works.
Ender, thanks a million for your fresh view on the code analysis! You actually found the spot where the problem was and it was totally off my radar! It is possible to declare variable space within one's code from what I've experienced (one can really make a mess if one really wanted to!) The bug was...
1 hour ago, geek504 said:PrDec16Tens:
.word 1
.word 10
.word 100
.word 1000
.word 10000
pad: .res 0 ; default 0 = no padding... pad like you said BUT it was because I was reserving ZERO byte(s) and thus overwriting PrHex8 as you mentioned. It is supposed to be .res 1 and it runs repeatedly without any problems. The ZERO was the remnant of my previous .byte 0 thinking about having a default value for pad, but the routine always write over this space so reserving was more accurate but forgot to change the 0 to 1.
I wasted so much time thinking that I was corrupting .A, .X, .Y, or the many r0-r15 or simply bad assembly code. *sigh*
-
1
-
-
I am in the process of writing support assembly code for my BASIC compiler and am stuck with a particular BUG in the routine (PrDec16) that converts and prints an UNSIGNED INT into a DECIMAL STRING (There is also a routine, PrSgnDec16, that prints SIGNED INT which relies on it).
When you compile and run the program, it seems to work BUT the side-effect of the bug is that when you type RUN again, it just clears the screen (it actually prints out something random before it clears). So if I wrote a larger program, it ends up clearing the screen preventing other things to be printed (or it crashed?).
I spent two full days hungting for this bug but cannot find it! Can anyone see where the mistake is?
Quote.org $0801
.byte $0C, $08
.byte $0A, $00
.byte $9E
.byte $20
.byte $32, $30, $36, $34
.byte $00
.byte $00, $00
.byte $00, $00 ; Padding so code starts at $0810CHROUT = $FFD2
PLOT = $FFF0
NEWLINE = $0D
UPPERCASE = $8Er0 = $02
r0L = $02
r0H = $03
r1 = $04
r1L = $04
r1H = $05
r2 = $06
r2L = $06
r2H = $07
r3 = $08
r3L = $08
r3H = $09
r4 = $0a
r4L = $0a
r4H = $0b
r5 = $0c
r5L = $0c
r5H = $0d
r6 = $0e
r6L = $0e
r6H = $0f
r7 = $10
r7L = $10
r7H = $11
r8 = $12
r8L = $12
r8H = $13
r9 = $14
r9L = $14
r9H = $15
r10 = $16
r10L = $16
r10H = $17
r11 = $18
r11L = $18
r11H = $19
r12 = $1a
r12L = $1a
r12H = $1b
r13 = $1c
r13L = $1c
r13H = $1d
r14 = $1e
r14L = $1e
r14H = $1f
r15 = $20
r15L = $20
r15H = $21; Loads a 16-bit Word (immediate) to .A (lo-byte) and .X (hi-byte)
;
.macro LoadWordAX value
lda #<value
ldx #>value
.endmacro; Loads the 16-bit Word value at address to .A (lo-byte) and .X (hi-byte)
;
.macro LoadAX address
lda address
ldx address+1
.endmacro; Moves the 8-bit Byte from source to dest
;
.macro MoveB source, dest
lda source
sta dest
.endmacro; Moves the 16-bit Word from source (lo,hi) to dest (lo,hi)
;
.macro MoveW source, dest
MoveB source+0, dest+0
MoveB source+1, dest+1
.endmacro; Store the 16-bit Word in AX to address (lo,hi)
;
.macro StoreAX address
sta address
stx address+1
.endmacro; Store a 16-bit Word (immediate) to address (lo,hi)
;
.macro StoreImm value, address
LoadWordAX value
StoreAX address
.endmacro; Print a NEWLINE char
;
.macro PrintNewline
lda #NEWLINE
jsr CHROUT
.endmacroSTART:
StoreImm $1234, r0 ; decimal = 4660
jsr PrHex16 ; input at r0
PrintNewline
jsr NEG16 ; input at r0, output at r2
MoveW r2, r0
jsr PrHex16 ; prints EDCC (decimal = 60876)
PrintNewlineldy #0 ; pad char, 0=none
jsr PrSgnDec16 ; ### BUG, prints -4660 OK, but prog corrupted
; jsr PrDec16 ; ### BUG, prints 60876 OK, but prog corruptedEND: rts
;-----------------------------------------------------------------
; FUNCTION: 16-bit Binary Negation (two's complement)
; INPUT: r0
;
; OUTPUT: r2 = 0 - r0 = ~r0 + 1
;-----------------------------------------------------------------
NEG16: ; 16 bit Binary Negation: r2 = 0 - r0 = ~r0 + 1 (two's complement)
SEC ;Ensure carry is set
LDA #0 ;Load constant zero
SBC r0L ;... subtract the least significant byte
STA r2L ;... and store the result
LDA #0 ;Load constant zero again
SBC r0H ;... subtract the most significant byte
STA r2H ;... and store the result
RTS;-----------------------------------------------------------------
; FUNCTION: Print 16-bit decimal number
; INPUT: r0 = value to print, copied to scratch r11
; .Y = pad character
; (e.g. '0' #48 or ' ' #32 or #0 for none)
;-----------------------------------------------------------------
PrSgnDec16:
phy ; save .Y = padding char
lda r0H ; load MSB
and #$80 ; check for sign bit of MSB
beq LL1 ; positive, print normally
jsr NEG16 ; negative, NEG16 result at r2
lda #'-' ; print '-' sign
jsr CHROUT
MoveW r2, r0 ; load new positive value
LL1:
ply ; restore .Y;-----------------------------------------------------------------
; FUNCTION: Print 16-bit decimal number
; INPUT: r0 = value to print, copied to scratch r11
; .Y = pad character
; (e.g. '0' #48 or ' ' #32 or #0 for none)
;
; INPUT: at PrDec16Lp1
; Y=(number of digits)*2-2, e.g. 8 for 5 digits
;
; OUTPUT: A,X,Y corrupted
;-----------------------------------------------------------------
PrDec16:
STY pad ; Save new padding character
MoveW r0, r11
LDY #8 ; Offset to powers of ten
PrDec16Lp1:
LDX #$FF ; Start with digit=-1
SEC
PrDec16Lp2:
LDA r11L ; Subtract current tens
SBC PrDec16Tens+0,Y
STA r11L
LDA r11H
SBC PrDec16Tens+1,Y
STA r11H
INX ; Loop until <0
BCS PrDec16Lp2
LDA r11L ; Add current tens back in
ADC PrDec16Tens+0,Y
STA r11L
LDA r11H
ADC PrDec16Tens+1,Y
STA r11H
TXA ; Not zero, print it
BNE PrDec16Digit
LDA pad ; pad<>0, use it
BNE PrDec16Print
BEQ PrDec16Next
PrDec16Digit:
LDX #48 ; ASC"0", No more zero padding
STX pad
ORA #48 ; ASC"0", Print this digit
PrDec16Print:
JSR CHROUT
PrDec16Next:
DEY ; Loop for next digit
DEY
BPL PrDec16Lp1
RTS
PrDec16Tens:
.word 1
.word 10
.word 100
.word 1000
.word 10000
pad: .res 0 ; default 0 = no padding;-----------------------------------------------------------------
; FUNCTION: Print 8-bit hexadecimal number
; INPUT: .A = value to print
;
; OUTPUT:
;-----------------------------------------------------------------
PrHex8: ; Print value in A in hexadecimal padded with zeros,
PHA ; Save A
LSR A ; Move top nybble to bottom nybble
LSR A
LSR A
LSR A
JSR PrNybble ; Print this nybble
PLA ; Get A back and print bottom nybble
PrNybble:
AND #15 ; Keep bottom four bits
CMP #10 ; If 0-9, jump to print
BCC PrDigit
ADC #6 ; Convert ':' to 'A'
PrDigit:
ADC #48 ; ASC"0"
JSR CHROUT ; Convert to character and print
RTS;-----------------------------------------------------------------
; FUNCTION: Print 16-bit hexadecimal number
; INPUT: r0 = Word to print
;
; OUTPUT:
;-----------------------------------------------------------------
PrHex16:
;pha
;txa
lda r0H
jsr PrHex8
lda r0L
;pla
jsr PrHex8
rts
C:\dev\src>rm test.prg
C:\dev\src>cl65 -o test.prg -t cx16 -C cx16-asm.cfg test.asm
C:\dev\src>\x16-r38\x16emu.exe -prg test.prg -run
-
I'm happy to share a preview of my INTEGER BASIC compiler written in Python using Lark for lexer and parser. Below shows the BASIC "hello world" program, followed by the AST, and the compiled code. Note the use of the virtual ABI r0 register to pass the string pointer to the PRINT routine:
Hmm... that "CMP #0" in the PRINT routine can now vanish... forgot about it! As a matter of fact, "PHX" and "PLX" should be changed because I replaced the index from X-reg to Y-reg for (indirect), Y addressing mode.
-
4 hours ago, desertfish said:Personally, I just wrote my own little strout routine that only uses the CHROUT kernal routine at its documented location. It's only a few instructions long. Any reason you really want to use basic's STROUT?
Mainly because I was thinking about economy of code, if it already exists in ROM, why not use it? Floating-point math also comes to mind.
But you're right, it's probably easier and much more compact to write our own PRINT function. I was already certain that a library would exist in HIGH RAM for my other functions such as 32-bit fixed-point math and Woz's 32-bit floating-point math.
The real reason I did it was because it's another way of doing HELLO WORLD and I learned a thing or two doing it!
-
52 minutes ago, Ender said:Oh cool, well if you already have an example of how to use it, then it's worth a try. You'd just change the definition of STROUT to $CD52, and make sure to change the ROM bank to 4 first.
Yay, it works! How did you figure out the ROM address for STROUT from code7.s? Hex string search or an easier way?
Quote;
; cl65 -o hw.prg -t cx16 -C cx16-asm.cfg hw.asm
;
; Run with x16emu.exe -prg hw.prg -run -scale 2
;
; hw.s: example using BASIC ROM routine to output a string
.org $0801 ; Assembled code should start at $0801
; (where BASIC programs start)
; The real program starts at $0810 = 2064; 10 SYS 2064
.byte $0C, $08 ; $080C - pointer to next line of BASIC code
.byte $0A, $00 ; 2-byte line number ($000A = 10)
.byte $9E ; SYS BASIC token
.byte $20 ; [space]
.byte $32, $30, $36, $34 ; $32="2",$30="0",$36="6",$34="4"
.byte $00 ; End of Line
.byte $00, $00 ; This is address $080C containing
; 2-byte pointer to next line of BASIC code
; ($0000 = end of program)
.byte $00, $00 ; Padding so code starts at $0810
STROUT = $CD52 ; BASIC in ROM BANK #4
VIA1 = $9F60 ; PB0-2 = 0-7LDA #4
STA VIA1
LDA #<msg
LDY #>msg
JMP STROUT
LDA #0
STA VIA1
RTSmsg:
.byte "hello world! ", 0 -
2 minutes ago, SlithyMatt said:As the X16 will have flashable ROM, it's really a bad idea to try to call code inside the BASIC interpreter. You won't know what build someone is using, but the published Kernal API should be stable, so stick with that.
I'm thinking about saving work, time, and RAM by using pre-made BASIC routines in one's assembly code, e.g. TAN, COS, *, \, PRINT, etc.
Once the BASIC ROM is stable enough, it should be safe to use. To avoid all this headache, maybe a JUMP TABLE would be a nice idea.
Eventually it will be used in my INTEGER BASIC compiler because it doesn't have floating-point math
-
7 minutes ago, Ender said:Well, if the address is a spot within the BASIC code, then it's not a vector kernal routine, therefore something not meant to be used by the user. That said, it looks like it's $CD52 on bank 4 on the X16 (in the source code it's in basic/code7.s). You can play around with it if you want, but it probably requires a very specific setup to actually use it.
Just like so... on a C64 which should be equivalent on the X16. How does one call a function in ROM BANK #4?
Quote; hw.s: example using BASIC ROM routine to output a string
; cl65 hw.s -o hw.prg -C c64-asm.cfg -u __EXEHDR__
LOWERCASE = $0E
CLRSCR = $93
WHITE = $05
LTBLUE = $9A
STROUT = $AB1ELDA #<msg
LDY #>msg
JMP STROUTmsg:
.byte LOWERCASE, CLRSCR, WHITE, "Hello World!", LTBLUE, 0
Prog8 language and compiler topic
in X16 General Chat
Posted
@desertfish awesome work! I sometimes wonder how you are able to dedicate so much time on your project! I have been away for a month or so due to graduate studies but I'm finally done for the semester and can now do some fun work on my compiler!