Skip to content

Commit

Permalink
continue storage implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
y0014984 committed Dec 25, 2024
1 parent 459a796 commit 0664f34
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 33 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ https://y0014984.github.io/65-o-fun
- 64 colors (foreground and background)
- software and time-based hardware interrupts
- date and time registers
- Filesystem on Storage
- manual breakpoints
- More display modes (not yet)
- RAM banking (not yet)
Expand Down
17 changes: 13 additions & 4 deletions src/logic/Computer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,19 @@ export class Computer {

this.stor = new Storage(this.mem);

this.stor.fsObjects.push(new File([], 'lala', this.stringToByteArray('lala - This is the way of the water')));
this.stor.fsObjects.push(new File([], 'lulu and the lootersXXXX'));
this.stor.fsObjects.push(new Directory([], 'tmp'));
this.stor.fsObjects.push(new Program([], 'snake', 0x4000, this.stringToByteArray('010101010101')));
this.stor.fsObjects.push(new File(null, 'lala', this.stringToByteArray('lala - This is the way of the water')));
this.stor.fsObjects.push(new File(null, 'lulu and the lootersXXXX'));

const tmpDir = new Directory(null, 'tmp');
this.stor.fsObjects.push(tmpDir);

const lowerDir = new Directory(tmpDir, 'lower');
tmpDir.fsObjects.push(lowerDir);

const lowestDir = new Directory(lowerDir, 'lowest');
lowerDir.fsObjects.push(lowestDir);

this.stor.fsObjects.push(new Program(null, 'snake', 0x4000, this.stringToByteArray('010101010101')));
}

stringToByteArray(string: string) {
Expand Down
10 changes: 6 additions & 4 deletions src/logic/Graphics.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Font, Letter } from './Font';
import Memory from './Memory';

const fontStart = 0xf400;

