atari8: fastbasic, only int-mode and builds carts right now

This commit is contained in:
Steven Hugg 2020-07-28 19:14:42 -05:00
parent b78fbe5ac4
commit b344590917
18 changed files with 915 additions and 3 deletions

View File

@ -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

View File

@ -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">&#x2190;&#x2191;&#x2193;&#x2192;</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>

View 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

View 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

View 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

View 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
View 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");
});

View File

@ -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', () => {

View File

@ -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, {

View 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;
}

Binary file not shown.

Binary file not shown.

View 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;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -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) {