1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-02 12:41:30 +00:00

Compare commits

..

No commits in common. "d733a2cd273cf6e0d33c2f780e1e17e1da0c17e9" and "8023d56b883055e3f7b3132e453b51840c4830d2" have entirely different histories.

28 changed files with 95 additions and 2455 deletions

View File

@ -45,22 +45,20 @@ Note: Github tests may fail due to lack of API key.
## License
Copyright © 2016-2024 [Steven E. Hugg](https://github.com/sehugg).
Copyright © 2016-2022 [Steven Hugg](https://github.com/sehugg).
This project is [GPL-3.0](https://github.com/sehugg/8bitworkshop/blob/master/LICENSE) licensed.
This project, unless specifically noted, is multi-licensed.
You may choose to adhere to the terms of either the [GPL-3.0](https://github.com/sehugg/8bitworkshop/blob/master/LICENSE) License for the entire project or respect the individual licenses of its dependencies and included code samples, as applicable.
Dependencies retain their original licenses.
This project includes various dependencies, modules, and components that retain their original licenses.
For detailed licensing information for each dependency, please refer to the respective files and documentation.
All included code samples located in the presets/ directory are licensed under
All included code samples (all files under the presets/ directory) are licensed under
[CC0](https://creativecommons.org/publicdomain/zero/1.0/)
unless a different license is explicitly stated within the specific code sample.
unless otherwise licensed.
## Dependencies
The IDE uses custom forks for many of these, found at https://github.com/sehugg?tab=repositories
### Emulators
* https://javatari.org/
@ -86,7 +84,6 @@ unless a different license is explicitly stated within the specific code sample.
* https://github.com/wiz-lang/wiz
* https://github.com/sylefeb/Silice
* https://github.com/steux/cc7800
* https://bellard.org/tcc/
### Assemblers/Linkers
@ -115,8 +112,6 @@ unless a different license is explicitly stated within the specific code sample.
* https://github.com/sehugg/8bitworkshop-compilers
* https://github.com/sehugg/8bit-tools
* https://github.com/sehugg/awesome-8bitgamedev
* https://github.com/sehugg?tab=repositories
## Tool Server (experimental)

View File

@ -127,15 +127,13 @@ div.mem_info {
bottom: 10px;
background-color: #333;
color: #66ff66;
white-space: pre;
padding: 20px;
z-index: 12;
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
font-size: 12pt;
box-shadow: 0px 0px 8px rgba(0,0,0,.5);
}
div.mem_info_msg {
white-space: pre;
padding: 20px;
max-height: 80vh;
max-height: 90vh;
overflow-y: auto;
}
div.mem_info a {
@ -150,9 +148,6 @@ div.mem_info a:hover {
div.mem_info a.selected {
color: #ffffff;
}
div.mem_info button {
color: #fff;
}
.mem_info_links {
text-align:right;
}

View File

@ -378,8 +378,6 @@ body {
</div>
</div>
<div id="mem_info" class="mem_info" style="display:none">
<div><button type="button" class="close" onclick="$('.mem_info').hide()" aria-hidden="true">&times;</button></div>
<div id="mem_info_msg" class="mem_info_msg"></div>
</div>
<div id="error_alert" class="alert alert-danger alert-dismissable" style="position:absolute;right:0;top:0;display:none">
<button type="button" class="close" onclick="$('.alert').hide()" aria-hidden="true">&times;</button>

View File

@ -1,7 +0,0 @@
#define SERIAL_OUT ((int*)0x4000048)
void putchar_(char c) {
*SERIAL_OUT = c;
}

View File

@ -1,35 +0,0 @@
#include <string.h>
#include <stdio.h>
#define true 1
#define false 0
#define size 8190
#define sizepl 8191
//#link "serialout.c"
main() {
char flags[sizepl];
int i, prime, k, count, iter;
printf("Running benchmark...\n");
for (iter = 1; iter <= 10; iter ++) {
count=0;
for (i = 0; i <= size; i++)
flags[i] = true;
for (i = 0; i <= size; i++) {
if (flags[i]) {
prime = i + i + 3;
k = i + prime;
while (k <= size) {
flags[k] = false;
k += prime;
}
count = count + 1;
}
}
}
printf("Primes: %d\n", count);
return 0;
}

View File

@ -1,11 +0,0 @@
#include <string.h>
#include <stdio.h>
//#link "serialout.c"
int main() {
int x = 2024;
printf("Hello World! %d\n", x);
return 0;
}

View File

@ -1,25 +0,0 @@
const char const str[] = "HELLO WORLD!";
int global = 0x1234;
int global2 = 0x123456;
#define VIDBASE ((int*)0x4000080)
int vidbuf[160*128];
int main() {
*VIDBASE = (int)vidbuf;
global += str[0];
global++;
global2++;
int c = 0xff880000;
c += str[0];
int* p = (int*) vidbuf;
for (int i=0; i<160*128; i++) {
p[i] = c++;
}
return 0;
}

View File

@ -873,19 +873,15 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
advance(novideo:boolean) {
let trap = this.getDebugCallback();
try {
var steps = this.machine.advanceFrame(trap);
return steps;
} finally {
// in case EmuHalt is thrown...
if (!novideo && this.video) {
this.video.updateFrame();
this.updateVideoDebugger();
}
if (!novideo && this.serialVisualizer) {
this.serialVisualizer.refresh();
}
var steps = this.machine.advanceFrame(trap);
if (!novideo && this.video) {
this.video.updateFrame();
this.updateVideoDebugger();
}
if (!novideo && this.serialVisualizer) {
this.serialVisualizer.refresh();
}
return steps;
}
updateVideoDebugger() {

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
import { Bus, Bus32, CPU, InstructionBased, SavesState } from "../devices";
import { Bus, CPU, InstructionBased, SavesState } from "../devices";
import { EmuHalt } from "../emu";
import { hex } from "../util";
@ -103,18 +103,12 @@ export interface ARMCoreState {
bankedRegisters: number[][],
spsr: number,
bankedSPSRs: number[],
sfprs: number[],
dfprs: number[],
ifprs: number[],
cycles: number,
instructionWidth: 2 | 4
}
interface ARMCoreType {
gprs: Int32Array;
sfprs: Float32Array;
dfprs: Float64Array;
ifprs: Int32Array;
PC: number;
SP: number;
LR: number;
@ -665,11 +659,6 @@ ARMCoreArm.prototype.constructAddressingMode4Writeback = function(immediate, off
}
};
ARMCoreArm.prototype.constructNOP = function() {
this.writesPC = false;
return function() { };
}
ARMCoreArm.prototype.constructADC = function(rd, rn, shiftOp, condOp) {
var cpu : ARMCoreType = this.cpu;
var gprs = cpu.gprs;
@ -1771,265 +1760,6 @@ ARMCoreArm.prototype.constructUMULLS = function(rd, rn, rs, rm, condOp) {
};
};
ARMCoreArm.prototype.constructVFP3Register = function(condOp, opcode, nOperandReg, destReg, sz, opcode2, mOperandReg) {
var cpu : ARMCoreType = this.cpu;
var fpregs = sz ? cpu.dfprs : cpu.sfprs;
//console.log("VFP3Register: " + hex(opcode) + " " + hex(nOperandReg) + " " + hex(destReg) + " " + hex(number) + " " + hex(opcode2) + " " + hex(mOperandReg));
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
switch (opcode) {
case 2: // VMUL
switch (opcode2) {
case 0:
fpregs[destReg] = fpregs[nOperandReg] * fpregs[mOperandReg];
return;
}
break;
case 3: // VADD/VSUB
switch (opcode2) {
case 0:
fpregs[destReg] = fpregs[nOperandReg] + fpregs[mOperandReg];
return;
case 2:
fpregs[destReg] = fpregs[nOperandReg] - fpregs[mOperandReg];
return;
}
break;
case 8: // VDIV
switch (opcode2) {
case 0:
fpregs[destReg] = fpregs[nOperandReg] / fpregs[mOperandReg];
return;
}
break;
}
console.log("Unsupported instruction: " + hex(opcode) + " " + hex(opcode2));
};
};
/*
if ConditionPassed() then
EncodingSpecificOperations(); CheckVFPEnabled(TRUE);
if to_integer then
if dp_operation then
S[d] = FPToFixed(D[m], 32, 0, unsigned, round_zero, TRUE);
else
S[d] = FPToFixed(S[m], 32, 0, unsigned, round_zero, TRUE);
else
if dp_operation then
D[d] = FixedToFP(S[m], 64, 0, unsigned, round_nearest, TRUE);
else
S[d] = FixedToFP(S[m], 32, 0, unsigned, round_nearest, TRUE);
*/
ARMCoreArm.prototype.constructVCVT = function(condOp, d, m, to_integer, dp_operation, unsigned, round_zero, round_nearest) {
var cpu : ARMCoreType = this.cpu;
var sregs = cpu.sfprs;
var dregs = cpu.dfprs;
var iregs = cpu.ifprs;
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
var src : number;
var dest : number;
// get source
if (to_integer && dp_operation) {
src = dregs[m];
} else if (to_integer) {
src = sregs[m];
} else {
src = iregs[m];
}
// convert
if (to_integer) {
dest = round_zero ? Math.floor(src) : Math.round(src);
} else {
dest = src;
}
// store result
if (to_integer) {
iregs[d] = dest;
} else if (dp_operation) {
dregs[d] = dest;
} else {
sregs[d] = dest;
}
};
}
ARMCoreArm.prototype.constructVCVTF = function(condOp, d, m, double_to_single) {
var cpu : ARMCoreType = this.cpu;
var sregs = cpu.sfprs;
var dregs = cpu.dfprs;
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
var n = double_to_single ? dregs[m] : sregs[m];
// store result
if (double_to_single) {
sregs[d] = n;
} else {
dregs[d] = n;
}
};
}
ARMCoreArm.prototype.constructVLDR = function(condOp, destReg, address, single_reg) {
var cpu : ARMCoreType = this.cpu;
var iregs = cpu.ifprs;
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
let addr = address();
if (single_reg) {
iregs[destReg] = cpu.mmu.load32(addr);
} else {
iregs[destReg] = cpu.mmu.load32(addr);
iregs[destReg+1] = cpu.mmu.load32(addr+4);
}
cpu.mmu.wait32(addr);
cpu.mmu.wait32(cpu.gprs[ARMRegs.PC]);
};
};
ARMCoreArm.prototype.constructVSTR = function(condOp, srcReg, address, single_reg) {
var cpu : ARMCoreType = this.cpu;
var iregs = cpu.ifprs;
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
let addr = address();
if (single_reg) {
cpu.mmu.store32(addr, iregs[srcReg]);
} else {
cpu.mmu.store32(addr, iregs[srcReg]);
cpu.mmu.store32(addr+4, iregs[srcReg+1]);
}
cpu.mmu.wait32(addr);
cpu.mmu.wait32(cpu.gprs[ARMRegs.PC]);
};
}
ARMCoreArm.prototype.constructVPUSH = function(condOp, d, regs, single_regs) {
var cpu : ARMCoreType = this.cpu;
var iregs = cpu.ifprs;
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
let addr = cpu.gprs[ARMRegs.SP] - regs * 4;
cpu.gprs[ARMRegs.SP] = addr;
for (let i = 0; i < regs; ++i) {
cpu.mmu.store32(addr, iregs[d+i]);
addr += 4;
}
};
}
ARMCoreArm.prototype.constructVPOP = function(condOp, d, regs, single_regs) {
var cpu : ARMCoreType = this.cpu;
var iregs = cpu.ifprs;
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
let addr = cpu.gprs[ARMRegs.SP];
cpu.gprs[ARMRegs.SP] += regs * 4;
for (let i = 0; i < regs; ++i) {
iregs[d+i] = cpu.mmu.load32(addr);
addr += 4;
}
};
}
function FPCompare(op1: number, op2: number) {
/* assert N IN {32,64};
fpscr_val = if fpscr_controlled then FPSCR else StandardFPSCRValue();
(type1,sign1,value1) = FPUnpack(op1, fpscr_val);
(type2,sign2,value2) = FPUnpack(op2, fpscr_val); */
if (isNaN(op1) || isNaN(op2)) {
return 0b0011;
}
if (op1 == op2) return 0b0110;
if (op1 < op2) return 0b1000;
else return 0b0010;
}
ARMCoreArm.prototype.constructVCMP = function(condOp, d, Vd, sz, E, m, Vm) {
var cpu : ARMCoreType = this.cpu;
var sregs = cpu.sfprs;
var dregs = cpu.dfprs;
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
let op1, op2;
if (sz) {
op1 = dregs[d];
op2 = dregs[m];
} else {
op1 = sregs[d];
op2 = sregs[m];
}
let result = FPCompare(op1, op2);
cpu.cpsrN = (result & 8) != 0;
cpu.cpsrZ = (result & 4) != 0;
cpu.cpsrC = (result & 2) != 0;
cpu.cpsrV = (result & 1) != 0;
}
}
ARMCoreArm.prototype.constructVCMP0 = function(condOp, d, Vd, sz, E) {
var cpu : ARMCoreType = this.cpu;
var sregs = cpu.sfprs;
var dregs = cpu.dfprs;
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
let op1, op2=0;
if (sz) {
op1 = dregs[d];
} else {
op1 = sregs[d];
}
let result = FPCompare(op1, op2);
cpu.cpsrN = (result & 8) != 0;
cpu.cpsrZ = (result & 4) != 0;
cpu.cpsrC = (result & 2) != 0;
cpu.cpsrV = (result & 1) != 0;
}
}
ARMCoreArm.prototype.constructVMOV = function(condOp, to_arm_reg, n, t) {
var cpu : ARMCoreType = this.cpu;
return function() {
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
if (condOp && !condOp()) {
return;
}
if (to_arm_reg) {
cpu.gprs[t] = cpu.ifprs[n];
} else {
cpu.ifprs[n] = cpu.gprs[t];
}
}
}
///////////////////////////////////////////////////////////////////////////
function ARMCoreThumb(cpu) {
@ -2928,9 +2658,6 @@ function ARMCore() {
this.generateConds();
this.gprs = new Int32Array(16);
this.dfprs = new Float64Array(16);
this.sfprs = new Float32Array(this.dfprs.buffer); // regs shared with dfprs
this.ifprs = new Int32Array(this.dfprs.buffer); // regs shared with dfprs
};
ARMCore.prototype.resetCPU = function(startOffset) {
@ -2938,7 +2665,6 @@ ARMCore.prototype.resetCPU = function(startOffset) {
this.gprs[i] = 0;
}
this.gprs[ARMRegs.PC] = startOffset + ARMConstants.WORD_SIZE_ARM;
this.dfprs.set(0); // no need to zero the sfprs, since they share the same buffer
this.loadInstruction = this.loadInstructionArm;
this.execMode = ARMMode.MODE_ARM;
@ -3043,9 +2769,6 @@ ARMCore.prototype.freeze = function() : ARMCoreState {
this.gprs[14],
this.gprs[15],
],
'sfprs': this.sfprs.slice(),
'dfprs': this.dfprs.slice(),
'ifprs': this.ifprs.slice(),
'mode': this.mode,
'cpsrI': this.cpsrI,
'cpsrF': this.cpsrF,
@ -3127,8 +2850,6 @@ ARMCore.prototype.defrost = function(frost: ARMCoreState) {
this.gprs[14] = frost.gprs[14];
this.gprs[15] = frost.gprs[15];
this.ifprs.set(frost.ifprs); // regs shared with sfprs
this.mode = frost.mode;
this.cpsrI = frost.cpsrI;
this.cpsrF = frost.cpsrF;
@ -3817,11 +3538,6 @@ ARMCore.prototype.compileArm = function(instruction) {
var load = instruction & 0x00100000;
var b = instruction & 0x00400000;
var i = instruction & 0x02000000;
// test for UDF instruction
if ((instruction & 0xfff000f0) == (0xe7f000f0|0)) {
var immediate = instruction & 0x0000000f; // TODO: full range
throw new EmuHalt("Program exited (" + immediate + ")");
}
var address : AddressFunction = function() {
throw new EmuHalt("Unimplemented memory access: 0x" + instruction.toString(16));
@ -3951,68 +3667,6 @@ ARMCore.prototype.compileArm = function(instruction) {
break;
case 0x0C000000:
// Coprocessor data transfer
var load = instruction & 0x00100000;
var w = instruction & 0x00200000;
var user = instruction & 0x00400000;
var u = instruction & 0x00800000;
var p = instruction & 0x01000000;
var rn = (instruction & 0x000F0000) >> 16;
var crd = (instruction & 0x0000F000) >> 12;
var cpnum = (instruction & 0x00000F00) >> 8;
var immediate = instruction & 0x000000FF;
var cond = (instruction >> 28) & 0xf;
var condOp = this.conds[cond];
// VPUSH, VPOP
if ((instruction & 0x0fbf0f00) == 0x0d2d0a00) {
op = this.armCompiler.constructVPUSH(condOp, (crd<<1)|(user?1:0), immediate, true);
}
else if ((instruction & 0x0fbf0f00) == 0x0d2d0b00) {
op = this.armCompiler.constructVPUSH(condOp, ((user?16:0)|crd)*2, immediate, false);
}
else if ((instruction & 0x0fbf0f00) == 0x0cbd0a00) {
op = this.armCompiler.constructVPOP(condOp, (crd<<1)|(user?1:0), immediate, true);
}
else if ((instruction & 0x0fbf0f00) == 0x0cbd0b00) {
op = this.armCompiler.constructVPOP(condOp, ((user?16:0)|crd)*2, immediate, false);
}
// VLDR, VSTR
// https://developer.arm.com/documentation/ddi0406/c/Application-Level-Architecture/Instruction-Details/Alphabetical-list-of-instructions/VSTR?lang=en
else if ((instruction & 0x0f200f00) == 0x0d000a00) {
immediate *= 4;
if (!u) immediate = -immediate;
var overlap = false;
var d = (crd<<1)|(user?1:0);
var address : AddressFunction;
if (w) {
address = this.armCompiler.constructAddressingMode4Writeback(immediate, offset, rn, overlap);
} else {
address = this.armCompiler.constructAddressingMode4(immediate, rn);
}
if (load) {
op = this.armCompiler.constructVLDR(condOp, d, address, true);
} else {
op = this.armCompiler.constructVSTR(condOp, d, address, true);
}
} else if ((instruction & 0x0f200f00) == 0x0d000b00) {
immediate *= 4;
if (!u) immediate = -immediate;
var overlap = false;
var d = ((user?16:0)|crd)*2;
var address : AddressFunction;
if (w) {
address = this.armCompiler.constructAddressingMode4Writeback(immediate, offset, rn, overlap);
} else {
address = this.armCompiler.constructAddressingMode4(immediate, rn);
}
if (load) {
op = this.armCompiler.constructVLDR(condOp, d, address, false);
} else {
op = this.armCompiler.constructVSTR(condOp, d, address, false);
}
}
break;
case 0x0E000000:
// Coprocessor data operation/SWI
@ -4022,148 +3676,6 @@ ARMCore.prototype.compileArm = function(instruction) {
op = this.armCompiler.constructSWI(immediate, condOp);
op.writesPC = false;
}
// VCVT, VCVTR, VCVT
// https://developer.arm.com/documentation/ddi0406/c/Application-Level-Architecture/Instruction-Details/Alphabetical-list-of-instructions/VCVT--VCVTR--between-floating-point-and-integer--Floating-point-
/*
if opc2 != '000' && !(opc2 IN "10x") then SEE "Related encodings";
to_integer = (opc2<2> == '1'); dp_operation = (sz == 1);
if to_integer then
unsigned = (opc2<0> == '0'); round_zero = (op == '1');
d = UInt(Vd:D); m = if dp_operation then UInt(M:Vm) else UInt(Vm:M);
else
unsigned = (op == '0'); round_nearest = FALSE; // FALSE selects FPSCR rounding
m = UInt(Vm:M); d = if dp_operation then UInt(D:Vd) else UInt(Vd:D);
*/
else if ((instruction & 0x0FB80E50) == 0x0EB80A40) {
const cond = (instruction >> 28) & 0xf;
const D = (instruction >> 22) & 0x1;
const opc2 = (instruction >> 16) & 0x7;
const Vd = (instruction >> 12) & 0xf;
const sz = (instruction >> 8) & 0x1;
const op0 = (instruction >> 7) & 0x1;
const M = (instruction >> 5) & 0x1;
const Vm = instruction & 0xf;
const to_integer = opc2 & 0x4;
const dp_operation = sz != 0;
const unsigned = to_integer ? opc2 & 0x1 : 0;
const round_zero = op0 != 0;
const round_nearest = false;
const d = sz ? (D?16:0)|Vd : (Vd<<1)|(D?1:0);
const m = sz ? (M?16:0)|Vm : (Vm<<1)|(M?1:0);
//console.log("VCVT", d, m, opc2, to_integer, dp_operation, unsigned, round_zero, round_nearest);
op = this.armCompiler.constructVCVT(condOp, d, m, to_integer, dp_operation, unsigned, round_zero, round_nearest);
op.writesPC = false;
}
// VCVT f64/f32
else if ((instruction & 0x0FBF0ED0) == 0x0EB70AC0) {
const cond = (instruction >> 28) & 0xf;
const D = (instruction >> 22) & 0x1;
const Vd = (instruction >> 12) & 0xf;
const sz = (instruction >> 8) & 0x1;
const M = (instruction >> 5) & 0x1;
const Vm = instruction & 0xf;
const double_to_single = sz != 0;
const d = sz ? (D?16:0)|Vd : (Vd<<1)|(D?1:0);
const m = sz ? (M?16:0)|Vm : (Vm<<1)|(M?1:0);
op = this.armCompiler.constructVCVTF(condOp, d, m, double_to_single);
op.writesPC = false;
}
// 3-op floating point vector instructions (VADD, etc)
else if ((instruction & 0x0FA00E10) == 0x0E200A00) {
const cond = (instruction >> 28) & 0xf;
const D = (instruction >> 22) & 0x1;
const N = (instruction >> 7) & 0x1;
const M = (instruction >> 5) & 0x1;
const opcode = (instruction & 0x0F00000) >> 20;
const Vn = (instruction & 0x000F0000) >> 16;
const Vd = (instruction & 0x0000F000) >> 12;
const opcode2 = (instruction & 0b11100000) >> 5;
const Vm = instruction & 0x0000000F;
const sz = (instruction >> 8) & 0x1;
const d = sz ? (D?16:0)|Vd : (Vd<<1)|(D?1:0);
const m = sz ? (M?16:0)|Vm : (Vm<<1)|(M?1:0);
const n = sz ? (N?16:0)|Vn : (Vn<<1)|(N?1:0);
var condOp = this.conds[cond];
op = this.armCompiler.constructVFP3Register(condOp, opcode, n, d, sz, opcode2, m);
op.writesPC = false;
}
// VDIV - https://developer.arm.com/documentation/ddi0597/2023-12/SIMD-FP-Instructions/VDIV--Divide-?lang=en
else if ((instruction & 0x0FB00C50) == 0x0E800800) {
const cond = (instruction >> 28) & 0xf;
const D = (instruction >> 22) & 0x1;
const Vn = (instruction >> 16) & 0xf;
const Vd = (instruction >> 12) & 0xf;
const size = (instruction >> 8) & 0x3;
const N = (instruction >> 7) & 0x1;
const M = (instruction >> 5) & 0x1;
const Vm = instruction & 0xf;
/*
case size of
when '01' esize = 16; d = UInt(Vd:D); n = UInt(Vn:N); m = UInt(Vm:M);
when '10' esize = 32; d = UInt(Vd:D); n = UInt(Vn:N); m = UInt(Vm:M);
when '11' esize = 64; d = UInt(D:Vd); n = UInt(N:Vn); m = UInt(M:Vm);
*/
const d = size==3 ? (D?16:0)|Vd : (Vd<<1)|(D?1:0);
const m = size==3 ? (M?16:0)|Vm : (Vm<<1)|(M?1:0);
const n = size==3 ? (N?16:0)|Vn : (Vn<<1)|(N?1:0);
op = this.armCompiler.constructVFP3Register(condOp, 8, n, d, size==3, 0, m);
op.writesPC = false;
}
// 2-op floating point vector instructions (VCMP, etc)
else if ((instruction & 0x0FBF0E50) == 0x0EB40A40) {
const cond = (instruction >> 28) & 0xf;
const D = (instruction >> 22) & 0x1;
const Vd = (instruction >> 12) & 0xf;
const sz = (instruction >> 8) & 0x1;
const E = (instruction >> 7) & 0x1;
const M = (instruction >> 5) & 0x1;
const Vm = instruction & 0x0000000F;
const d = sz ? (D?16:0)|Vd : (Vd<<1)|(D?1:0);
const m = sz ? (M?16:0)|Vm : (Vm<<1)|(M?1:0);
var condOp = this.conds[cond];
op = this.armCompiler.constructVCMP(condOp, d, Vd, sz, E, m, Vm);
op.writesPC = false;
}
// VCMP #0
else if ((instruction & 0x0FBF0EFF) == 0x0EB50A40) {
const cond = (instruction >> 28) & 0xf;
const D = (instruction >> 22) & 0x1;
const Vd = (instruction >> 12) & 0xf;
const sz = (instruction >> 8) & 0x1;
const E = (instruction >> 7) & 0x1;
const M = (instruction >> 5) & 0x1;
const Vm = instruction & 0x0000000F;
const d = sz ? (D?16:0)|Vd : (Vd<<1)|(D?1:0);
const m = sz ? (M?16:0)|Vm : (Vm<<1)|(M?1:0);
var condOp = this.conds[cond];
op = this.armCompiler.constructVCMP0(condOp, d, Vd, sz, E, m, Vm);
op.writesPC = false;
}
// vmrs apsr_nzcv, fpscr (ignore, we always call this after CMP)
else if (instruction == 0xeef1fa10) {
op = this.armCompiler.constructNOP();
}
// VMOV - https://developer.arm.com/documentation/ddi0406/c/Application-Level-Architecture/Instruction-Details/Alphabetical-list-of-instructions/VMOV--between-ARM-core-register-and-single-precision-register-
else if ((instruction & 0x0FE00F10) == 0x0E000A10) {
const cond = (instruction >> 28) & 0xf;
const opc1 = (instruction >> 20) & 0x1;
const Vn = (instruction >> 16) & 0xf;
const Rt = (instruction >> 12) & 0xf;
const N = (instruction >> 7) & 0x1;
var condOp = this.conds[cond];
//console.log("VMOV", instruction.toString(16), opc1, Vn, Rt, N);
op = this.armCompiler.constructVMOV(condOp, opc1, (Vn<<1)|(N?1:0), Rt);
}
// vmov.32 dn[i], rn
else if (instruction == 0xee000b10) {
op = this.armCompiler.constructVMOV(condOp, false, 0, 0);
}
else if (instruction == 0xee201b10) {
op = this.armCompiler.constructVMOV(condOp, false, 1, 1);
}
break;
default:
throw new EmuHalt('Bad opcode: 0x' + instruction.toString(16));
@ -4591,16 +4103,11 @@ ARMCore.prototype.compileThumb = function(instruction) {
///////////////////////////////////////////////////////////////////////////
type ARMBus = Bus & Bus32;
export class ARM32CPU implements CPU, InstructionBased, ARMMMUInterface, ARMIRQInterface, SavesState<ARMCoreState> {
core : ARMCoreType;
bus : ARMBus;
bus : Bus;
memory : ARMMemoryRegion[];
f64arr = new Float64Array(1);
f32arr = new Float32Array(this.f64arr.buffer);
i32arr = new Int32Array(this.f64arr.buffer);
BASE_OFFSET = 24;
OFFSET_MASK = 0x00FFFFFF;
@ -4615,7 +4122,8 @@ export class ARM32CPU implements CPU, InstructionBased, ARMMMUInterface, ARMIRQI
this.memory = []; // TODO
for (var i=0; i<256; i++) {
// TODO: constant
const bits = 10;
var bits = 10;
var size = 0x80000;
this.memory[i] = {
PAGE_MASK: (2 << bits) - 1,
ICACHE_PAGE_BITS: bits,
@ -4638,13 +4146,12 @@ export class ARM32CPU implements CPU, InstructionBased, ARMMMUInterface, ARMIRQI
isStable(): boolean {
return true; // TODO?
}
connectMemoryBus(bus: ARMBus): void {
connectMemoryBus(bus: Bus): void {
this.bus = bus;
}
reset(): void {
this.resetMemory();
const resetVector = this.load32(0);
this.core.resetCPU(resetVector);
this.core.resetCPU(0);
}
saveState() : ARMCoreState {
return this.core.freeze();
@ -4666,7 +4173,7 @@ export class ARM32CPU implements CPU, InstructionBased, ARMMMUInterface, ARMIRQI
return this.bus.read(a) | (this.bus.read(a+1) << 8);
}
load32(a: number): number {
var v = this.bus.read32(a);
var v = this.bus.read(a) | (this.bus.read(a+1) << 8) | (this.bus.read(a+2) << 16) | (this.bus.read(a+3) << 24);
return v;
}
// TODO: memory.invalidatePage(maskedOffset);
@ -4678,7 +4185,10 @@ export class ARM32CPU implements CPU, InstructionBased, ARMMMUInterface, ARMIRQI
this.bus.write(a+1, (v >> 8) & 0xff);
}
store32(a: number, v: number): void {
this.bus.write32(a, v);
this.bus.write(a, v & 0xff);
this.bus.write(a+1, (v >> 8) & 0xff);
this.bus.write(a+2, (v >> 16) & 0xff);
this.bus.write(a+3, (v >> 24) & 0xff);
}
// TODO
wait(a: number): void {
@ -4743,10 +4253,4 @@ export class ARM32CPU implements CPU, InstructionBased, ARMMMUInterface, ARMIRQI
isThumb() : boolean {
return this.core.instructionWidth == 2;
}
getDebugTree() {
return {
state: this.saveState(),
mmu: this.core.mmu
};
}
}

View File

@ -10,12 +10,6 @@ export interface Bus {
readConst?(a: number): number;
}
export interface Bus32 {
read32(a: number): number;
write32(a: number, v: number): void;
readConst32?(a: number): number;
}
export interface ClockBased {
advanceClock(): void;
}
@ -282,7 +276,7 @@ export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, P
this.probe.logClocks(n);
return n;
}
probeMemoryBus(membus: Bus & Partial<Bus32>): Bus & Partial<Bus32> {
probeMemoryBus(membus: Bus): Bus {
return {
read: (a) => {
let val = membus.read(a);
@ -292,20 +286,11 @@ export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, P
write: (a, v) => {
this.probe.logWrite(a, v);
membus.write(a, v);
},
read32: (a) => {
let val = membus.read32(a);
this.probe.logRead(a, val);
return val;
},
write32: (a, v) => {
this.probe.logWrite(a, v);
membus.write32(a, v);
}
};
}
connectCPUMemoryBus(membus: Bus): void {
this.cpu.connectMemoryBus(this.probeMemoryBus(membus as Bus&Bus32));
this.cpu.connectMemoryBus(this.probeMemoryBus(membus));
}
probeIOBus(iobus: Bus): Bus {
return {
@ -317,7 +302,7 @@ export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, P
write: (a, v) => {
this.probe.logIOWrite(a, v);
iobus.write(a, v);
},
}
};
}
probeDMABus(iobus: Bus): Bus {

View File

@ -658,7 +658,7 @@ export function padBytes(data:Uint8Array|number[], len:number, padstart?:boolean
type AddressReadWriteFn = ((a:number) => number) | ((a:number,v:number) => void);
type AddressDecoderEntry = [number, number, number, AddressReadWriteFn];
type AddressDecoderOptions = {gmask?:number, defaultval?:number};
type AddressDecoderOptions = {gmask?:number};
// TODO: better performance, check values
export function AddressDecoder(table : AddressDecoderEntry[], options?:AddressDecoderOptions) {
@ -679,7 +679,7 @@ export function AddressDecoder(table : AddressDecoderEntry[], options?:AddressDe
if (mask) s += "a&="+mask+";";
s += "return this.__fn"+i+"(a,v)&0xff;}\n";
}
s += "return "+(options?.defaultval|0)+";";
s += "return 0;"; // TODO: noise()?
return new Function('a', 'v', s);
}
return makeFunction().bind(self);

View File

@ -1,24 +1,3 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// https://dev.to/ndesmic/building-a-minimal-wasi-polyfill-for-browsers-4nel
// http://www.wasmtutor.com/webassembly-barebones-wasi
@ -175,7 +154,7 @@ export enum WASIErrors {
export class WASIFileDescriptor {
fdindex: number = -1;
protected data: Uint8Array = new Uint8Array(16);
data: Uint8Array = new Uint8Array(16);
flags: number = 0;
size: number = 0;
offset: number = 0;
@ -245,8 +224,6 @@ class WASIStreamingFileDescriptor extends WASIFileDescriptor {
export interface WASIFilesystem {
getFile(name: string) : WASIFileDescriptor;
getFiles() : WASIFileDescriptor[];
getDirectories() : WASIFileDescriptor[];
}
export class WASIMemoryFilesystem implements WASIFilesystem {
@ -262,13 +239,6 @@ export class WASIMemoryFilesystem implements WASIFilesystem {
}
putDirectory(name: string, rights?: number) {
if (!rights) rights = FDRights.PATH_OPEN | FDRights.PATH_CREATE_DIRECTORY | FDRights.PATH_CREATE_FILE;
if (name != '/' && name.endsWith('/')) name = name.substring(0, name.length - 1);
// add parent directory(s)
const parent = name.substring(0, name.lastIndexOf('/'));
if (parent && parent != name) {
this.putDirectory(parent, rights);
}
// add directory
const dir = new WASIFileDescriptor(name, FDType.DIRECTORY, rights);
this.dirs.set(name, dir);
return dir;
@ -291,12 +261,6 @@ export class WASIMemoryFilesystem implements WASIFilesystem {
}
return file;
}
getDirectories() {
return [...this.dirs.values()];
}
getFiles() {
return [...this.files.values()];
}
}
export class WASIRunner {

View File

@ -274,8 +274,7 @@ export class CodeProject {
var depfiles = [];
msg.updates.push({path:mainfilename, data:maintext});
this.filename2path[mainfilename] = this.mainPath;
const tool = this.getToolForFilename(this.mainPath);
let usesRemoteTool = tool.startsWith('remote:');
let usesRemoteTool = this.getToolForFilename(mainfilename).startsWith('remote:');
for (var dep of depends) {
// remote tools send both includes and linked files in one build step
if (!dep.link || usesRemoteTool) {

View File

@ -136,7 +136,6 @@ const TOOL_TO_SOURCE_STYLE = {
'ecs': 'ecs',
'remote:llvm-mos': 'text/x-csrc',
'cc7800': 'text/x-csrc',
'armtcc': 'text/x-csrc',
}
// TODO: move into tool class
@ -909,15 +908,13 @@ function hideDebugInfo() {
function showDebugInfo(state?) {
if (!isDebuggable(platform)) return;
var meminfo = $("#mem_info");
var meminfomsg = $("#mem_info_msg");
var allcats = platform.getDebugCategories();
if (allcats && !debugCategory)
debugCategory = allcats[0];
var s = state && platform.getDebugInfo(debugCategory, state);
if (typeof s === 'string') {
if (s) {
var hs = lastDebugInfo ? highlightDifferences(lastDebugInfo, s) : s;
meminfo.show();
meminfomsg.html(hs);
meminfo.show().html(hs);
var catspan = $('<div class="mem_info_links">');
var addCategoryLink = (cat:string) => {
var catlink = $('<a>'+cat+'</a>');
@ -934,8 +931,8 @@ function showDebugInfo(state?) {
for (var cat of allcats) {
addCategoryLink(cat);
}
meminfomsg.append('<br>');
meminfomsg.append(catspan);
meminfo.append('<br>');
meminfo.append(catspan);
lastDebugInfo = s;
} else {
hideDebugInfo();

View File

@ -23,8 +23,7 @@ export class MemoryView implements ProjectView {
dumplines;
maindiv : HTMLElement;
recreateOnResize = true;
hibits = 0; // a hack to make it work with 32-bit addresses
totalRows = 0x1400; // a little more room in case we split lots of lines
totalRows = 0x1400;
createDiv(parent : HTMLElement) {
var div = document.createElement('div');
@ -45,7 +44,7 @@ export class MemoryView implements ProjectView {
var linediv = document.createElement("div");
if (this.dumplines) {
var dlr = this.dumplines[row];
if (dlr) linediv.classList.add('seg_' + this.getMemorySegment(this.dumplines[row].a | this.hibits));
if (dlr) linediv.classList.add('seg_' + this.getMemorySegment(this.dumplines[row].a));
}
linediv.appendChild(document.createTextNode(s));
return linediv;
@ -60,8 +59,7 @@ export class MemoryView implements ProjectView {
scrollToAddress(addr : number) {
if (this.dumplines) {
this.hibits = addr & 0xffff0000;
this.memorylist.scrollToItem(this.findMemoryWindowLine(addr & 0xffff));
this.memorylist.scrollToItem(this.findMemoryWindowLine(addr));
}
}
@ -103,7 +101,7 @@ export class MemoryView implements ProjectView {
for (var i=0; i<n1; i++) s += ' ';
if (n1 > 8) s += ' ';
for (var i=n1; i<n2; i++) {
var read = this.readAddress((offset+i) | this.hibits);
var read = this.readAddress(offset+i);
if (i==8) s += ' ';
s += ' ' + (typeof read == 'number' ? hex(read,2) : '??');
}
@ -132,7 +130,7 @@ export class MemoryView implements ProjectView {
var sym;
for (const _nextofs of Object.keys(addr2sym)) {
var nextofs = parseInt(_nextofs); // convert from string (stupid JS)
var nextsym = addr2sym[nextofs | this.hibits];
var nextsym = addr2sym[nextofs];
if (sym) {
// ignore certain symbols
if (ignoreSymbol(sym)) {

View File

@ -1,27 +1,6 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { ARM32CPU, ARMCoreState } from "../common/cpu/ARM";
import { BasicScanlineMachine, Bus32, HasSerialIO, SerialEvent, SerialIOInterface } from "../common/devices";
import { BasicScanlineMachine, HasSerialIO, SerialEvent, SerialIOInterface } from "../common/devices";
import { newAddressDecoder, Keys, makeKeycodeMap, newKeyboardHandler, EmuHalt } from "../common/emu";
import { Debuggable, EmuState } from "../common/baseplatform";
import { hex, lpad } from "../common/util";
@ -39,41 +18,36 @@ var GBA_KEYCODE_MAP = makeKeycodeMap([
[Keys.DOWN, 0, 0x80],
]);
const RAM_START = 0x0;
const RAM_SIZE = 0x100000;
const ROM_BASE = 0x0;
const ROM_START = 0x0;
const ROM_SIZE = 0x80000;
const RAM_START = 0x2000000;
const RAM_SIZE = 0x80000;
const IO_START = 0x4000000;
const IO_SIZE = 0x100;
const MAX_SERIAL_CHARS = 1000000;
const CPU_FREQ = 4000000; // 4 MHz
const ILLEGAL_OPCODE = 0xedededed;
export class ARM32Machine extends BasicScanlineMachine
implements Debuggable, HasSerialIO, Bus32 {
export class ARM32Machine extends BasicScanlineMachine implements Debuggable, HasSerialIO {
cpuFrequency = CPU_FREQ; // MHz
canvasWidth = 160;
numTotalScanlines = 256;
numVisibleScanlines = 128;
cpuCyclesPerLine = Math.floor(CPU_FREQ / (256*60));
defaultROMSize = RAM_SIZE - ROM_BASE;
defaultROMSize = 512*1024;
sampleRate = 1;
cpu: ARM32CPU = new ARM32CPU();
ram = new Uint8Array(RAM_SIZE);
ram = new Uint8Array(96*1024);
ram16 = new Uint16Array(this.ram.buffer);
ram32 = new Uint32Array(this.ram.buffer);
pixels32 : Uint32Array;
pixels8 : Uint8Array;
rombase : number = ROM_BASE;
vidbase : number = 0;
brightness : number = 255;
serial : SerialIOInterface;
serialOut : SerialEvent[];
serialIn : SerialEvent[];
ioregs = new Uint8Array(IO_SIZE);
ioregs32 = new Uint32Array(this.ioregs.buffer);
constructor() {
super();
@ -91,15 +65,7 @@ export class ARM32Machine extends BasicScanlineMachine
this.serial = serial;
}
loadROM(rom: Uint8Array) {
super.loadROM(rom);
}
reset() {
this.ram.fill(0);
if (this.rom) {
this.ram.set(this.rom, this.rombase);
}
super.reset();
this.serialOut = [];
this.serialIn = [];
@ -108,13 +74,19 @@ export class ARM32Machine extends BasicScanlineMachine
// TODO: 32-bit bus?
read = newAddressDecoder([
[ROM_START, ROM_START+ROM_SIZE-1, ROM_SIZE-1, (a) => {
return this.rom ? this.rom[a] : 0;
}],
[RAM_START, RAM_START+RAM_SIZE-1, RAM_SIZE-1, (a) => {
return this.ram[a];
}],
[IO_START, IO_START+IO_SIZE-1, IO_SIZE-1, (a, v) => {
return this.readIO(a);
}],
], {defaultval: ILLEGAL_OPCODE & 0xff});
[0, (1<<31)-1, 0, (a, v) => {
throw new EmuHalt(`Address read out of bounds: 0x${hex(a)}`);
}]
]);
write = newAddressDecoder([
[RAM_START, RAM_START+RAM_SIZE-1, RAM_SIZE-1, (a, v) => {
@ -125,42 +97,10 @@ export class ARM32Machine extends BasicScanlineMachine
}],
]);
read32 = (a) => {
if (a >= RAM_START && a < RAM_SIZE && (a & 3) == 0) {
return this.ram32[a >> 2];
} else {
return this.read(a) | (this.read(a+1)<<8) | (this.read(a+2)<<16) | (this.read(a+3)<<24);
}
};
write32 = (a, v) => {
if (a >= RAM_START && a < RAM_SIZE && (a & 3) == 0) {
this.ram32[a >> 2] = v;
} else {
this.write(a, v & 0xff);
this.write(a+1, (v>>8) & 0xff);
this.write(a+2, (v>>16) & 0xff);
this.write(a+3, (v>>24) & 0xff);
}
}
readAddress(a : number) : number {
if (a >= RAM_START && a < RAM_START+RAM_SIZE) return this.read(a);
else return ILLEGAL_OPCODE;
}
readIO(a : number) : number {
switch (a) {
case 0x0:
return this.inputs[0];
case 0x20:
return this.getRasterY() & 0xff;
case 0x21:
return this.getRasterY() >> 8;
case 0x24:
return this.getRasterX();
case 0x25:
return this.getRasterX() >> 8;
case 0x40:
return (this.serial.byteAvailable() ? 0x80 : 0) | (this.serial.clearToSend() ? 0x40 : 0);
case 0x44:
@ -176,14 +116,16 @@ export class ARM32Machine extends BasicScanlineMachine
}
writeIO(a : number, v : number) : void {
this.ioregs[a] = v;
switch (a) {
case 0x0:
//this.brightness = v & 0xff;
break;
case 0x48:
if (this.serialOut.length < MAX_SERIAL_CHARS) {
this.serialOut.push({op:'write', value:v, nbits:8});
}
break;
}
}
}
startScanline() {
@ -194,8 +136,7 @@ export class ARM32Machine extends BasicScanlineMachine
postFrame() {
var p32 = this.pixels32;
const vidbase = this.ioregs32[0x80 >> 2];
var vbase = (vidbase >> 1) & 0xfffff;
var vbase = (this.vidbase >> 1) & 0xfffff;
var mask = this.brightness << 24;
for (var i=0; i<p32.length; i++) {
var col = this.ram16[i + vbase];
@ -206,34 +147,18 @@ export class ARM32Machine extends BasicScanlineMachine
}
getDebugCategories() {
return ['CPU', 'Stack', 'FPU'];
return ['CPU', 'Stack'];
}
getDebugInfo?(category: string, state: EmuState) : string {
switch (category) {
case 'Stack':
var s = '';
var c = state.c as ARMCoreState;
var sp = c.gprs[13];
var fp = c.gprs[11];
// dump stack using ram32
for (var i=0; i<16; i++) {
s += hex(sp,8) + ' ' + hex(this.ram32[(sp-RAM_START)>>2],8);
if (sp == fp) s += ' FP';
s += '\n';
sp += 4;
if (sp >= RAM_START+RAM_SIZE) break;
}
return s;
case 'CPU':
var s = '';
var c = state.c as ARMCoreState;
const EXEC_MODE = {2:'Thumb',4:'ARM'};
const REGNAMES = {15:'PC',14:'LR',13:'SP',12:'IP',11:'FP',9:'SB'};
for (var i=0; i<8; i++) {
let j = i+8;
s += lpad('r'+i, 5) + ' ' + hex(c.gprs[i],8) + ' ';
s += lpad('r'+j, 5) + ' ' + hex(c.gprs[j],8) + lpad(REGNAMES[j]||'',3) + '\n';
for (var i=0; i<16; i++) {
s += lpad(REGNAMES[i]||'',3) + lpad('r'+i, 5) + ' ' + hex(c.gprs[i],8) + '\n';
}
s += 'Flags ';
s += c.cpsrN ? " N" : " -";
@ -247,19 +172,6 @@ export class ARM32Machine extends BasicScanlineMachine
s += 'SPSR ' + hex(c.spsr,8) + '\n';
s += 'cycl ' + c.cycles + '\n';
return s;
case 'FPU':
var s = '';
var c = state.c as ARMCoreState;
for (var i=0; i<16; i++) {
//let j = i+16;
s += lpad('s'+i, 5) + ' ' + hex(c.ifprs[i],8) + ' ' + c.sfprs[i].toPrecision(6);
if (i & 1) {
s += lpad('d'+(i>>1), 5) + ' ' + c.dfprs[i>>1].toPrecision(12);
}
s += '\n';
//s += lpad('s'+j, 5) + ' ' + lpad(c.sfprs[j]+'',8) + '\n';
}
return s;
}
}

View File

@ -1,49 +1,40 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { Platform, DisasmLine, Machine, BaseMachinePlatform } from "../common/baseplatform";
import { PLATFORMS } from "../common/emu";
import { loadScript } from "../common/util";
import { BaseDebugPlatform, CpuState, EmuState, Platform, DisasmLine, Debuggable, Machine, BaseMachinePlatform } from "../common/baseplatform";
import { AnimationTimer, EmuHalt, padBytes, PLATFORMS, RasterVideo } from "../common/emu";
import { hex, lpad, loadScript } from "../common/util";
import { ARM32CPU } from "../common/cpu/ARM";
import { ARM32Machine } from "../machine/arm32";
declare var cs : any; // Unicorn module
declare var uc, cs : any; // Unicorn module
const ARM32_PRESETS = [
{ id: 'vidfill.c', name: 'Video Memory Fill' },
{ id: 'vidfill.vasm', name: 'Video Memory Fill' },
];
const SCREEN_WIDTH = 160;
const SCREEN_HEIGHT = 128;
const ROM_START_ADDR = 0x0;
const HIROM_START_ADDR = 0xff800000;
const ROM_SIZE = 512*1024;
const RAM_START_ADDR = 0x20000000;
const RAM_SIZE = 512*1024;
const CLOCKS_PER_FRAME = 10000;
interface ARM32State extends EmuState {
r: Uint32Array; // registers
}
export abstract class BaseARMMachinePlatform<T extends Machine> extends BaseMachinePlatform<T> {
//getOpcodeMetadata = getOpcodeMetadata_z80;
getToolForFilename(fn: string) {
fn = fn.toLowerCase();
if (fn.endsWith('.vasm')) return "vasmarm";
if (fn.endsWith('.armips')) return "armips";
if (fn.endsWith('.c')) return "armtcc";
if (fn.endsWith('.s')) return "armtcc";
return "armtcc";
else if (fn.endsWith('.armips')) return "armips";
else return "vasmarm";
}
getPresets() { return ARM32_PRESETS; }
getDefaultExtension() { return ".c"; };
getDefaultExtension() { return ".vasm"; };
}
class ARM32Platform extends BaseARMMachinePlatform<ARM32Machine> implements Platform {
@ -62,16 +53,10 @@ class ARM32Platform extends BaseARMMachinePlatform<ARM32Machine> implements Plat
newMachine() { return new ARM32Machine(); }
readAddress(a) { return this.machine.read(a); }
getMemoryMap = function() { return { main:[
{name:'ROM',start:0x0000000,size:0x100000,type:'ram'},
{name:'ROM',start:0x0000000,size:0x80000,type:'rom'},
{name:'RAM',start:0x2000000,size:0x80000,type:'ram'},
{name:'I/O',start:0x4000000,size:0x100,type:'io'},
] } };
getPlatformName() { return "ARM7"; }
getDebugTree() {
return {
...this.machine.cpu.getDebugTree(),
dwarf: this.debugSymbols.debuginfo
}
}
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
var is_thumb = this.machine.cpu.isThumb();
var capstone = is_thumb ? this.capstone_thumb : this.capstone_arm;

View File

@ -1,63 +0,0 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import assert from "assert";
import { DWARFParser, ELFParser } from "../common/binutils";
describe('test ELFParser', () => {
const fs = require('fs');
const data = fs.readFileSync('./test/exes/arm32.elf');
const elfParser = new ELFParser(new Uint8Array(data));
it('should parse sections and symbols', () => {
/*
elfParser.sectionHeaders.forEach((section, index) => {
console.log('section', index, section.name, section.type, section.vaddr.toString(16), section.size.toString(16));
});
elfParser.getSymbols().forEach((symbol, index) => {
console.log('symbol', index, symbol.info, symbol.other, symbol.name, symbol.value.toString(16));
});
*/
assert.strictEqual(21, elfParser.sectionHeaders.length);
assert.strictEqual(29, elfParser.getSymbols().length);
assert.ok(elfParser.sectionHeaders.find((section) => section.name === '.text') != null);
assert.ok(elfParser.getSymbols().find((symbol) => symbol.name === 'main') != null);
});
it('should parse DWARF info', () => {
const dwarf = new DWARFParser(elfParser);
assert.strictEqual(2, dwarf.units.length);
const cu = dwarf.units[0];
// TODO: check info content
const li = dwarf.lineInfos[0];
assert.strictEqual('crt0.c', li.files[1].name);
/*
assert.ok(info != null);
assert.ok(info!.lineNumberProgram != null);
assert.ok(info!.lineNumberProgram!.length > 0);
assert.ok(info!.lineNumberProgram![0].file != null);
assert.ok(info!.lineNumberProgram![0].file!.name != null);
assert.ok(info!.lineNumberProgram![0].file!.name!.length > 0);
*/
});
});

Binary file not shown.

View File

@ -1,27 +0,0 @@
extern void _end;
void malloc_addblock(void* addr, int size);
int entry();
__attribute__((weak, naked, noinline, noreturn)) void _start() {
// set bss segment symbols
asm(".global __bss_start__, __bss_end__");
asm("__bss_start__ = _edata");
asm("__bss_end__ = _end");
// set stack pointer
asm("mov sp, #0x100000");
// allocate heap block
malloc_addblock(&_end, (void*)0xf0000 - &_end);
// run main()
entry();
// wait for next video frame
while (*(volatile int*)0x4000020 != 0) { }
// halt cpu
asm(".long 0xe7f000f0"); // udf #0
}
void _Exit(int ec) {
asm(".long 0xe7f000f0"); // udf #0
}

Binary file not shown.

View File

@ -1,24 +1,3 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
export var PLATFORM_PARAMS = {
'vcs': {
@ -355,13 +334,6 @@ export var PLATFORM_PARAMS = {
extra_link_files: ['crt0.o', 'exidy.cfg'],
//extra_compile_files: ['exidy.h'],
},
'arm32': {
arch: 'arm32',
define: ['__ARM__', 'DISABLE_UNIMPLEMENTED_LIBC_APIS', 'PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT'],
extra_compile_args: ['-I./arch/arm/include', '-I./openlibm/include', '-I./openlibm/src', '-I./printf/src'],
extra_link_files: ['crt0.c', 'libc.a'],
extra_link_args: ['crt0.c', '-lc'],
},
};
PLATFORM_PARAMS['sms-sms-libcv'] = PLATFORM_PARAMS['sms-sg1000-libcv'];

View File

@ -1,32 +1,8 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { DWARFParser, ELFParser } from "../../common/binutils";
import { hex } from "../../common/util";
import { WASIFilesystem } from "../../common/wasi/wasishim";
import { CodeListingMap, SourceLine, WorkerError, WorkerResult } from "../../common/workertypes";
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, putWorkFile, anyTargetChanged, getPrefix, getWorkFileAsString, populateExtraFiles, processEmbedDirective } from "../builder";
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, putWorkFile, anyTargetChanged, getPrefix, getWorkFileAsString } from "../builder";
import { makeErrorMatcher, re_crlf } from "../listingutils";
import { loadWASIFilesystemZip } from "../wasiutils";
import { loadNative, moduleInstFn, execMain, emglobal, EmscriptenModule } from "../wasmutils";
export function assembleARMIPS(step: BuildStep): WorkerResult {
@ -263,191 +239,3 @@ export function assembleVASMARM(step: BuildStep): BuildStepResult {
}
}
function tccErrorMatcher(errors: WorkerError[], mainpath: string) {
return makeErrorMatcher(errors, /([^:]+|tcc):(\d+|\s*error): (.+)/, 2, 3, mainpath, 1);;
}
let armtcc_fs: WASIFilesystem | null = null;
export async function compileARMTCC(step: BuildStep): Promise<BuildStepResult> {
loadNative("arm-tcc");
const params = step.params;
const errors = [];
gatherFiles(step, { mainFilePath: "main.c" });
const objpath = step.prefix + ".o";
const error_fn = tccErrorMatcher(errors, step.path);
if (!armtcc_fs) {
armtcc_fs = await loadWASIFilesystemZip("arm32-fs.zip");
}
if (staleFiles(step, [objpath])) {
const armtcc: EmscriptenModule = await emglobal.armtcc({
instantiateWasm: moduleInstFn('arm-tcc'),
noInitialRun: true,
print: error_fn,
printErr: error_fn,
});
var args = ['-c', '-I.', '-I./include',
//'-std=c11',
'-funsigned-char',
//'-Wwrite-strings',
'-gdwarf-2',
'-o', objpath];
if (params.define) {
params.define.forEach((x) => args.push('-D' + x));
}
if (params.extra_compile_args) {
args = args.concat(params.extra_compile_args);
}
args.push(step.path);
const FS = armtcc.FS;
// TODO: only should do once?
armtcc_fs.getDirectories().forEach((dir) => {
if (dir.name != '/') FS.mkdir(dir.name);
});
armtcc_fs.getFiles().forEach((file) => {
FS.writeFile(file.name, file.getBytes(), { encoding: 'binary' });
});
populateExtraFiles(step, FS, params.extra_compile_files);
populateFiles(step, FS, {
mainFilePath: step.path,
processFn: (path, code) => {
if (typeof code === 'string') {
code = processEmbedDirective(code);
}
return code;
}
});
execMain(step, armtcc, args);
if (errors.length)
return { errors: errors };
var objout = FS.readFile(objpath, { encoding: 'binary' }) as Uint8Array;
putWorkFile(objpath, objout);
}
return {
linktool: "armtcclink",
files: [objpath],
args: [objpath]
}
}
export async function linkARMTCC(step: BuildStep): Promise<WorkerResult> {
loadNative("arm-tcc");
const params = step.params;
const errors = [];
gatherFiles(step, { mainFilePath: "main.c" });
const objpath = "main.elf";
const error_fn = tccErrorMatcher(errors, step.path);
if (staleFiles(step, [objpath])) {
const armtcc: EmscriptenModule = await emglobal.armtcc({
instantiateWasm: moduleInstFn('arm-tcc'),
noInitialRun: true,
print: error_fn,
printErr: error_fn,
});
var args = ['-L.', '-nostdlib', '-nostdinc',
'-Wl,--oformat=elf32-arm',
//'-Wl,-section-alignment=0x100000',
'-gdwarf-2',
'-o', objpath];
if (params.define) {
params.define.forEach((x) => args.push('-D' + x));
}
args = args.concat(step.files);
if (params.extra_link_args) {
args = args.concat(params.extra_link_args);
}
const FS = armtcc.FS;
populateExtraFiles(step, FS, params.extra_link_files);
populateFiles(step, FS);
execMain(step, armtcc, args);
if (errors.length)
return { errors: errors };
var objout = FS.readFile(objpath, { encoding: 'binary' }) as Uint8Array;
putWorkFile(objpath, objout);
if (!anyTargetChanged(step, [objpath]))
return;
// parse ELF and create ROM
const elfparser = new ELFParser(objout);
let maxaddr = 0;
elfparser.sectionHeaders.forEach((section, index) => {
maxaddr = Math.max(maxaddr, section.vmaddr + section.size);
});
let rom = new Uint8Array(maxaddr);
elfparser.sectionHeaders.forEach((section, index) => {
if (section.flags & 0x2) {
let data = objout.slice(section.offset, section.offset + section.size);
//console.log(section.name, section.vmaddr.toString(16), data);
rom.set(data, section.vmaddr);
}
});
// set vectors, entry point etc
const obj32 = new Uint32Array(rom.buffer);
const start = elfparser.entry;
obj32[0] = start; // set reset vector
obj32[1] = start; // set undefined vector
obj32[2] = start; // set swi vector
obj32[3] = start; // set prefetch abort vector
obj32[4] = start; // set data abort vector
obj32[5] = start; // set reserved vector
obj32[6] = start; // set irq vector
obj32[7] = start; // set fiq vector
let symbolmap = {};
elfparser.getSymbols().forEach((symbol, index) => {
symbolmap[symbol.name] = symbol.value;
});
let segments = [];
elfparser.sectionHeaders.forEach((section, index) => {
if ((section.flags & 0x2) && section.size) {
segments.push({
name: section.name,
start: section.vmaddr,
size: section.size,
type: section.type,
});
}
});
const listings: CodeListingMap = {};
const dwarf = new DWARFParser(elfparser);
dwarf.lineInfos.forEach((lineInfo) => {
lineInfo.files.forEach((file) => {
if (!file || !file.lines) return;
file.lines.forEach((line) => {
const filename = line.file;
const offset = line.address;
const path = getPrefix(filename) + '.lst';
const linenum = line.line;
let lst = listings[path];
if (lst == null) { lst = listings[path] = { lines: [] }; }
lst.lines.push({
path,
line: linenum,
offset
});
});
});
});
//console.log(listings);
return {
output: rom, //.slice(0x34),
listings: listings,
errors: errors,
symbolmap: symbolmap,
segments: segments,
debuginfo: dwarf
};
}
}

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -52,8 +52,6 @@ export const TOOLS = {
'ecs': ecs.assembleECS,
'remote': remote.buildRemote,
'cc7800': cc7800.compileCC7800,
'armtcc': arm.compileARMTCC,
'armtcclink': arm.linkARMTCC,
}
export const TOOL_PRELOADFS = {

Binary file not shown.