mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-22 12:29:06 +00:00
atari8: fastbasic, only int-mode and builds carts right now
This commit is contained in:
parent
b78fbe5ac4
commit
b344590917
@ -64,6 +64,8 @@ The IDE uses custom forks for many of these, found at https://github.com/sehugg?
|
||||
* https://www.veripool.org/wiki/verilator
|
||||
* http://mcpp.sourceforge.net/
|
||||
* http://www.ifarchive.org/indexes/if-archiveXinfocomXcompilersXinform6.html
|
||||
* https://github.com/dmsc/fastbasic
|
||||
* https://github.com/apple2accumulator/merlin32
|
||||
|
||||
### Assemblers/Linkers
|
||||
|
||||
|
@ -380,9 +380,9 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
||||
</div>
|
||||
<div class="emucontrols-atari8 text-center small control-insns" style="display:none">
|
||||
<span class="control-def"><span class="control-key">←↑↓→</span> Joystick</span>
|
||||
<span class="control-def"><span class="control-key">Z</span> Button 1</span>
|
||||
<span class="control-def"><span class="control-key">X</span> Button 2</span>
|
||||
<span class="control-def"><span class="control-key">1</span> Start</span>
|
||||
<span class="control-def"><span class="control-key small">Left Ctrl</span> Button 1</span>
|
||||
<span class="control-def"><span class="control-key small">Left Alt</span> Button 2</span>
|
||||
</div>
|
||||
<!-- -->
|
||||
<div id="emuoverlay" class="emuoverlay" style="display:none">
|
||||
@ -557,6 +557,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
||||
<script src="src/codemirror/6502.js"></script>
|
||||
<script src="src/codemirror/bataribasic.js"></script>
|
||||
<script src="src/codemirror/inform6.js"></script>
|
||||
<script src="src/codemirror/fastbasic.js"></script>
|
||||
<link rel="stylesheet" href="css/codemirror.css">
|
||||
<script src="codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script src="codemirror/addon/search/search.js"></script>
|
||||
|
72
presets/atari8-800xl/dli.bas
Normal file
72
presets/atari8-800xl/dli.bas
Normal file
@ -0,0 +1,72 @@
|
||||
' Define the DLI: set background
|
||||
' color to $24 = dark red.
|
||||
DLI SET d1 = $24 INTO $D01A
|
||||
' Setups screen
|
||||
GRAPHICS 0
|
||||
' Alter the Display List, adds
|
||||
' a DLI at line 11 on the screen
|
||||
POKE DPEEK(560) + 16, 130
|
||||
' Activate DLI
|
||||
DLI d1
|
||||
' Wait for any keyu
|
||||
? "Press a Key" : GET K
|
||||
' Disable the DLI
|
||||
DLI
|
||||
|
||||
? "Again..."
|
||||
GET K
|
||||
|
||||
' An array with color values
|
||||
DATA Colors() BYTE = $24,$46,$68
|
||||
' Define the DLI: set background
|
||||
' color from the Color() array
|
||||
' and text color with value $80
|
||||
DLI SET d2 = Colors INTO $D01A, $80 INTO $D018
|
||||
' Setups screen
|
||||
GRAPHICS 0
|
||||
' Adds DLI at three lines:
|
||||
POKE DPEEK(560) + 13, 130
|
||||
POKE DPEEK(560) + 16, 130
|
||||
POKE DPEEK(560) + 19, 130
|
||||
' Activate DLI
|
||||
DLI d2
|
||||
' Wait for any keyu
|
||||
? "Press a Key" : GET K
|
||||
' Disable the DLI
|
||||
DLI
|
||||
|
||||
? "Again..."
|
||||
GET K
|
||||
|
||||
' Player shapes, positions and colors
|
||||
DATA p1() BYTE = $E7,$81,$81,$E7
|
||||
DATA p2() BYTE = $18,$3C,$3C,$18
|
||||
DATA pos() BYTE = $40,$60,$80,$A0
|
||||
DATA c1() BYTE = $28,$88,$C8,$08
|
||||
DATA c2() BYTE = $2E,$80,$CE,$06
|
||||
' Our DLI writes the position and
|
||||
' colors to Player 1 and Player 2
|
||||
DLI SET d3 = pos INTO $D000, pos INTO $D001,
|
||||
DLI = c1 INTO $D012, c2 INTO $D013
|
||||
GRAPHICS 0 : PMGRAPHICS 2
|
||||
' Setup our 4 DLI and Players
|
||||
FOR I = 8 TO 20 STEP 4
|
||||
POKE DPEEK(560) + I, 130
|
||||
MOVE ADR(p1), PMADR(0)+I*4+5,4
|
||||
MOVE ADR(p2), PMADR(1)+I*4+5,4
|
||||
NEXT
|
||||
' Activate DLI
|
||||
DLI d3
|
||||
? "Press a Key"
|
||||
REPEAT
|
||||
PAUSE 0
|
||||
pos(0) = pos(0) + 2
|
||||
pos(1) = pos(1) + 1
|
||||
pos(2) = pos(2) - 1
|
||||
pos(3) = pos(3) - 2
|
||||
UNTIL KEY()
|
||||
DLI
|
||||
|
||||
? "Key to end..."
|
||||
GET K
|
||||
|
265
presets/atari8-800xl/joyas.bas
Normal file
265
presets/atari8-800xl/joyas.bas
Normal file
@ -0,0 +1,265 @@
|
||||
'-------------------------------------
|
||||
' Joyas: A match-three pieces game
|
||||
'
|
||||
|
||||
' Character set redefinition
|
||||
'/*{w:8,h:8,bpp:1,brev:1,count:13}*/
|
||||
data charset() byte = $D0,$68,$34,$68,$D0,$68,$34,$68, ' 1: Wall 1
|
||||
data byte = $16,$2C,$58,$2C,$16,$2C,$58,$2C, ' 2: Wall 2
|
||||
data byte = $00,$18,$68,$44,$2C,$30,$00,$00, ' 3: Rotated square
|
||||
data byte = $00,$10,$38,$6C,$38,$10,$00,$00, ' 4: Diamond
|
||||
data byte = $00,$7C,$54,$7C,$54,$7C,$00,$00, ' 5: Filled Square
|
||||
data byte = $00,$64,$2C,$10,$68,$4C,$00,$00, ' 6: Cross
|
||||
data byte = $00,$38,$4C,$5C,$7C,$38,$00,$00, ' 7: Big ball
|
||||
data byte = $00,$5C,$40,$54,$04,$74,$00,$00, ' 8: Flag?
|
||||
data byte = $00,$00,$00,$00,$00,$00,$00,$00, ' 9: Explosion
|
||||
data byte = $7C,$82,$82,$82,$82,$82,$7C,$00, '10: Cursor
|
||||
data byte = $D1,$6A,$35,$1B,$0E,$04,$00,$00, ' B: Bottom-left
|
||||
data byte = $11,$AA,$55,$BB,$EE,$44,$00,$00, ' C: Bottom
|
||||
data byte = $16,$AC,$58,$B0,$E0,$40,$00,$00 ' D: Bottom-right
|
||||
';
|
||||
'/*{w:8,h:8,bpp:1,brev:1,count:4}*/
|
||||
data explode() byte = $00,$00,$00,$38,$54,$38,$00,$00,
|
||||
data byte = $00,$00,$24,$40,$12,$08,$44,$00,
|
||||
data byte = $00,$42,$00,$80,$00,$01,$00,$82,
|
||||
data byte = $00,$00,$00,$00,$00,$00,$00,$00
|
||||
';
|
||||
' Our board pieces:
|
||||
data pieces() byte = $03, $44, $85, $C6, $07, $48
|
||||
|
||||
' Our empty board (two lines)
|
||||
data eboard() byte = $80,$40,$81,$09,$09,$09,$09,$09,$09,$09,$09,$09,$09,$82,$40,$80,
|
||||
data byte = $40,$80,$81,$09,$09,$09,$09,$09,$09,$09,$09,$09,$09,$82,$80,$40
|
||||
data lboard() byte = $80,$40,$8B,$8C,$8C,$8C,$8C,$8C,$8C,$8C,$8C,$8C,$8C,$8D,$40,$80
|
||||
|
||||
' Set graphics mode and narrow screen
|
||||
graphics 18
|
||||
poke 559, 33
|
||||
|
||||
' Redefine character set
|
||||
move $E000, $7C00, 512
|
||||
move adr(charset), $7C08, 104
|
||||
poke 756, $7C
|
||||
|
||||
' Set colors
|
||||
if peek($d014) = 1
|
||||
' PAL
|
||||
se. 0,3,8
|
||||
se. 1,11,10
|
||||
se. 2,8,6
|
||||
se. 3,14,14
|
||||
else
|
||||
' NTSC
|
||||
se. 0,4,8
|
||||
se. 1,12,10
|
||||
se. 2,9,6
|
||||
se. 3,2,14
|
||||
endif
|
||||
|
||||
' Memory area for the board
|
||||
mainBoard = $7000 + 19
|
||||
fullBoard = $7000 + 16
|
||||
' Clear board, needed to detect bad moves
|
||||
mset $7000, 192, 0
|
||||
|
||||
hiScore = 0
|
||||
screen = dpeek(88)
|
||||
screenBoard = screen + 3
|
||||
C = mainBoard - screenBoard
|
||||
|
||||
' Loop forever
|
||||
do
|
||||
|
||||
' Clear board
|
||||
for i=0 to 4
|
||||
move adr(eboard), fullBoard+i*32, 32
|
||||
next i
|
||||
|
||||
' Init game variables
|
||||
score = 0 ' Score
|
||||
nmoves = 15 ' Remaining moves
|
||||
addMove = 16 ' Points to bonus
|
||||
crsPos = 0 ' Cursor pos
|
||||
|
||||
' Clear the screen
|
||||
mset screen, 176, 0
|
||||
position 0, 0
|
||||
|
||||
' Show game info
|
||||
print #6, , , " joyas", , , "HI SCORE:"; hiScore
|
||||
print #6, "BUTTON: game"
|
||||
|
||||
' Wait for button press and release
|
||||
repeat : until not strig(0)
|
||||
repeat : until strig(0)
|
||||
|
||||
' Disable attract mode
|
||||
poke 77,0
|
||||
' Draw bottom of board
|
||||
move adr(lboard), screen+160, 16
|
||||
|
||||
' Call game loop
|
||||
while nmoves > 0
|
||||
exec GameLoop
|
||||
wend
|
||||
|
||||
if hiScore < score then hiScore = score
|
||||
|
||||
loop
|
||||
|
||||
'-------------------------------------
|
||||
' Move the cursor and wait for play
|
||||
proc MoveCursor
|
||||
|
||||
' Loop
|
||||
do
|
||||
' Disable attract mode
|
||||
poke 77,0
|
||||
|
||||
' Wait for valid move
|
||||
repeat
|
||||
' Show cursor
|
||||
poke crsPos+screenBoard, 192+10
|
||||
pause 1
|
||||
' Remove cursor
|
||||
poke crsPos+screenBoard, peek(crsPos+mainBoard)
|
||||
pause 1
|
||||
' Move cursor
|
||||
i = stick(0)
|
||||
nxtPos = (i=7) - (i=11) + 16 * ((i=13) - (i=14)) + crsPos
|
||||
until nxtPos <> crsPos and peek(nxtPos + mainBoard) & 63 > 2
|
||||
|
||||
' If button is pressed, return
|
||||
if not strig(0) then Exit
|
||||
|
||||
' Move cursor
|
||||
crsPos = nxtPos
|
||||
loop
|
||||
|
||||
endproc
|
||||
|
||||
|
||||
'-------------------------------------
|
||||
' Make pieces fall in the board
|
||||
proc FallPieces
|
||||
|
||||
' Loop until there are holes in the board
|
||||
repeat
|
||||
|
||||
endFall = 1
|
||||
|
||||
' Move board to screen
|
||||
move fullBoard, screen, 160
|
||||
|
||||
' Search for holes in the board
|
||||
for A=mainBoard to mainBoard + 151 step 16
|
||||
for P=A to A+9
|
||||
if peek(P) & 63 = 9
|
||||
' If we found a hole, fall pieces!
|
||||
i = P
|
||||
while i > mainBoard + 15
|
||||
poke i, peek(i-16)
|
||||
i = i-16
|
||||
wend
|
||||
' Set new piece and set A to exit outer loop
|
||||
poke i, pieces(rand(6))
|
||||
A = mainBoard + 152
|
||||
endFall = 0
|
||||
endif
|
||||
next P
|
||||
next A
|
||||
until endFall
|
||||
|
||||
endproc
|
||||
|
||||
'-------------------------------------
|
||||
' Search matching pieces and remove
|
||||
proc MatchPieces
|
||||
|
||||
' Number of matches found
|
||||
lsize = 0
|
||||
|
||||
' Go through each line
|
||||
for A = screenBoard to screenBoard + 151 step 16
|
||||
' And through each column
|
||||
for X=A to A+9
|
||||
P = peek(X)
|
||||
' Test if equal to the next two pieces
|
||||
if P = peek(X+1) and P = peek(X+2)
|
||||
' Transform screen pointer to board pointer
|
||||
Y = X + C
|
||||
' Clean the three pieces found
|
||||
PC = (P & 192) + 9
|
||||
poke Y, PC
|
||||
poke Y+1, PC
|
||||
poke Y+2, PC
|
||||
inc lsize
|
||||
endif
|
||||
|
||||
' Test if equal to the two pieces bellow
|
||||
IF P = peek(X + 16) and P = peek(X + 32)
|
||||
' Transform screen pointer to board pointer
|
||||
Y = X + C
|
||||
' Clean the three pieces found
|
||||
PC = (P & 192) + 9
|
||||
poke Y, PC
|
||||
poke Y + 16, PC
|
||||
poke Y + 32, PC
|
||||
inc lsize
|
||||
endif
|
||||
next X
|
||||
next A
|
||||
|
||||
if lsize
|
||||
' Found a line, add to score and show a little animation
|
||||
score = score + lsize * lsize
|
||||
move fullBoard, screen, 160
|
||||
|
||||
for i = 0 to 3
|
||||
sound 1, 80, 0, 10 - i * 3
|
||||
' Set animation frame
|
||||
move i*8 + adr(explode), $7C48, 8
|
||||
pause 4
|
||||
next i
|
||||
endif
|
||||
|
||||
' Add one move at 16, 32, 64, etc. points
|
||||
if score >= addMove
|
||||
inc nmoves
|
||||
addMove = addMove * 2
|
||||
endif
|
||||
|
||||
' Print current score and moves left
|
||||
position 18, 8
|
||||
print #6, "score "; score; "/"; nmoves,
|
||||
sound
|
||||
|
||||
endproc
|
||||
|
||||
'-------------------------------------
|
||||
' Our main game loop
|
||||
proc GameLoop
|
||||
|
||||
' Update number of moves
|
||||
dec nmoves
|
||||
|
||||
' Loop until no pieces are left to move
|
||||
repeat
|
||||
exec FallPieces
|
||||
exec MatchPieces
|
||||
until not lsize
|
||||
|
||||
' Game over if no more moves
|
||||
if nmoves < 1 then exit
|
||||
|
||||
exec MoveCursor
|
||||
|
||||
' Perform an exchange
|
||||
poke crsPos + mainBoard, peek(nxtPos + screenBoard)
|
||||
poke nxtPos + mainBoard, peek(crsPos + screenBoard)
|
||||
sound 0, 100, 10, 10
|
||||
pause 2
|
||||
sound
|
||||
|
||||
endproc
|
||||
|
45
presets/atari8-800xl/pmtest.bas
Normal file
45
presets/atari8-800xl/pmtest.bas
Normal file
@ -0,0 +1,45 @@
|
||||
' P/M test program
|
||||
|
||||
graphics 0 ' Setups graphics mode
|
||||
pmgraphics 2 ' And P/M mode
|
||||
P0Mem = pmadr(0) ' Get player 0 address
|
||||
oldPos = P0Mem ' and into "old position"
|
||||
|
||||
mset P0Mem, 128, 0 ' Clears P/M 0 Memory
|
||||
setcolor -4, 1, 15
|
||||
|
||||
' P/M data and blank (to clear P/M)
|
||||
DATA PMdata() byte = $38,$44,$54,$44,$38
|
||||
|
||||
' Initial Conditions
|
||||
xPos = 6400 : yPos = 2560
|
||||
xSpd = 64 : ySpd = 0
|
||||
|
||||
repeat
|
||||
xPos = xPos + xSpd : yPos = yPos + ySpd
|
||||
ySpd = ySpd + 2
|
||||
if (ySpd > 0) and (yPos > 12800)
|
||||
ySpd = -ySpd
|
||||
xSpd = Rand(512) - 256
|
||||
endif
|
||||
if xSpd > 0
|
||||
if xPos > 25600 Then xSpd = -xSpd
|
||||
else
|
||||
if xPos < 6400 Then xSpd = -xSpd
|
||||
endif
|
||||
exec MovePm ' Move P/M Graphics
|
||||
until Key()
|
||||
|
||||
graphics 0
|
||||
|
||||
END
|
||||
|
||||
proc MovePm
|
||||
x = xPos / 128 : y = P0Mem + yPos / 128
|
||||
poke $D01A,$74 ' Change background color
|
||||
pause 0
|
||||
pmhpos 0, x ' Set new horizontal position
|
||||
mset oldPos, 5, 0 ' Clear old sprite
|
||||
move adr(PMdata), y, 5 ' Draw at new vertical pos.
|
||||
oldPos = y
|
||||
endproc
|
26
presets/atari8-800xl/sieve.bas
Normal file
26
presets/atari8-800xl/sieve.bas
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
? "Starting!"
|
||||
NumIter = 10
|
||||
sTime = TIME
|
||||
' Arrays are initialized to 0
|
||||
DIM A(8190) Byte
|
||||
FOR Iter= 1 TO NumIter
|
||||
MSET Adr(A), 8190, 0
|
||||
Count = 0
|
||||
FOR I = 0 TO 8190
|
||||
IF NOT A(I)
|
||||
Prime = I + I + 3
|
||||
FOR K = I + Prime TO 8190 STEP Prime
|
||||
A(K) = 1
|
||||
NEXT K
|
||||
INC Count
|
||||
ENDIF
|
||||
NEXT I
|
||||
NEXT Iter
|
||||
|
||||
eTime = TIME
|
||||
? "End."
|
||||
? "Elapsed time: "; eTime-sTime; " in "; NumIter; " iterations."
|
||||
? "Found "; Count; " primes."
|
||||
|
||||
input "PRESS ENTER TO EXIT...";NAME$
|
282
src/codemirror/fastbasic.js
Normal file
282
src/codemirror/fastbasic.js
Normal file
@ -0,0 +1,282 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("fastbasic", function(conf, parserConf) {
|
||||
var ERRORCLASS = 'error';
|
||||
|
||||
function wordRegexp(words) {
|
||||
return new RegExp("^((" + words.join(")|(") + "))\\b", "i");
|
||||
}
|
||||
|
||||
var singleOperators = new RegExp("^[\\+\\-\\*/%&\\\\|\\^~<>!]");
|
||||
var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
|
||||
var doubleOperators = new RegExp("^((==)|(<>)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
|
||||
var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
|
||||
var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
|
||||
var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
|
||||
|
||||
var openingKeywords = ['while','repeat','proc','do','if','for'];
|
||||
var middleKeywords = ['else','elseif','to'];
|
||||
var endKeywords = ['next','loop','wend','endproc','endif','end','until'];
|
||||
|
||||
var operatorKeywords = ['and', 'or', 'not', 'xor', 'in'];
|
||||
var wordOperators = wordRegexp(operatorKeywords);
|
||||
var commonKeywords = [
|
||||
'as', 'dim', 'break', 'continue','optional', 'then', 'until', 'goto', 'true','false',
|
||||
'data','graphics','poke','se','move','mset',
|
||||
'print','exec','pause','inc','dec','sound',
|
||||
'get','put','cls','input','position','exit',
|
||||
'color','drawto','fcolor','fillto','locate','plot','pmgraphics','pmhpos','setcolor',
|
||||
'bget','bput','close','open','xio',
|
||||
'clr','timer','dli','into','step','set',
|
||||
'dpoke','dpeek','adr','usr',
|
||||
];
|
||||
var commontypes = ['byte','word'];
|
||||
|
||||
var keywords = wordRegexp(commonKeywords);
|
||||
var types = wordRegexp(commontypes);
|
||||
var stringPrefixes = '"';
|
||||
|
||||
var opening = wordRegexp(openingKeywords);
|
||||
var middle = wordRegexp(middleKeywords);
|
||||
var closing = wordRegexp(endKeywords);
|
||||
var doubleClosing = wordRegexp(['end']);
|
||||
var doOpening = wordRegexp(['do']);
|
||||
|
||||
var indentInfo = null;
|
||||
|
||||
CodeMirror.registerHelper("hintWords", "vb", openingKeywords.concat(middleKeywords).concat(endKeywords)
|
||||
.concat(operatorKeywords).concat(commonKeywords).concat(commontypes));
|
||||
|
||||
function indent(_stream, state) {
|
||||
state.currentIndent++;
|
||||
}
|
||||
|
||||
function dedent(_stream, state) {
|
||||
state.currentIndent--;
|
||||
}
|
||||
// tokenizers
|
||||
function tokenBase(stream, state) {
|
||||
if (stream.eatSpace()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ch = stream.peek();
|
||||
|
||||
// Handle Comments
|
||||
if (ch === "'") {
|
||||
stream.skipToEnd();
|
||||
return 'comment';
|
||||
}
|
||||
|
||||
|
||||
// Handle Number Literals
|
||||
if (stream.match(/^(\$)?[0-9\.a-f]/i, false)) {
|
||||
var floatLiteral = false;
|
||||
// Floats
|
||||
if (stream.match(/^\d*\.\d+F?/i)) { floatLiteral = true; }
|
||||
else if (stream.match(/^\d+\.\d*F?/)) { floatLiteral = true; }
|
||||
else if (stream.match(/^\.\d+F?/)) { floatLiteral = true; }
|
||||
|
||||
if (floatLiteral) {
|
||||
// Float literals may be "imaginary"
|
||||
stream.eat(/J/i);
|
||||
return 'number';
|
||||
}
|
||||
// Integers
|
||||
var intLiteral = false;
|
||||
// Hex
|
||||
if (stream.match(/^\$[0-9a-f]+/i)) { intLiteral = true; }
|
||||
// Octal
|
||||
else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; }
|
||||
// Decimal
|
||||
else if (stream.match(/^[1-9]\d*F?/)) {
|
||||
// Decimal literals may be "imaginary"
|
||||
stream.eat(/J/i);
|
||||
// TODO - Can you have imaginary longs?
|
||||
intLiteral = true;
|
||||
}
|
||||
// Zero by itself with no other piece of number.
|
||||
else if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
|
||||
if (intLiteral) {
|
||||
// Integer literals may be "long"
|
||||
stream.eat(/L/i);
|
||||
return 'number';
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Strings
|
||||
if (stream.match(stringPrefixes)) {
|
||||
state.tokenize = tokenStringFactory(stream.current());
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
|
||||
// Handle operators and Delimiters
|
||||
if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
|
||||
return null;
|
||||
}
|
||||
if (stream.match(doubleOperators)
|
||||
|| stream.match(singleOperators)
|
||||
|| stream.match(wordOperators)) {
|
||||
return 'operator';
|
||||
}
|
||||
if (stream.match(singleDelimiters)) {
|
||||
return null;
|
||||
}
|
||||
if (stream.match(doOpening)) {
|
||||
indent(stream,state);
|
||||
state.doInCurrentLine = true;
|
||||
return 'keyword';
|
||||
}
|
||||
if (stream.match(opening)) {
|
||||
if (! state.doInCurrentLine)
|
||||
indent(stream,state);
|
||||
else
|
||||
state.doInCurrentLine = false;
|
||||
return 'keyword';
|
||||
}
|
||||
if (stream.match(middle)) {
|
||||
return 'keyword';
|
||||
}
|
||||
|
||||
if (stream.match(doubleClosing)) {
|
||||
dedent(stream,state);
|
||||
dedent(stream,state);
|
||||
return 'keyword';
|
||||
}
|
||||
if (stream.match(closing)) {
|
||||
dedent(stream,state);
|
||||
return 'keyword';
|
||||
}
|
||||
|
||||
if (stream.match(types)) {
|
||||
return 'keyword';
|
||||
}
|
||||
|
||||
if (stream.match(keywords)) {
|
||||
return 'keyword';
|
||||
}
|
||||
|
||||
if (stream.match(identifiers)) {
|
||||
return 'variable';
|
||||
}
|
||||
|
||||
// Handle non-detected items
|
||||
stream.next();
|
||||
return ERRORCLASS;
|
||||
}
|
||||
|
||||
function tokenStringFactory(delimiter) {
|
||||
var singleline = delimiter.length == 1;
|
||||
var OUTCLASS = 'string';
|
||||
|
||||
return function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
stream.eatWhile(/[^'"]/);
|
||||
if (stream.match(delimiter)) {
|
||||
state.tokenize = tokenBase;
|
||||
return OUTCLASS;
|
||||
} else {
|
||||
stream.eat(/['"]/);
|
||||
}
|
||||
}
|
||||
if (singleline) {
|
||||
if (parserConf.singleLineStringErrors) {
|
||||
return ERRORCLASS;
|
||||
} else {
|
||||
state.tokenize = tokenBase;
|
||||
}
|
||||
}
|
||||
return OUTCLASS;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function tokenLexer(stream, state) {
|
||||
var style = state.tokenize(stream, state);
|
||||
var current = stream.current();
|
||||
|
||||
// Handle '.' connected identifiers
|
||||
if (current === '.') {
|
||||
style = state.tokenize(stream, state);
|
||||
if (style === 'variable') {
|
||||
return 'variable';
|
||||
} else {
|
||||
return ERRORCLASS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var delimiter_index = '[({'.indexOf(current);
|
||||
if (delimiter_index !== -1) {
|
||||
indent(stream, state );
|
||||
}
|
||||
if (indentInfo === 'dedent') {
|
||||
if (dedent(stream, state)) {
|
||||
return ERRORCLASS;
|
||||
}
|
||||
}
|
||||
delimiter_index = '])}'.indexOf(current);
|
||||
if (delimiter_index !== -1) {
|
||||
if (dedent(stream, state)) {
|
||||
return ERRORCLASS;
|
||||
}
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
var external = {
|
||||
electricChars:"dDpPtTfFeE ",
|
||||
startState: function() {
|
||||
return {
|
||||
tokenize: tokenBase,
|
||||
lastToken: null,
|
||||
currentIndent: 0,
|
||||
nextLineIndent: 0,
|
||||
doInCurrentLine: false
|
||||
|
||||
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
state.currentIndent += state.nextLineIndent;
|
||||
state.nextLineIndent = 0;
|
||||
state.doInCurrentLine = 0;
|
||||
}
|
||||
var style = tokenLexer(stream, state);
|
||||
|
||||
state.lastToken = {style:style, content: stream.current()};
|
||||
|
||||
|
||||
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
var trueText = textAfter.replace(/^\s+|\s+$/g, '') ;
|
||||
if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1);
|
||||
if(state.currentIndent < 0) return 0;
|
||||
return state.currentIndent * conf.indentUnit;
|
||||
},
|
||||
|
||||
lineComment: "'"
|
||||
};
|
||||
return external;
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-vb", "vb");
|
||||
|
||||
});
|
@ -80,6 +80,7 @@ var TOOL_TO_SOURCE_STYLE = {
|
||||
'yasm': 'gas',
|
||||
'smlrc': 'text/x-csrc',
|
||||
'inform6': 'inform6',
|
||||
'fastbasic': 'fastbasic',
|
||||
}
|
||||
|
||||
function gaEvent(category:string, action:string, label?:string, value?:string) {
|
||||
@ -1907,6 +1908,7 @@ function addPageFocusHandlers() {
|
||||
// TODO: merge w/ embed.html somehow?
|
||||
function showInstructions() {
|
||||
var div = $(document).find(".emucontrols-" + getRootBasePlatform(platform_id));
|
||||
if (platform_id.endsWith(".mame")) div.show(); // TODO: MAME seems to eat the focus() event
|
||||
var vcanvas = $("#emulator").find("canvas");
|
||||
if (vcanvas) {
|
||||
vcanvas.on('focus', () => {
|
||||
|
@ -15,6 +15,13 @@ var Atari8_PRESETS = [
|
||||
{id:'hellodlist.c', name:'Display List (C)'},
|
||||
];
|
||||
|
||||
var Atari800_PRESETS = Atari8_PRESETS.concat([
|
||||
{id:'sieve.bas', name:'Benchmark (FastBasic)'},
|
||||
{id:'pmtest.bas', name:'Sprites Test (FastBasic)'},
|
||||
{id:'dli.bas', name:'DLI Test (FastBasic)'},
|
||||
{id:'joyas.bas', name:'Match-3 Game (FastBasic)'},
|
||||
]);
|
||||
|
||||
const ATARI8_KEYCODE_MAP = makeKeycodeMap([
|
||||
[Keys.VK_SPACE, 0, 0],
|
||||
[Keys.VK_ENTER, 0, 0],
|
||||
@ -780,12 +787,22 @@ for (var i=0; i<256; i++) {
|
||||
|
||||
abstract class Atari8MAMEPlatform extends BaseMAMEPlatform {
|
||||
getPresets() { return Atari8_PRESETS; }
|
||||
getToolForFilename = getToolForFilename_6502;
|
||||
getToolForFilename = function(fn:string) {
|
||||
if (fn.endsWith(".bas") || fn.endsWith(".fb") || fn.endsWith(".fbi")) return "fastbasic";
|
||||
else return getToolForFilename_6502(fn);
|
||||
}
|
||||
getOpcodeMetadata = getOpcodeMetadata_6502;
|
||||
getDefaultExtension() { return ".asm"; };
|
||||
showHelp(tool:string, ident:string) {
|
||||
if (tool == 'fastbasic')
|
||||
window.open("https://github.com/dmsc/fastbasic/blob/master/manual.md", "_help");
|
||||
else
|
||||
window.open("https://atariwiki.org/wiki/Wiki.jsp?page=Assembler", "_help"); // TODO
|
||||
}
|
||||
}
|
||||
|
||||
class Atari800MAMEPlatform extends Atari8MAMEPlatform implements Platform {
|
||||
getPresets() { return Atari800_PRESETS; }
|
||||
loadROM(title, data) {
|
||||
if (!this.started) {
|
||||
this.startModule(this.mainElement, {
|
||||
|
57
src/worker/lib/atari8-800xl/fastbasic-cart.cfg
Normal file
57
src/worker/lib/atari8-800xl/fastbasic-cart.cfg
Normal file
@ -0,0 +1,57 @@
|
||||
#
|
||||
# FastBasic - Fast basic interpreter for the Atari 8-bit computers
|
||||
# Copyright (C) 2017-2019 Daniel Serpell
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#
|
||||
|
||||
# Linker configuration file for placing the code in a CARTRIDGE
|
||||
# -------------------------------------------------------------
|
||||
|
||||
FEATURES {
|
||||
# This defines the start of RAM used for the program
|
||||
STARTADDRESS: default = $2000;
|
||||
}
|
||||
SYMBOLS {
|
||||
__STARTADDRESS__: type = export, value = %S;
|
||||
__CARTFLAGS__: type = weak, value = $05;
|
||||
_FASTBASIC_CART_: type = import;
|
||||
}
|
||||
|
||||
MEMORY {
|
||||
# Interpreter in ZP
|
||||
INTERP: file = "", start = $0082, size = $0012;
|
||||
# Non initialized ZP
|
||||
ZP: file = "", define = yes, start = $0094, size = $0040;
|
||||
# Main memory - used for writable DATA
|
||||
MAIN: file = "", define = yes, start = %S, size = $8000;
|
||||
# Cartridge ROM
|
||||
ROM: file = %O, define = yes, start = $A000, size = $1FFA, fill = yes, fillval = $FF;
|
||||
# Cartridge header
|
||||
CARTID: file = %O, start = $BFFA, size = 6;
|
||||
}
|
||||
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp, optional = yes;
|
||||
JUMPTAB: load = ROM, type = ro, define = yes, align = $100;
|
||||
RUNTIME: load = ROM, type = ro, define = yes;
|
||||
BYTECODE: load = ROM, type = ro, define = yes;
|
||||
CODE: load = ROM, type = rw, define = yes;
|
||||
INTERP: load = ROM, run = INTERP, type = rw, define = yes;
|
||||
RT_DATA: load = ROM, run = MAIN, type = rw, define = yes;
|
||||
DATA: load = ROM, run = MAIN type = rw, optional = yes, define = yes;
|
||||
BSS: load = MAIN, type = bss, optional = yes, define = yes;
|
||||
CARTHDR: load = CARTID, type = ro;
|
||||
}
|
||||
|
BIN
src/worker/lib/atari8-800xl/fastbasic-fp.lib
Normal file
BIN
src/worker/lib/atari8-800xl/fastbasic-fp.lib
Normal file
Binary file not shown.
BIN
src/worker/lib/atari8-800xl/fastbasic-int.lib
Normal file
BIN
src/worker/lib/atari8-800xl/fastbasic-int.lib
Normal file
Binary file not shown.
60
src/worker/lib/atari8-800xl/fastbasic.cfg
Normal file
60
src/worker/lib/atari8-800xl/fastbasic.cfg
Normal file
@ -0,0 +1,60 @@
|
||||
#
|
||||
# FastBasic - Fast basic interpreter for the Atari 8-bit computers
|
||||
# Copyright (C) 2017-2019 Daniel Serpell
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#
|
||||
|
||||
# Linker configuration file
|
||||
# -------------------------
|
||||
|
||||
FEATURES {
|
||||
# This defines the start of RAM used for the program
|
||||
STARTADDRESS: default = $2000;
|
||||
}
|
||||
SYMBOLS {
|
||||
__STARTADDRESS__: type = export, value = %S;
|
||||
}
|
||||
|
||||
MEMORY {
|
||||
ZP: file = "", define = yes, start = $0094, size = $0040;
|
||||
# Used by the IDE to write the header into compiled programs
|
||||
PREMAIN: file = %O, define = yes, start = %S-4, size = 4;
|
||||
# "main program" load chunk
|
||||
MAIN: file = %O, define = yes, start = %S, size = $BC20 - %S;
|
||||
# code in zero page!
|
||||
INTERP: file = %O, define = yes, start = $0082, size = $0012;
|
||||
}
|
||||
|
||||
#FILES {
|
||||
# %O: format = atari;
|
||||
#}
|
||||
|
||||
#FORMATS {
|
||||
# atari: runad = start;
|
||||
#}
|
||||
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp, optional = yes;
|
||||
PREHEAD: load = PREMAIN, type = rw, optional = yes, define = yes;
|
||||
JUMPTAB: load = MAIN, type = ro, define = yes, align = $100;
|
||||
RUNTIME: load = MAIN, type = rw, define = yes;
|
||||
RT_DATA: load = MAIN, type = rw, define = yes;
|
||||
BYTECODE: load = MAIN, type = rw, define = yes;
|
||||
CODE: load = MAIN, type = rw, define = yes;
|
||||
ALIGNDATA:load = MAIN, type = ro, optional = yes, define = yes, align = $100;
|
||||
DATA: load = MAIN, type = rw optional = yes, define = yes;
|
||||
BSS: load = MAIN, type = bss, optional = yes, define = yes;
|
||||
INTERP: load = INTERP, type = rw;
|
||||
}
|
22
src/worker/wasm/fastbasic-fp.js
Normal file
22
src/worker/wasm/fastbasic-fp.js
Normal file
File diff suppressed because one or more lines are too long
BIN
src/worker/wasm/fastbasic-fp.wasm
Normal file
BIN
src/worker/wasm/fastbasic-fp.wasm
Normal file
Binary file not shown.
22
src/worker/wasm/fastbasic-int.js
Normal file
22
src/worker/wasm/fastbasic-int.js
Normal file
File diff suppressed because one or more lines are too long
BIN
src/worker/wasm/fastbasic-int.wasm
Normal file
BIN
src/worker/wasm/fastbasic-int.wasm
Normal file
Binary file not shown.
@ -2612,6 +2612,43 @@ function assembleMerlin32(step:BuildStep) {
|
||||
}
|
||||
}
|
||||
|
||||
// README.md:2:5: parse error, expected: statement or variable assignment, integer variable, variable assignment
|
||||
function compileFastBasic(step:BuildStep) {
|
||||
// TODO: fastbasic-fp?
|
||||
loadNative("fastbasic-int");
|
||||
var params = step.params;
|
||||
gatherFiles(step, {mainFilePath:"main.fb"});
|
||||
var destpath = step.prefix + '.s';
|
||||
var errors = [];
|
||||
if (staleFiles(step, [destpath])) {
|
||||
var fastbasic = emglobal.fastbasic({
|
||||
instantiateWasm: moduleInstFn('fastbasic-int'),
|
||||
noInitialRun:true,
|
||||
print:print_fn,
|
||||
printErr:makeErrorMatcher(errors, /(.+?):(\d+):(\d+):\s*(.+)/, 2, 4, step.path, 1),
|
||||
});
|
||||
var FS = fastbasic['FS'];
|
||||
populateFiles(step, FS);
|
||||
params.libargs = ['fastbasic-int.lib'];
|
||||
params.cfgfile = 'fastbasic-cart.cfg';
|
||||
//params.extra_compile_args = ["--asm-define", "NO_SMCODE"];
|
||||
params.extra_link_files = ['fastbasic-int.lib', 'fastbasic-cart.cfg'];
|
||||
//fixParamsWithDefines(step.path, params);
|
||||
var args = [step.path, destpath];
|
||||
execMain(step, fastbasic, args);
|
||||
if (errors.length)
|
||||
return {errors:errors};
|
||||
var asmout = FS.readFile(destpath, {encoding:'utf8'});
|
||||
putWorkFile(destpath, asmout);
|
||||
}
|
||||
return {
|
||||
nexttool:"ca65",
|
||||
path:destpath,
|
||||
args:[destpath],
|
||||
files:[destpath],
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
|
||||
var TOOLS = {
|
||||
@ -2644,6 +2681,7 @@ var TOOLS = {
|
||||
'js': runJavascript,
|
||||
'inform6': compileInform6,
|
||||
'merlin32': assembleMerlin32,
|
||||
'fastbasic': compileFastBasic,
|
||||
}
|
||||
|
||||
var TOOL_PRELOADFS = {
|
||||
@ -2664,6 +2702,7 @@ var TOOL_PRELOADFS = {
|
||||
'sccz80': 'sccz80',
|
||||
'bataribasic': '2600basic',
|
||||
'inform6': 'inform',
|
||||
'fastbasic': '65-atari8',
|
||||
}
|
||||
|
||||
function applyDefaultErrorPath(errors:WorkerError[], path:string) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user