Skip to content

Commit

Permalink
add fill to assembler
Browse files Browse the repository at this point in the history
  • Loading branch information
MESYETI committed Mar 30, 2024
1 parent bc16682 commit 554c469
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 132 deletions.
80 changes: 25 additions & 55 deletions source/app.d
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
module yeti16.app;

import std.utf;
import std.conv;
import std.file;
import std.range;
import std.stdio;
import std.string;
import std.algorithm;
import yeti16.util;
import yeti16.emulator;
import yeti16.assembler.lexer;
Expand All @@ -17,19 +14,12 @@ const string appUsage = "
Usage: %s OPERATION [flags]
Operations:
run FILE [read flags] - runs the given binary file in the emulator
asm FILE [read flags] - assembles the given file (to \"out.bin\" by default)
new_disk FILE SECTORS - creates a disk at FILE with SECTORS sectors
run FILE [read flags] - runs the given binary file in the emulator
asm FILE [-o out_file.bin] - assembles the given file (to \"out.bin\" by default)
Run flags:
--serial : Enables the serial port (port 4040)
--allow-ip <IP> : Adds an IP to the serial port whitelist
--disk <PATH> : Loads the given disk
--memdump <FILE> : On exit, YETI-16 writes the whole contents of memory to FILE
Asm flags:
-o <FILE> : Sets output binary file to FILE
--labels : Shows label offset addresses after compilation
--serial : Enables the serial port (port 4040)
--allow-ip <IP> : Adds an IP to the serial port whitelist
";

void main(string[] args) {
Expand All @@ -50,6 +40,27 @@ void main(string[] args) {
exit(1);
}

bool enableSerial;
string[] allowedIPs = ["127.0.0.1", "0.0.0.0"];

for (size_t i = 3; i < args.length; ++ i) {
switch (args[i]) {
case "--serial": {
enableSerial = true;
break;
}
case "--allow-ip": {
++ i;
allowedIPs ~= args[i];
break;
}
default: {
stderr.writefln("Unknown flag %s", args[i]);
exit(1);
}
}
}

auto emulator = new Emulator(args);
ubyte[] program;

Expand All @@ -70,7 +81,6 @@ void main(string[] args) {
case "asm": {
string file;
string outFile = "out.bin";
bool showLabels;

for (size_t i = 2; i < args.length; ++ i) {
if (args[i][0] == '-') {
Expand All @@ -81,10 +91,6 @@ void main(string[] args) {
// TODO: check
break;
}
case "--labels": {
showLabels = true;
break;
}
default: {
stderr.writefln("Unknown flag '%s'", args[i]);
exit(1);
Expand Down Expand Up @@ -120,7 +126,6 @@ void main(string[] args) {
lexer.code = code;
lexer.file = file;
lexer.Lex();

parser.tokens = lexer.tokens;
parser.Parse();

Expand All @@ -132,44 +137,9 @@ void main(string[] args) {
exit(1);
}

if (showLabels) {
size_t maxLength =
assembler.labels.keys().map!(a => a.length).maxElement();

foreach (key, ref value ; assembler.labels) {
writefln(
"%s%s = %.6X", key,
iota(maxLength - key.length).map!(a => ' '), value
);
}
}

std.file.write(outFile, assembler.bin);
break;
}
case "new_disk": {
if (args.length != 4) {
stderr.writeln("2 parameters (FILE, SECTORS) required for new_disk");
exit(1);
}
if (!args[3].isNumeric()) {
stderr.writeln("SECTORS parameter isn't numeric");
exit(1);
}

auto path = args[2];
auto sectors = parse!uint(args[3]);

auto file = File(path, "wb");

foreach (i ; 0 .. sectors) {
file.rawWrite(new ubyte[512]);
writef("\r[%d/%d] Writing sectors", i + 1, sectors);
stdout.flush();
}
writeln();
break;
}
default: {
stderr.writefln("Unknown operation '%s'", args[1]);
exit(1);
Expand Down
94 changes: 18 additions & 76 deletions source/assembler/assembler.d
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ module yeti16.assembler.assembler;

import std.stdio;
import std.format;
import std.string;
import std.algorithm;
import yeti16.util;
import yeti16.assembler.error;
Expand Down Expand Up @@ -424,11 +423,6 @@ class Assembler {
throw new AssemblerError();
}

void Warn(Char, A...)(ErrorInfo info, in Char[] fmt, A args) {
WarningBegin(info);
stderr.writeln(format(fmt, args));
}

uint GetDataSize(InstructionNode node) {
// no error checking, leave that until later
uint size;
Expand All @@ -440,8 +434,9 @@ class Assembler {
size += node2.value.length;
break;
}
case NodeType.Identifier:
case NodeType.Integer: {
auto node2 = cast(IntegerNode) param;

switch (node.name) {
case "db": size += 1; break;
case "dw": size += 2; break;
Expand All @@ -462,7 +457,7 @@ class Assembler {
switch (param.type) {
case NodeType.String: {
auto node2 = cast(StringNode) param;

if (node.name != "db") {
Error(node.error, "String literals are only allowed in db");
}
Expand All @@ -481,24 +476,6 @@ class Assembler {
}
break;
}
case NodeType.Identifier: {
auto node2 = cast(IdentifierNode) param;

if (node2.name in consts) {
auto value = consts[node2.name];

switch (node.name) {
case "db": bin ~= cast(ubyte) (value & 0xFF); break;
case "dw": bin ~= NativeToYeti!ushort(cast(ushort) value); break;
case "da": bin ~= AddrNativeToYeti(cast(uint) value); break;
default: assert(0);
}
}
else {
Error(node2.error, "Can't use this identifier here");
}
break;
}
default: assert(0);
}
}
Expand All @@ -507,27 +484,12 @@ class Assembler {
void Assemble() {
uint programSize;
string[] dataInstructions = ["db", "dw", "da"];
string lastLabel;

foreach (ref inode ; nodes) {
switch (inode.type) {
case NodeType.Label: {
auto node = cast(LabelNode) inode;
string labelName;

if (node.name[0] == '.') {
if (lastLabel.strip() == "") {
Warn(node.error, "Local label has no parent label");
}

labelName = format("%s%s", lastLabel, node.name);
}
else {
labelName = node.name;
lastLabel = labelName;
}

labels[labelName] = programSize;
auto node = cast(LabelNode) inode;
labels[node.name] = programSize;
break;
}
case NodeType.Instruction: {
Expand All @@ -549,50 +511,22 @@ class Assembler {
}
}

lastLabel = "";

foreach (ref inode ; nodes) {
switch (inode.type) {
case NodeType.Label: {
auto node = cast(LabelNode) inode;

if (node.name[0] != '.') {
lastLabel = node.name;
}
break;
}
case NodeType.Label: break;
case NodeType.Instruction: {
auto node = cast(InstructionNode) inode;
Node[] params;

string[] noLabelInsts = [
"wrb", "wrw", "wra", "rdb", "rdw", "rda", "jmp", "jz", "jnz",
"js", "jns", "jc", "jnc", "call"
];

foreach (ref param ; node.params) {
switch (param.type) {
case NodeType.Identifier: {
auto node2 = cast(IdentifierNode) param;
string labelName;
auto node2 = cast(IdentifierNode) param;

if (node2.name[0] == '.') {
labelName = format("%s%s", lastLabel, node2.name);
}
else {
labelName = node2.name;
}

if (labelName in labels) {
if (node2.name in labels) {
params ~= new IntegerNode(
param.error, labels[labelName]
param.error, labels[node2.name]
);
if (noLabelInsts.canFind(node.name)) {
Warn(
param.error,
"Label used in instruction that doesn't use BS"
);
}
}
else if (node2.name in consts) {
params ~= new IntegerNode(
Expand Down Expand Up @@ -636,10 +570,18 @@ class Assembler {
consts[node.name] = node.value;
break;
}
case NodeType.Fill: {
auto node = cast(FillNode) inode;

foreach (i ; 0 .. node.times) {
bin ~= cast(ubyte) node.value;
}
break;
}
default: {
Error(inode.error, "Unexpected %s node", inode.type);
}
}
}
}
}
}
34 changes: 33 additions & 1 deletion source/assembler/parser.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ enum NodeType {
String,
RegPair,
Identifier,
Define
Define,
Fill
}

class Node {
Expand Down Expand Up @@ -171,6 +172,20 @@ class DefineNode : Node {
}
}

class FillNode : Node {
uint times;
uint value;

this(ErrorInfo perror) {
type = NodeType.Fill;
error = perror;
}

override string toString() {
return format("fill %d %d", times, value);
}
}

class ParserError : Exception {
this() {
super("", "", 0);
Expand Down Expand Up @@ -272,12 +287,29 @@ class Parser {
return ret;
}

Node ParseFill() {
auto ret = new FillNode(GetError());

Next();
Expect(TokenType.Integer);
ret.times = parse!uint(tokens[i].contents);

Next();
Expect(TokenType.Integer);
ret.value = parse!uint(tokens[i].contents);

Next();
Expect(TokenType.End);
return ret;
}

Node ParseStatement() {
switch (tokens[i].type) {
case TokenType.Label: return ParseLabel();
case TokenType.Identifier: {
switch (tokens[i].contents) {
case "define": return ParseDefine();
case "fill": return ParseFill();
default: return ParseInstruction();
}
}
Expand Down
2 changes: 2 additions & 0 deletions tests/fill.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; 256 byte big file filled with zeros
fill 256 0

0 comments on commit 554c469

Please sign in to comment.