mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-04-06 17:39:40 +00:00
arm32: working w/ gba emu
This commit is contained in:
parent
7725884eb0
commit
76d29c6026
@ -1,6 +1,6 @@
|
||||
.set VIDMEM, 0x20000000
|
||||
.set VIDMEM, 0x40000000
|
||||
|
||||
mov r0, #0x884400 ; RGB value
|
||||
mov r0, #0xff880000 ; RGB value
|
||||
mov r1, #VIDMEM ; memory start
|
||||
LOOP2:
|
||||
mov r2, #160*128 ; word count
|
||||
@ -9,7 +9,8 @@ LOOP:
|
||||
sub r2, r2, #1
|
||||
cmp r2, #0
|
||||
bge LOOP
|
||||
sub r0, r0, #0xff11
|
||||
add r0, r0, #0xf002
|
||||
cmp r0, #0
|
||||
bgt LOOP2
|
||||
blt LOOP2
|
||||
.ualong 0x11223344 ; illegal instruction
|
||||
|
||||
|
@ -1220,6 +1220,14 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
|
||||
readAddress(addr : number) : number {
|
||||
return this.machine.read(addr);
|
||||
}
|
||||
|
||||
getDebugCategories() {
|
||||
if (isDebuggable(this.machine))
|
||||
return this.machine.getDebugCategories();
|
||||
}
|
||||
getDebugInfo(category:string, state:EmuState) : string {
|
||||
return isDebuggable(this.machine) && this.machine.getDebugInfo(category, state);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move debug info into CPU?
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -626,16 +626,16 @@ type AddressDecoderOptions = {gmask?:number};
|
||||
// TODO: better performance, check values
|
||||
export function AddressDecoder(table : AddressDecoderEntry[], options?:AddressDecoderOptions) {
|
||||
var self = this;
|
||||
function makeFunction(lo, hi) {
|
||||
function makeFunction() {
|
||||
var s = "";
|
||||
if (options && options.gmask) {
|
||||
s += "a&=" + options.gmask + ";";
|
||||
}
|
||||
for (var i=0; i<table.length; i++) {
|
||||
var entry = table[i];
|
||||
var start = entry[0];
|
||||
var end = entry[1];
|
||||
var mask = entry[2];
|
||||
var start = entry[0]|0;
|
||||
var end = entry[1]|0;
|
||||
var mask = entry[2]|0;
|
||||
var func = entry[3];
|
||||
self['__fn'+i] = func;
|
||||
s += "if (a>=" + start + " && a<="+end + "){";
|
||||
@ -645,7 +645,7 @@ export function AddressDecoder(table : AddressDecoderEntry[], options?:AddressDe
|
||||
s += "return 0;"; // TODO: noise()?
|
||||
return new Function('a', 'v', s);
|
||||
}
|
||||
return makeFunction(0x0, 0xffff).bind(self);
|
||||
return makeFunction().bind(self);
|
||||
}
|
||||
|
||||
export function newAddressDecoder(table : AddressDecoderEntry[], options?:AddressDecoderOptions) : (a:number,v?:number) => number {
|
||||
|
@ -32,7 +32,11 @@ export function getFilenamePrefix(s:string):string {
|
||||
|
||||
export function hex(v:number, nd?:number) {
|
||||
if (!nd) nd = 2;
|
||||
return toradix(v,nd,16);
|
||||
if (nd == 8) {
|
||||
return hex((v>>16)&0xffff,4) + hex(v&0xffff,4);
|
||||
} else {
|
||||
return toradix(v,nd,16);
|
||||
}
|
||||
}
|
||||
|
||||
export function tobin(v:number, nd?:number) {
|
||||
|
@ -55,7 +55,7 @@ var debugCategory; // current debug category
|
||||
var debugTickPaused = false;
|
||||
var recorderActive = false;
|
||||
var lastViewClicked = null;
|
||||
|
||||
var errorWasRuntime = false;
|
||||
var lastBreakExpr = "c.PC == 0x6000";
|
||||
|
||||
// TODO: codemirror multiplex support?
|
||||
@ -1106,14 +1106,16 @@ function getErrorElement(err : WorkerError) {
|
||||
|
||||
function hideErrorAlerts() {
|
||||
$("#error_alert").hide();
|
||||
errorWasRuntime = false;
|
||||
}
|
||||
|
||||
function showErrorAlert(errors : WorkerError[]) {
|
||||
function showErrorAlert(errors : WorkerError[], runtime : boolean) {
|
||||
var div = $("#error_alert_msg").empty();
|
||||
for (var err of errors.slice(0,10)) {
|
||||
div.append(getErrorElement(err));
|
||||
}
|
||||
$("#error_alert").show();
|
||||
errorWasRuntime = runtime;
|
||||
}
|
||||
|
||||
function showExceptionAsError(err, msg:string) {
|
||||
@ -1125,7 +1127,7 @@ function showExceptionAsError(err, msg:string) {
|
||||
console.log(werr);
|
||||
projectWindows.refresh(false);
|
||||
}
|
||||
showErrorAlert([werr]);
|
||||
showErrorAlert([werr], true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1146,7 +1148,7 @@ function setCompileOutput(data: WorkerResult) {
|
||||
if (data && data.errors && data.errors.length > 0) {
|
||||
toolbar.addClass("has-errors");
|
||||
projectWindows.setErrors(data.errors);
|
||||
showErrorAlert(data.errors);
|
||||
showErrorAlert(data.errors, false);
|
||||
} else {
|
||||
toolbar.removeClass("has-errors"); // may be added in next callback
|
||||
projectWindows.setErrors(null);
|
||||
@ -1286,7 +1288,7 @@ function setupDebugCallback(btnid? : string) {
|
||||
if (platform.setupDebug) platform.setupDebug((state:EmuState, msg:string) => {
|
||||
uiDebugCallback(state);
|
||||
setDebugButtonState(btnid||"pause", "stopped");
|
||||
msg && showErrorAlert([{msg:"STOPPED: " + msg, line:0}]);
|
||||
msg && showErrorAlert([{msg:"STOPPED: " + msg, line:0}], true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1318,7 +1320,7 @@ function _resume() {
|
||||
console.log("Resumed");
|
||||
}
|
||||
setDebugButtonState("go", "active");
|
||||
// TODO: hide alerts, but only if exception generated them
|
||||
if (errorWasRuntime) { hideErrorAlerts(); }
|
||||
}
|
||||
|
||||
function resume() {
|
||||
|
@ -553,7 +553,8 @@ export class DisassemblerView implements ProjectView {
|
||||
}
|
||||
return s;
|
||||
}
|
||||
let text = disassemble(pc-disasmWindow, disasmWindow) + disassemble(pc, disasmWindow);
|
||||
var startpc = pc < 0 ? pc-disasmWindow : Math.max(0, pc-disasmWindow); // for 32-bit PCs w/ hi bit set
|
||||
let text = disassemble(startpc, pc-startpc) + disassemble(pc, disasmWindow);
|
||||
this.disasmview.setValue(text);
|
||||
if (moveCursor) {
|
||||
this.disasmview.setCursor(selline, 0);
|
||||
|
121
src/machine/arm32.ts
Normal file
121
src/machine/arm32.ts
Normal file
@ -0,0 +1,121 @@
|
||||
|
||||
import { ARM32CPU, ARMCoreState } from "../common/cpu/ARM";
|
||||
import { BasicScanlineMachine } from "../common/devices";
|
||||
import { KeyFlags, newAddressDecoder, padBytes, Keys, makeKeycodeMap, newKeyboardHandler } from "../common/emu";
|
||||
import { TssChannelAdapter, MasterAudio, AY38910_Audio } from "../common/audio";
|
||||
import { Debuggable, EmuState } from "../common/baseplatform";
|
||||
import { hex, lpad, printFlags } from "../common/util";
|
||||
|
||||
const SPACEINV_KEYCODE_MAP = makeKeycodeMap([
|
||||
[Keys.A, 1, 0x10], // P1
|
||||
[Keys.LEFT, 1, 0x20],
|
||||
[Keys.RIGHT, 1, 0x40],
|
||||
[Keys.P2_A, 2, 0x10], // P2
|
||||
[Keys.P2_LEFT, 2, 0x20],
|
||||
[Keys.P2_RIGHT, 2, 0x40],
|
||||
[Keys.SELECT, 1, 0x1],
|
||||
[Keys.START, 1, 0x4],
|
||||
[Keys.P2_START, 1, 0x2],
|
||||
]);
|
||||
|
||||
const ROM_START = 0x0;
|
||||
const ROM2_START= 0xff800000;
|
||||
const ROM_SIZE = 0x80000;
|
||||
const RAM_START = 0x20000000;
|
||||
const RAM_SIZE = 0x80000;
|
||||
const VID_START = 0x40000000;
|
||||
const VID_SIZE = 0x20000;
|
||||
|
||||
const CPU_FREQ = 4000000;
|
||||
|
||||
export class ARM32Machine extends BasicScanlineMachine implements Debuggable {
|
||||
|
||||
cpuFrequency = CPU_FREQ; // MHz
|
||||
canvasWidth = 160;
|
||||
numTotalScanlines = 256;
|
||||
numVisibleScanlines = 128;
|
||||
cpuCyclesPerLine = Math.floor(CPU_FREQ / (256*60));
|
||||
defaultROMSize = 512*1024;
|
||||
sampleRate = 1;
|
||||
|
||||
cpu: ARM32CPU = new ARM32CPU();
|
||||
ram = new Uint8Array(512*1024);
|
||||
pixels8 : Uint8Array;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.connectCPUMemoryBus(this);
|
||||
this.handler = newKeyboardHandler(this.inputs, SPACEINV_KEYCODE_MAP);
|
||||
}
|
||||
|
||||
connectVideo(pixels:Uint32Array) : void {
|
||||
super.connectVideo(pixels);
|
||||
this.pixels8 = new Uint8Array(pixels.buffer);
|
||||
//this.pixels.fill(0xff000000);
|
||||
}
|
||||
|
||||
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];
|
||||
}],
|
||||
[ROM2_START, ROM2_START+ROM_SIZE-1, ROM_SIZE-1, (a) => {
|
||||
return this.rom ? this.rom[a] : 0;
|
||||
}],
|
||||
]);
|
||||
|
||||
write = newAddressDecoder([
|
||||
[RAM_START, RAM_START+RAM_SIZE-1, RAM_SIZE-1, (a, v) => {
|
||||
this.ram[a] = v;
|
||||
}],
|
||||
[VID_START, VID_START+VID_SIZE-1, VID_SIZE-1, (a, v) => {
|
||||
this.pixels8[a] = v;
|
||||
}],
|
||||
]);
|
||||
|
||||
startScanline() {
|
||||
}
|
||||
|
||||
drawScanline() {
|
||||
// at end of scanline
|
||||
}
|
||||
|
||||
getDebugCategories() {
|
||||
return ['CPU'];
|
||||
}
|
||||
|
||||
getDebugInfo?(category: string, state: EmuState) : string {
|
||||
var s = '';
|
||||
var c = state.c as ARMCoreState;
|
||||
for (var i=0; i<13; i++) {
|
||||
s += lpad('r'+i, 3) + ' ' + hex(c.gprs[i],8) + '\n';
|
||||
}
|
||||
s += ' SP ' + hex(c.SP,8) + '\n';
|
||||
s += ' LR ' + hex(c.gprs[14],8) + '\n';
|
||||
s += ' PC ' + hex(c.PC,8) + '\n';
|
||||
s += c.cpsrN ? " N" : " -";
|
||||
s += c.cpsrV ? " V" : " -";
|
||||
s += c.cpsrF ? " F" : " -";
|
||||
s += c.cpsrZ ? " Z" : " -";
|
||||
s += c.cpsrC ? " C" : " -";
|
||||
s += c.cpsrI ? " I" : " -";
|
||||
s += '\n';
|
||||
s += 'MODE ' + MODE_NAMES[c.mode];
|
||||
s += '\n';
|
||||
s += 'cycl ' + c.cycles;
|
||||
s += '\n';
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
const MODE_NAMES = {
|
||||
0x10: "USER",
|
||||
0x11: "FIQ",
|
||||
0x12: "IRQ",
|
||||
0x13: "SUPERVISOR",
|
||||
0x17: "ABORT",
|
||||
0x1b: "UNDEFINED",
|
||||
0x1f: "SYSTEM",
|
||||
};
|
@ -6,12 +6,6 @@ import { TssChannelAdapter, MasterAudio, AY38910_Audio } from "../common/audio";
|
||||
|
||||
// http://www.computerarcheology.com/Arcade/
|
||||
|
||||
const MW8080BW_PRESETS = [
|
||||
{ id: 'gfxtest.c', name: 'Graphics Test' },
|
||||
{ id: 'shifter.c', name: 'Sprite w/ Bit Shifter' },
|
||||
{ id: 'game2.c', name: 'Cosmic Impalas' },
|
||||
];
|
||||
|
||||
const SPACEINV_KEYCODE_MAP = makeKeycodeMap([
|
||||
[Keys.A, 1, 0x10], // P1
|
||||
[Keys.LEFT, 1, 0x20],
|
||||
|
@ -1,10 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
import { BaseDebugPlatform, CpuState, EmuState, Platform, DisasmLine, Debuggable } from "../common/baseplatform";
|
||||
import { BaseDebugPlatform, CpuState, EmuState, Platform, DisasmLine, Debuggable, Machine, BaseMachinePlatform } from "../common/baseplatform";
|
||||
import { AnimationTimer, EmuHalt, padBytes, PLATFORMS, RasterVideo } from "../common/emu";
|
||||
import { loadScript } from "../ide/ui";
|
||||
import { hex, lpad } from "../common/util";
|
||||
import { ARM32CPU } from "../common/cpu/ARM";
|
||||
import { ARM32Machine } from "../machine/arm32";
|
||||
|
||||
declare var uc, cs : any; // Unicorn module
|
||||
|
||||
@ -25,7 +25,7 @@ interface ARM32State extends EmuState {
|
||||
r: Uint32Array; // registers
|
||||
}
|
||||
|
||||
class ARM32Platform extends BaseDebugPlatform implements Platform, Debuggable {
|
||||
class ARM32UnicornPlatform extends BaseDebugPlatform implements Platform, Debuggable {
|
||||
|
||||
u : any; // Unicorn
|
||||
d : any; // Capstone
|
||||
@ -48,7 +48,7 @@ class ARM32Platform extends BaseDebugPlatform implements Platform, Debuggable {
|
||||
await loadScript('./lib/unicorn-arm.min.js');
|
||||
await loadScript('./lib/capstone-arm.min.js');
|
||||
|
||||
//this.cpu = new ARM32CPU();
|
||||
this.cpu = new ARM32CPU();
|
||||
|
||||
this.u = new uc.Unicorn(uc.ARCH_ARM, uc.MODE_ARM);
|
||||
this.u.mem_map(ROM_START_ADDR, ROM_SIZE, uc.PROT_READ | uc.PROT_EXEC);
|
||||
@ -63,7 +63,7 @@ class ARM32Platform extends BaseDebugPlatform implements Platform, Debuggable {
|
||||
this.timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
||||
}
|
||||
reset() {
|
||||
//this.cpu.reset();
|
||||
this.cpu.reset();
|
||||
this.u.reg_write_i32(uc.ARM_REG_PC, 0);
|
||||
var cpsr = this.u.reg_read_i32(uc.ARM_REG_CPSR);
|
||||
this.u.reg_write_i32(uc.ARM_REG_CPSR, (cpsr & 0xffffff00) | 0b11010011);
|
||||
@ -89,8 +89,8 @@ class ARM32Platform extends BaseDebugPlatform implements Platform, Debuggable {
|
||||
}
|
||||
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
|
||||
try {
|
||||
var b = this.u.mem_read(pc, 8);
|
||||
var insns = this.d.disasm(b, pc, 8);
|
||||
var b = this.u.mem_read(pc, 4);
|
||||
var insns = this.d.disasm(b, pc, 4);
|
||||
var i0 = insns[0];
|
||||
return {
|
||||
nbytes: i0.size,
|
||||
@ -220,29 +220,59 @@ class ARM32Platform extends BaseDebugPlatform implements Platform, Debuggable {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
////
|
||||
|
||||
export abstract class BaseARMMachinePlatform<T extends Machine> extends BaseMachinePlatform<T> {
|
||||
|
||||
//getOpcodeMetadata = getOpcodeMetadata_z80;
|
||||
getToolForFilename() { return "armips"; }
|
||||
getToolForFilename() { return "vasmarm"; }
|
||||
|
||||
}
|
||||
|
||||
class ARM32Platform extends BaseARMMachinePlatform<ARM32Console> implements Platform {
|
||||
class ARM32Platform extends BaseARMMachinePlatform<ARM32Machine> implements Platform {
|
||||
|
||||
capstone : any;
|
||||
|
||||
async start() {
|
||||
console.log("Loading Unicorn");
|
||||
await loadScript('./unicorn.js/dist/unicorn-arm.min.js');
|
||||
return super.start();
|
||||
super.start();
|
||||
console.log("Loading Capstone");
|
||||
await loadScript('./lib/capstone-arm.min.js');
|
||||
this.capstone = new cs.Capstone(cs.ARCH_ARM, cs.MODE_ARM);
|
||||
}
|
||||
newMachine() { return new ARM32Console(); }
|
||||
|
||||
newMachine() { return new ARM32Machine(); }
|
||||
getPresets() { return ARM32_PRESETS; }
|
||||
getDefaultExtension() { return ".asm"; };
|
||||
readAddress(a) { return this.machine.read(a); }
|
||||
getMemoryMap = function() { return { main:[
|
||||
{name:'Frame Buffer',start:0x2400,size:7168,type:'ram'},
|
||||
{name:'ROM',start:0x00000000,size:0x80000,type:'rom'},
|
||||
{name:'RAM',start:0x20000000,size:0x80000,type:'ram'},
|
||||
{name:'Video RAM',start:0x40000000,size:0x20000,type:'ram'},
|
||||
] } };
|
||||
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
|
||||
var buf = [];
|
||||
for (var i=0; i<4; i++) {
|
||||
buf[i] = read(pc+i);
|
||||
}
|
||||
var insns = this.capstone.disasm(buf, pc, 4);
|
||||
var i0 = insns && insns[0];
|
||||
if (i0) {
|
||||
return {
|
||||
nbytes: i0.size,
|
||||
line: i0.mnemonic + " " + i0.op_str,
|
||||
isaddr: i0.address > 0
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
nbytes: 4,
|
||||
line: "???",
|
||||
isaddr: false
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
////
|
||||
|
||||
PLATFORMS['arm32.u'] = ARM32UnicornPlatform;
|
||||
PLATFORMS['arm32'] = ARM32Platform;
|
||||
|
Loading…
x
Reference in New Issue
Block a user