interface Color {
r: number;
g: number;
Expand Down Expand Up @@ -53,13 +55,13 @@ export default class Graphics {
}

// check writing to font ram
if (index >= 0xd000 && index < 0xd000 + 256 * 8) {
const fontIndex = Math.floor((index - 0xd000) / 8);
if (index >= fontStart && index < fontStart + 256 * 8) {
const fontIndex = Math.floor((index - fontStart) / 8);
const letterCode = fontIndex.toString(16).toUpperCase().padStart(2, '0');

const letterBitmap = [];
for (let i = 0; i < 8; i++) {
const value = this.mem.int[0xd000 + fontIndex * 8 + i]
const value = this.mem.int[fontStart + fontIndex * 8 + i]
.toString(2)
.padStart(8, '0')
.split('')
Expand Down Expand Up @@ -97,7 +99,7 @@ export default class Graphics {
}

readLetterFromMem(letterCode: string) {
const fontIndex = 0xd000 + parseInt(letterCode, 16) * 8;
const fontIndex = fontStart + parseInt(letterCode, 16) * 8;

const letterBitmap = [];
for (let i = 0; i < 8; i++) {
Expand Down
4 changes: 3 additions & 1 deletion src/logic/Processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ export default class Processor {
let startTime = 0;
if (this.isWindowAvailable) startTime = window.performance.now();

if (!references.get(this.ir.getAsHexString())) console.log(`Instruction not found: ${this.ir.getAsHexString()}`);
if (!references.get(this.ir.getAsHexString())) {
console.log(
`Instruction not found: ${this.ir.getAsHexString()} PC: ${this.pc.int.toString(16).toUpperCase().padStart(4, '0')}`
);
// illegal opcode? or any other execution problem?
this.fetchInstruction();
return;
Expand Down
196 changes: 172 additions & 24 deletions src/logic/Storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,32 @@ const commandFlowReady = 0xe1;
const commandFlowInProgess = 0x99;
const commandFlowDone = 0x87;
const commandReturnValue = 0x021d;
const commandLastError = 0x021e;

const fsObjTypeFile = 0x99;
const fsObjTypeDirectory = 0xe1;
const fsObjTypeProgram = 0x87;

const returnValError = 0x00;
const returnValSuccess = 0xff;

const errorMissingParameter = 0x89;
const errorNoFileOrDir = 0xc1;
const errorNotDirectory = 0xa1;

export class Storage {
private mem: Memory;
type: 'ROOT' = 'ROOT';
fsObjects: FilesystemObject[];
currentDir: FilesystemObject[];
currentDirFsObjects: FilesystemObject[];
currentParentDir: Directory | null;

constructor(mem: Memory) {
this.mem = mem;

this.fsObjects = [];

this.currentDir = this.fsObjects;
this.currentDirFsObjects = this.fsObjects;
this.currentParentDir = null;
}

checkMemWrite(index: number) {
Expand All @@ -34,6 +48,7 @@ export class Storage {
for (let i = 0; i < commandLength; i++) {
command = command.concat(String.fromCharCode(this.mem.int[commandBufferAddress + i]));
}

console.log(`Storage command received: '${command}'`);

this.mem.setInt(registerCommandFlow, commandFlowInProgess);
Expand All @@ -51,6 +66,10 @@ export class Storage {
case 'GFN':
this.getFilesystemObjectName(command.substring(3, 4).charCodeAt(0));
break;
case 'GTD':
const param = this.getCommandStringParam(command, commandLength);
this.gotoDirectory(param);
break;
default:
break;
}
Expand All @@ -60,12 +79,141 @@ export class Storage {
}
}

getCommandStringParam(command: string, commandLength: number) {
let param = '';

for (let i = 3; i < commandLength; i++) {
const char = command[i];
if (char.charCodeAt(0) === 0x00) break;
param += char;
}

return param;
}

gotoDirectory(subDirName: string) {
subDirName.trim();

if (subDirName === '') {
this.mem.setInt(commandReturnValue, returnValError);
this.mem.setInt(commandLastError, errorMissingParameter);
return;
}

if (subDirName === '/') {
this.currentDirFsObjects = this.fsObjects;
this.currentParentDir = null;

this.mem.setInt(commandReturnValue, returnValSuccess);
return;
}

if (subDirName[0] === '/' && subDirName.length > 1) {
const path = subDirName.split('/');
path.shift();

let targetDir: Storage | FilesystemObject | undefined = this;

while (path.length > 0) {
if (targetDir.type === 'FILE' || targetDir.type === 'PROGRAM') break;

targetDir = (targetDir as Directory).fsObjects.find(fsObj => fsObj.name === path[0]);

if (!targetDir) break;

path.shift();
}

if (!targetDir) {
this.mem.setInt(commandReturnValue, returnValError);
this.mem.setInt(commandLastError, errorNoFileOrDir);
} else {
this.currentDirFsObjects = (targetDir as Directory).fsObjects;
this.currentParentDir = targetDir as Directory;

this.mem.setInt(commandReturnValue, returnValSuccess);
}
return;
}

if (subDirName[0] !== '/' && subDirName.length > 1 && subDirName.includes('/')) {
const path = subDirName.split('/');

let targetDir: Storage | FilesystemObject | undefined;
targetDir = this.currentParentDir as Directory;
if (this.currentParentDir === null) targetDir = this;

while (path.length > 0) {
if (targetDir.type === 'FILE' || targetDir.type === 'PROGRAM') break;

targetDir = (targetDir as Directory).fsObjects.find(fsObj => fsObj.name === path[0]);

if (!targetDir) break;

path.shift();
}

if (!targetDir) {
this.mem.setInt(commandReturnValue, returnValError);
this.mem.setInt(commandLastError, errorNoFileOrDir);
} else {
this.currentDirFsObjects = (targetDir as Directory).fsObjects;
this.currentParentDir = targetDir as Directory;

this.mem.setInt(commandReturnValue, returnValSuccess);
}
return;
}

if (subDirName === '..') {
if (this.currentParentDir !== null) {
const nextParentDir = this.currentParentDir.parentDir;
if (nextParentDir === null) {
this.currentDirFsObjects = this.fsObjects;
this.currentParentDir = null;
} else {
this.currentDirFsObjects = nextParentDir.fsObjects;
this.currentParentDir = nextParentDir;
}
}

this.mem.setInt(commandReturnValue, returnValSuccess);
return;
}

let subDir = this.currentDirFsObjects.find(fsObj => fsObj.name === subDirName);

if (!subDir) {
const subDirNumber = parseInt(subDirName);
if (!isNaN(subDirNumber) && subDirNumber >= 0 && subDirNumber <= this.currentDirFsObjects.length - 1) {
subDir = this.currentDirFsObjects[subDirNumber];
}
}

if (!subDir) {
this.mem.setInt(commandReturnValue, returnValError);
this.mem.setInt(commandLastError, errorNoFileOrDir);
return;
}

if (subDir.type !== 'DIRECTORY') {
this.mem.setInt(commandReturnValue, returnValError);
this.mem.setInt(commandLastError, errorNotDirectory);
return;
}

this.currentDirFsObjects = (subDir as Directory).fsObjects;
this.currentParentDir = subDir as Directory;

this.mem.setInt(commandReturnValue, returnValSuccess);
}

getFilesystemObjectsCount() {
this.mem.setInt(commandReturnValue, this.currentDir.length);
this.mem.setInt(commandReturnValue, this.currentDirFsObjects.length);
}

getFilesystemObjectName(index: number) {
const name = this.currentDir[index].name;
const name = this.currentDirFsObjects[index].name;

const readWriteBufferAddress = this.mem.int[registerReadWriteBuffer + 1] * 256 + this.mem.int[registerReadWriteBuffer];

Expand All @@ -76,15 +224,15 @@ export class Storage {

getFilesystemObjectType(index: number) {
let type;
switch (this.currentDir[index].type) {
switch (this.currentDirFsObjects[index].type) {
case 'FILE':
type = 0x99;
type = fsObjTypeFile;
break;
case 'DIRECTORY':
type = 0xe1;
type = fsObjTypeDirectory;
break;
case 'PROGRAM':
type = 0x87;
type = fsObjTypeProgram;
break;
default:
type = 0x00;
Expand All @@ -95,27 +243,27 @@ export class Storage {
this.mem.setInt(readWriteBufferAddress, type);

if (type === 0x00) {
this.mem.setInt(commandReturnValue, 0x00);
this.mem.setInt(commandReturnValue, returnValError);
} else {
this.mem.setInt(commandReturnValue, 0xff);
this.mem.setInt(commandReturnValue, returnValSuccess);
}
}

getFileSize(index: number) {
switch (this.currentDir[index].type) {
switch (this.currentDirFsObjects[index].type) {
case 'DIRECTORY':
this.mem.setInt(commandReturnValue, 0x00);
this.mem.setInt(commandReturnValue, returnValError);
break;
case 'FILE':
case 'PROGRAM':
const file = this.currentDir[index] as File;
const file = this.currentDirFsObjects[index] as File;
const size = file.content.length;

const readWriteBufferAddress = this.mem.int[registerReadWriteBuffer + 1] * 256 + this.mem.int[registerReadWriteBuffer];
this.mem.setInt(readWriteBufferAddress, size & 0x00ff);
this.mem.setInt(readWriteBufferAddress + 1, (size & 0xff00) >> 8);

this.mem.setInt(commandReturnValue, 0xff);
this.mem.setInt(commandReturnValue, returnValSuccess);
break;
default:
break;
Expand All @@ -124,14 +272,14 @@ export class Storage {
}

export class FilesystemObject {
path: string[];
parentDir: Directory | null;
name: string;
type: 'FILE' | 'DIRECTORY' | 'PROGRAM';
created: Date;
changed: Date;

constructor(path: string[], name: string, type: 'FILE' | 'DIRECTORY' | 'PROGRAM') {
this.path = path;
constructor(parentDir: Directory | null, name: string, type: 'FILE' | 'DIRECTORY' | 'PROGRAM') {
this.parentDir = parentDir;
this.name = name;
this.type = type;
this.created = new Date();
Expand All @@ -142,8 +290,8 @@ export class FilesystemObject {
export class File extends FilesystemObject {
content: number[] = [];

constructor(path: string[], name: string, content?: number[]) {
super(path, name, 'FILE');
constructor(parentDir: Directory | null, name: string, content?: number[]) {
super(parentDir, name, 'FILE');

if (content) this.content = content;
}
Expand All @@ -152,8 +300,8 @@ export class File extends FilesystemObject {
export class Directory extends FilesystemObject {
fsObjects: FilesystemObject[];

constructor(path: string[], name: string) {
super(path, name, 'DIRECTORY');
constructor(parentDir: Directory | null, name: string) {
super(parentDir, name, 'DIRECTORY');

this.fsObjects = [];
}
Expand All @@ -163,8 +311,8 @@ export class Program extends FilesystemObject {
loadAddress: number;
content: number[] = [];

constructor(path: string[], name: string, loadAddress: number, content?: number[]) {
super(path, name, 'PROGRAM');
constructor(parentDir: Directory | null, name: string, loadAddress: number, content?: number[]) {
super(parentDir, name, 'PROGRAM');

this.loadAddress = loadAddress;
if (content) this.content = content;
Expand Down

0 comments on commit 0664f34

Please sign in to comment.