1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2026-04-20 00:17:04 +00:00

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
+2
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
+3 -2
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>
+72
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
+265
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
+45
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
+26
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
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");
});
+2
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', () => {
+18 -1
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, {
@@ -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.
+60
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.
+39
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) {