mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-12-30 18:31:30 +00:00
x86: started using v86, freedos, fatfs, yasm, SmallerC
This commit is contained in:
parent
9396a2ddbb
commit
0d77912ccc
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,4 +6,5 @@ local
|
|||||||
./test/output
|
./test/output
|
||||||
tests_output/
|
tests_output/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
tmp
|
tmp/
|
||||||
|
web/
|
||||||
|
@ -558,3 +558,11 @@ div.asset_toolbar {
|
|||||||
.book-title {
|
.book-title {
|
||||||
font-size:12pt;
|
font-size:12pt;
|
||||||
}
|
}
|
||||||
|
.pc-console {
|
||||||
|
background-color: #000;
|
||||||
|
color: #7f7f7f;
|
||||||
|
white-space: pre;
|
||||||
|
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||||
|
font-size: 10pt;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
@ -516,6 +516,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||||||
<script src="codemirror/mode/verilog/verilog.js"></script>
|
<script src="codemirror/mode/verilog/verilog.js"></script>
|
||||||
<script src="codemirror/mode/markdown/markdown.js"></script>
|
<script src="codemirror/mode/markdown/markdown.js"></script>
|
||||||
<script src="codemirror/mode/javascript/javascript.js"></script>
|
<script src="codemirror/mode/javascript/javascript.js"></script>
|
||||||
|
<script src="codemirror/mode/gas/gas.js"></script>
|
||||||
<script src="src/codemirror/6502.js"></script>
|
<script src="src/codemirror/6502.js"></script>
|
||||||
<script src="src/codemirror/bataribasic.js"></script>
|
<script src="src/codemirror/bataribasic.js"></script>
|
||||||
<link rel="stylesheet" href="css/codemirror.css">
|
<link rel="stylesheet" href="css/codemirror.css">
|
||||||
|
8275
lib/fatfs.js
Normal file
8275
lib/fatfs.js
Normal file
File diff suppressed because it is too large
Load Diff
1281
lib/libv86.js
Normal file
1281
lib/libv86.js
Normal file
File diff suppressed because it is too large
Load Diff
13
presets/x86/hello.asm
Normal file
13
presets/x86/hello.asm
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
; http://www.ablmcc.edu.hk/~scy/CIT/8086_bios_and_dos_interrupts.htm
|
||||||
|
org 100h ; EXE files start at 0x100
|
||||||
|
section .text ; code section
|
||||||
|
|
||||||
|
mov dx,msg ; DX = string address
|
||||||
|
mov ah,9 ; 9 = "draw string"
|
||||||
|
int 21h
|
||||||
|
mov ah,4Ch ; 4ch = "exit to OS"
|
||||||
|
int 21h
|
||||||
|
|
||||||
|
section .data ; data section
|
||||||
|
msg db 'Hello, World!',0Dh,0Ah,'$'
|
152
presets/x86/mandelg.asm
Normal file
152
presets/x86/mandelg.asm
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
;; Draw a grayscale mandelbrot fractal
|
||||||
|
;;
|
||||||
|
;; i compiled with yasm: yasm -o mandel.com mandel.asm
|
||||||
|
;; but i think it should be quite portable to other assemblers.
|
||||||
|
;;
|
||||||
|
;; from: https://www.reddit.com/r/asm/comments/8o8c0b/mandelbrot_x86_asm_w_vga/
|
||||||
|
|
||||||
|
SECTION .data
|
||||||
|
|
||||||
|
maxi: equ 128 ; upto maxi iterations per pixel
|
||||||
|
palscale: equ 1 ; ammount to shift to fit maxi onto palette
|
||||||
|
crestep: equ 2 ; x (mandelwidth/320) * 2^shift
|
||||||
|
cimstep: equ 3 ; y (mandelheight/200) * 2^shift
|
||||||
|
one: equ 256 ; fixed point 1.0
|
||||||
|
n15: equ -450 ; start of left side
|
||||||
|
two: equ 512 ; fixed point 2.0
|
||||||
|
four: equ 1024 ; fixed point 4.0
|
||||||
|
|
||||||
|
cim: dw 300 ; imaginary part of Y
|
||||||
|
cre: dw 0 ; imaginary part of X
|
||||||
|
x: dw 0 ; real part of X
|
||||||
|
y: dw 0 ; real part of Y
|
||||||
|
xx: dw 0 ; x*x placeholder
|
||||||
|
yy: dw 0 ; y*y placeholder
|
||||||
|
twox: dw 0 ; 2*x placeholder
|
||||||
|
xnew: dw 0 ; temporary x placeholder
|
||||||
|
row: dw 0 ; current row
|
||||||
|
col dw 0 ; current col
|
||||||
|
|
||||||
|
SECTION .text
|
||||||
|
ORG 0x100 ; dos .com file starts at 0100h
|
||||||
|
|
||||||
|
call setup ; setup screen mode
|
||||||
|
call draw ; draw the fractal
|
||||||
|
call waitkey ; wait for a keypress
|
||||||
|
|
||||||
|
exit:
|
||||||
|
mov ax, 3 ; back to text
|
||||||
|
int 0x10 ; mode
|
||||||
|
mov ax, 0x4c00 ; clean dos
|
||||||
|
int 0x21 ; exit
|
||||||
|
|
||||||
|
setup:
|
||||||
|
mov ax, 0x13 ; setup screen mode 13
|
||||||
|
int 0x10 ; 320x200x256
|
||||||
|
mov ax, 0 ; setup grayscale palette
|
||||||
|
mov dx, 0x03c8 ; setup register to receive
|
||||||
|
out dx, al ; full palette (768bytes of rgb data)
|
||||||
|
inc dx ; the next register expects data
|
||||||
|
setpalette:
|
||||||
|
out dx, al ; red value
|
||||||
|
out dx, al ; green value
|
||||||
|
out dx, al ; blue value
|
||||||
|
inc al ; next 'color'
|
||||||
|
jnz setpalette
|
||||||
|
mov ax, 0xa000 ; point es:di to
|
||||||
|
mov es, ax ; 0a000:0000
|
||||||
|
xor di, di ; so stos functions write to vram
|
||||||
|
cld ; we move forward in memory
|
||||||
|
xor ax,ax ; clear
|
||||||
|
mov cx,32000 ; screen
|
||||||
|
rep stosw
|
||||||
|
xor di, di ; restore di to start of vram
|
||||||
|
ret
|
||||||
|
|
||||||
|
waitkey:
|
||||||
|
mov ax, 0 ; wait for
|
||||||
|
int 0x16 ; keypress
|
||||||
|
jnz waitkey ; none received, start over
|
||||||
|
ret
|
||||||
|
|
||||||
|
draw:
|
||||||
|
mov word [row], 200 ; 200 rows
|
||||||
|
|
||||||
|
yloop:
|
||||||
|
mov ax, n15
|
||||||
|
mov [cre], ax ; start of left side
|
||||||
|
|
||||||
|
mov word [col], 320 ; 320 columns
|
||||||
|
xloop:
|
||||||
|
xor ax, ax
|
||||||
|
xor cx, cx ; iter = 0
|
||||||
|
mov [x], ax ; x = 0
|
||||||
|
mov [y], ax ; y = 0
|
||||||
|
|
||||||
|
whileloop: ; while ( iter < maxi && x*x + y*y < 4)
|
||||||
|
cmp cx, maxi ; if iter == maxi
|
||||||
|
je escape ; escape
|
||||||
|
|
||||||
|
mov ax, [x] ; x*x
|
||||||
|
mov bx, ax
|
||||||
|
imul bx
|
||||||
|
mov bx, one
|
||||||
|
idiv bx
|
||||||
|
mov [xx], ax
|
||||||
|
|
||||||
|
mov ax, [y] ; y*y
|
||||||
|
mov bx, ax
|
||||||
|
imul bx
|
||||||
|
mov bx, one
|
||||||
|
idiv bx
|
||||||
|
mov [yy], ax
|
||||||
|
|
||||||
|
add ax, [xx] ; if x*x + y*y ==
|
||||||
|
cmp ax, four ; four
|
||||||
|
jge escape ; escape
|
||||||
|
|
||||||
|
mov ax, [xx] ; xnew = x*x - y*y + cre
|
||||||
|
sub ax, [yy]
|
||||||
|
add ax, [cre]
|
||||||
|
mov [xnew], ax
|
||||||
|
|
||||||
|
mov ax, [x] ; x * 2 * y
|
||||||
|
mov bx, two
|
||||||
|
imul bx
|
||||||
|
mov bx, one
|
||||||
|
idiv bx
|
||||||
|
mov bx, [y]
|
||||||
|
imul bx
|
||||||
|
mov bx, one
|
||||||
|
idiv bx
|
||||||
|
add ax, [cim] ; + cim
|
||||||
|
|
||||||
|
mov [y], ax ; y = x * 2 * y + cim
|
||||||
|
|
||||||
|
mov ax, [xnew] ; x = xnew
|
||||||
|
mov [x], ax
|
||||||
|
|
||||||
|
inc cx ; ++iter
|
||||||
|
jmp whileloop
|
||||||
|
|
||||||
|
escape:
|
||||||
|
mov al, cl ; copy color index (iter)
|
||||||
|
cmp al, maxi ; plot pixel
|
||||||
|
jne color ; w/ black if maximum reached
|
||||||
|
xor al, al
|
||||||
|
color: ; otherwise w/ palette value
|
||||||
|
shl al, palscale ; scale to fit palette
|
||||||
|
stosb ; write pixel
|
||||||
|
|
||||||
|
add word [cre], crestep ; cre += crestep
|
||||||
|
|
||||||
|
dec word [col]
|
||||||
|
jnz xloop ; next column
|
||||||
|
|
||||||
|
sub word [cim], cimstep ; cim -= cimstep
|
||||||
|
|
||||||
|
dec word [row] ; next row
|
||||||
|
jnz yloop
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
11
presets/x86/skeleton.yasm
Normal file
11
presets/x86/skeleton.yasm
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
section .text
|
||||||
|
org 100h
|
||||||
|
|
||||||
|
mov dx,msg ; DX = string address
|
||||||
|
mov ah,9 ; 9 = "draw string"
|
||||||
|
int 21h
|
||||||
|
mov ah,4Ch ; 4ch = "exit to OS"
|
||||||
|
int 21h
|
||||||
|
|
||||||
|
section .data
|
||||||
|
msg db 'Hello, World!',0Dh,0Ah,'$'
|
418
presets/x86/snake.c
Normal file
418
presets/x86/snake.c
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
/*
|
||||||
|
Compile:
|
||||||
|
smlrc -seg16 -nobss snake.c snake.asm
|
||||||
|
nasm -f bin snake.asm -o snake.com
|
||||||
|
|
||||||
|
Run snake.com in DOS, 32-bit Windows or DosBox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
asm("org 0x0");
|
||||||
|
|
||||||
|
int main(void);
|
||||||
|
|
||||||
|
void start(void)
|
||||||
|
{
|
||||||
|
asm("mov ax,cs");
|
||||||
|
asm("mov ds,ax");
|
||||||
|
asm("mov es,ax");
|
||||||
|
asm("mov fs,ax");
|
||||||
|
main();
|
||||||
|
asm("mov ax,4ch");
|
||||||
|
asm("int 21h");
|
||||||
|
}
|
||||||
|
|
||||||
|
// defines the game speed
|
||||||
|
#define DELAY 150
|
||||||
|
|
||||||
|
// video mode, video buffer segment and dimensions
|
||||||
|
#define VMODE 1 // 40x25 color text mode
|
||||||
|
#define VSEG 0xB800
|
||||||
|
#define VWIDTH 40
|
||||||
|
#define VHEIGHT 25
|
||||||
|
|
||||||
|
// foreground and background colors
|
||||||
|
#define FORE_BLACK 0x00
|
||||||
|
#define FORE_BLUE 0x01
|
||||||
|
#define FORE_GREEN 0x02
|
||||||
|
#define FORE_CYAN 0x03
|
||||||
|
#define FORE_RED 0x04
|
||||||
|
#define FORE_MAGENTA 0x05
|
||||||
|
#define FORE_BROWN 0x06
|
||||||
|
#define FORE_WHITE 0x07
|
||||||
|
#define FORE_GRAY 0x08
|
||||||
|
#define FORE_BRIGHT_BLUE 0x09
|
||||||
|
#define FORE_BRIGHT_GREEN 0x0A
|
||||||
|
#define FORE_BRIGHT_CYAN 0x0B
|
||||||
|
#define FORE_BRIGHT_RED 0x0C
|
||||||
|
#define FORE_BRIGHT_MAGENTA 0x0D
|
||||||
|
#define FORE_YELLOW 0x0E
|
||||||
|
#define FORE_BRIGHT_WHITE 0x0F
|
||||||
|
#define BACK_BLACK 0x00
|
||||||
|
#define BACK_BLUE 0x10
|
||||||
|
#define BACK_GREEN 0x20
|
||||||
|
#define BACK_CYAN 0x30
|
||||||
|
#define BACK_RED 0x40
|
||||||
|
#define BACK_MAGENTA 0x50
|
||||||
|
#define BACK_BROWN 0x60
|
||||||
|
#define BACK_WHITE 0x70
|
||||||
|
|
||||||
|
// key codes
|
||||||
|
#define KEY_ESCAPE 0x011B
|
||||||
|
#define KEY_ENTER 0x1C0D
|
||||||
|
#define KEY_UP 0x4800
|
||||||
|
#define KEY_LEFT 0x4B00
|
||||||
|
#define KEY_RIGHT 0x4D00
|
||||||
|
#define KEY_DOWN 0x5000
|
||||||
|
|
||||||
|
// snake state
|
||||||
|
#define MIN_LENGTH 6
|
||||||
|
#define MAX_LENGTH (VWIDTH * VHEIGHT)
|
||||||
|
unsigned snake[MAX_LENGTH][2]; // coordinates
|
||||||
|
unsigned length;
|
||||||
|
unsigned direction;
|
||||||
|
|
||||||
|
// target
|
||||||
|
unsigned target[2]; // coordinates
|
||||||
|
|
||||||
|
unsigned score;
|
||||||
|
|
||||||
|
int BiosKeyAvailable(void)
|
||||||
|
{
|
||||||
|
asm("mov ah, 1\n"
|
||||||
|
"int 0x16\n"
|
||||||
|
"setnz al\n"
|
||||||
|
"cbw");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned BiosReadKey(void)
|
||||||
|
{
|
||||||
|
asm("mov ah, 0\n"
|
||||||
|
"int 0x16");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiosSetGfxMode(unsigned mode)
|
||||||
|
{
|
||||||
|
asm("mov ah, 0\n"
|
||||||
|
"mov al, [bp + 4]\n"
|
||||||
|
"int 0x10");
|
||||||
|
}
|
||||||
|
|
||||||
|
void pokeb(unsigned seg, unsigned ofs, unsigned char val)
|
||||||
|
{
|
||||||
|
asm("push ds\n"
|
||||||
|
"mov ds, [bp + 4]\n"
|
||||||
|
"mov bx, [bp + 6]\n"
|
||||||
|
"mov al, [bp + 8]\n"
|
||||||
|
"mov [bx], al\n"
|
||||||
|
"pop ds");
|
||||||
|
}
|
||||||
|
|
||||||
|
void poke(unsigned seg, unsigned ofs, unsigned val)
|
||||||
|
{
|
||||||
|
asm("push ds\n"
|
||||||
|
"mov ds, [bp + 4]\n"
|
||||||
|
"mov bx, [bp + 6]\n"
|
||||||
|
"mov ax, [bp + 8]\n"
|
||||||
|
"mov [bx], ax\n"
|
||||||
|
"pop ds");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char peekb(unsigned seg, unsigned ofs)
|
||||||
|
{
|
||||||
|
asm("push ds\n"
|
||||||
|
"mov ds, [bp + 4]\n"
|
||||||
|
"mov bx, [bp + 6]\n"
|
||||||
|
"mov al, [bx]\n"
|
||||||
|
"mov ah, 0\n"
|
||||||
|
"pop ds");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned peek(unsigned seg, unsigned ofs)
|
||||||
|
{
|
||||||
|
asm("push ds\n"
|
||||||
|
"mov ds, [bp + 4]\n"
|
||||||
|
"mov bx, [bp + 6]\n"
|
||||||
|
"mov ax, [bx]\n"
|
||||||
|
"pop ds");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiosGetTicks(unsigned ticks[2])
|
||||||
|
{
|
||||||
|
unsigned low, high1, high2;
|
||||||
|
high2 = peek(0x40, 0x6E);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
high1 = high2;
|
||||||
|
low = peek(0x40, 0x6C);
|
||||||
|
high2 = peek(0x40, 0x6E);
|
||||||
|
// make sure the top 16 bits of the ticks counter haven't changed meanwhile
|
||||||
|
} while (high1 != high2);
|
||||||
|
ticks[0] = low;
|
||||||
|
ticks[1] = high2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delay(unsigned milliseconds)
|
||||||
|
{
|
||||||
|
unsigned tcnt = (milliseconds + 27) / 55; // the 32-bit ticks counter increments every 55 ms
|
||||||
|
unsigned ticks[2][2];
|
||||||
|
BiosGetTicks(ticks[0]);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
BiosGetTicks(ticks[1]);
|
||||||
|
// ticks[1] -= ticks[0]
|
||||||
|
if (ticks[1][0] < ticks[0][0])
|
||||||
|
--ticks[1][1];
|
||||||
|
ticks[1][0] -= ticks[0][0];
|
||||||
|
ticks[1][1] -= ticks[0][1];
|
||||||
|
// ticks[1] >= tcnt ?
|
||||||
|
if (ticks[1][0] >= tcnt || ticks[1][1])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lineh(unsigned x, unsigned y, unsigned w, unsigned chr, unsigned color)
|
||||||
|
{
|
||||||
|
unsigned ofs = (y * VWIDTH + x) * 2;
|
||||||
|
unsigned v = (color << 8) | chr;
|
||||||
|
while (w--)
|
||||||
|
{
|
||||||
|
poke(VSEG, ofs, v);
|
||||||
|
ofs += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void linev(unsigned x, unsigned y, unsigned h, unsigned chr, unsigned color)
|
||||||
|
{
|
||||||
|
unsigned ofs = (y * VWIDTH + x) * 2;
|
||||||
|
unsigned v = (color << 8) | chr;
|
||||||
|
while (h--)
|
||||||
|
{
|
||||||
|
poke(VSEG, ofs, v);
|
||||||
|
ofs += VWIDTH * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void box(unsigned x, unsigned y, unsigned w, unsigned h, unsigned chr, unsigned color, unsigned solid)
|
||||||
|
{
|
||||||
|
if (solid)
|
||||||
|
{
|
||||||
|
while (h--)
|
||||||
|
lineh(x, y++, w, chr, color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lineh(x, y, w, chr, color);
|
||||||
|
linev(x + w - 1, y, h, chr, color);
|
||||||
|
lineh(x, y + h - 1, w, chr, color);
|
||||||
|
linev(x, y, h, chr, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void text(unsigned x, unsigned y, char* s, unsigned color)
|
||||||
|
{
|
||||||
|
unsigned ofs = (y * VWIDTH + x) * 2;
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
|
unsigned v = (color << 8) | *s++;
|
||||||
|
poke(VSEG, ofs, v);
|
||||||
|
ofs += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void number(unsigned x, unsigned y, unsigned n, unsigned color)
|
||||||
|
{
|
||||||
|
char s[6];
|
||||||
|
int i;
|
||||||
|
for (i = 4; i >= 0; --i)
|
||||||
|
{
|
||||||
|
s[i] = '0' + n % 10;
|
||||||
|
n /= 10;
|
||||||
|
}
|
||||||
|
s[5] = 0;
|
||||||
|
text(x, y, s, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RAND_MAX 0x7FFF
|
||||||
|
unsigned rand_next[2] = { 1, 0 };
|
||||||
|
int rand(void)
|
||||||
|
{
|
||||||
|
asm("mov eax, [_rand_next]\n"
|
||||||
|
"imul eax, eax, 1103515245\n"
|
||||||
|
"add eax, 12345\n"
|
||||||
|
"mov [_rand_next], eax\n"
|
||||||
|
"shr eax, 16\n"
|
||||||
|
"and ax, 0x7FFF\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void srand(unsigned seed)
|
||||||
|
{
|
||||||
|
rand_next[0] = seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void play(void);
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
unsigned ticks[2];
|
||||||
|
|
||||||
|
BiosSetGfxMode(VMODE);
|
||||||
|
|
||||||
|
text((VWIDTH - 20) / 2, VHEIGHT / 2, "Press a key to start", BACK_BLACK | FORE_BRIGHT_WHITE);
|
||||||
|
while (BiosKeyAvailable()) BiosReadKey(); // clear the keyboard buffer, just in case
|
||||||
|
BiosReadKey();
|
||||||
|
|
||||||
|
BiosGetTicks(ticks);
|
||||||
|
srand(ticks[0]);
|
||||||
|
|
||||||
|
play();
|
||||||
|
|
||||||
|
BiosSetGfxMode(3); // 80x25 color text mode
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void newtarget(void)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
unsigned bit = 0, i;
|
||||||
|
i = rand() % ((VWIDTH - 2) * (VHEIGHT - 2));
|
||||||
|
target[0] = 1 + i % (VWIDTH - 2);
|
||||||
|
target[1] = 1 + i / (VWIDTH - 2);
|
||||||
|
for (i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
if (target[0] == snake[i][0] &&
|
||||||
|
target[1] == snake[i][1])
|
||||||
|
{
|
||||||
|
bit = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bit)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
text(target[0], target[1], "$", BACK_GREEN | FORE_YELLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void play(void)
|
||||||
|
{
|
||||||
|
unsigned i, key;
|
||||||
|
|
||||||
|
// set up the field
|
||||||
|
box(0, 0, VWIDTH, VHEIGHT, ' ', BACK_GREEN | FORE_YELLOW, 1);
|
||||||
|
box(0, 0, VWIDTH, VHEIGHT, ' ', BACK_BROWN | FORE_BLACK, 0);
|
||||||
|
text((VWIDTH - 12) / 2, 0, "Score: ", BACK_BROWN | FORE_BLACK);
|
||||||
|
score = 0;
|
||||||
|
number((VWIDTH - 12) / 2 + 7, 0, score, BACK_BROWN | FORE_BLACK);
|
||||||
|
|
||||||
|
// set up the snake
|
||||||
|
for (length = 0; length < MIN_LENGTH; ++length)
|
||||||
|
{
|
||||||
|
snake[length][0] = VWIDTH / 2;
|
||||||
|
snake[length][1] = VHEIGHT - 1 - MIN_LENGTH + length;
|
||||||
|
text(snake[length][0], snake[length][1], "O", BACK_GREEN | FORE_YELLOW);
|
||||||
|
}
|
||||||
|
direction = KEY_UP;
|
||||||
|
|
||||||
|
// set up the target
|
||||||
|
newtarget();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
key = 0;
|
||||||
|
|
||||||
|
if (BiosKeyAvailable())
|
||||||
|
key = BiosReadKey();
|
||||||
|
|
||||||
|
delay(DELAY);
|
||||||
|
|
||||||
|
// update the direction
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case KEY_ESCAPE:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case KEY_LEFT:
|
||||||
|
if (direction != KEY_RIGHT)
|
||||||
|
direction = key;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHT:
|
||||||
|
if (direction != KEY_LEFT)
|
||||||
|
direction = key;
|
||||||
|
break;
|
||||||
|
case KEY_UP:
|
||||||
|
if (direction != KEY_DOWN)
|
||||||
|
direction = key;
|
||||||
|
break;
|
||||||
|
case KEY_DOWN:
|
||||||
|
if (direction != KEY_UP)
|
||||||
|
direction = key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move the snake
|
||||||
|
text(snake[length - 1][0], snake[length - 1][1], " ", BACK_GREEN | FORE_YELLOW); // erase the tail
|
||||||
|
for (i = length - 1; i > 0; --i) // update the body position
|
||||||
|
{
|
||||||
|
snake[i][0] = snake[i - 1][0];
|
||||||
|
snake[i][1] = snake[i - 1][1];
|
||||||
|
}
|
||||||
|
switch (direction) // update the head position
|
||||||
|
{
|
||||||
|
case KEY_LEFT:
|
||||||
|
--snake[0][0];
|
||||||
|
break;
|
||||||
|
case KEY_RIGHT:
|
||||||
|
++snake[0][0];
|
||||||
|
break;
|
||||||
|
case KEY_UP:
|
||||||
|
--snake[0][1];
|
||||||
|
break;
|
||||||
|
case KEY_DOWN:
|
||||||
|
++snake[0][1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
text(snake[0][0], snake[0][1], "O", BACK_GREEN | FORE_YELLOW); // draw the head
|
||||||
|
|
||||||
|
// check the head against the boundaries
|
||||||
|
if (snake[0][0] < 1 || snake[0][0] >= VWIDTH - 1 ||
|
||||||
|
snake[0][1] < 1 || snake[0][1] >= VHEIGHT - 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// check for self biting
|
||||||
|
{
|
||||||
|
unsigned bit = 0;
|
||||||
|
for (i = 1; i < length; ++i)
|
||||||
|
{
|
||||||
|
if (snake[0][0] == snake[i][0] &&
|
||||||
|
snake[0][1] == snake[i][1])
|
||||||
|
{
|
||||||
|
bit = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bit)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for hitting the target
|
||||||
|
if (snake[0][0] == target[0] &&
|
||||||
|
snake[0][1] == target[1])
|
||||||
|
{
|
||||||
|
// enlarge the snake
|
||||||
|
snake[length][0] = snake[length - 1][0];
|
||||||
|
snake[length][1] = snake[length - 1][1];
|
||||||
|
++length;
|
||||||
|
|
||||||
|
++score;
|
||||||
|
number((VWIDTH - 12) / 2 + 7, 0, score, BACK_BROWN | FORE_BLACK);
|
||||||
|
|
||||||
|
// set up the target
|
||||||
|
newtarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text((VWIDTH - 10) / 2, VHEIGHT / 2, "Game Over!", BACK_BLACK | FORE_BRIGHT_WHITE);
|
||||||
|
delay(1000);
|
||||||
|
while (BiosKeyAvailable()) BiosReadKey(); // clear the keyboard buffer
|
||||||
|
BiosReadKey();
|
||||||
|
}
|
BIN
res/freedos722.img
Normal file
BIN
res/freedos722.img
Normal file
Binary file not shown.
BIN
res/seabios.bin
Normal file
BIN
res/seabios.bin
Normal file
Binary file not shown.
BIN
res/vgabios.bin
Normal file
BIN
res/vgabios.bin
Normal file
Binary file not shown.
165
src/common/audio/z80worker.ts
Normal file
165
src/common/audio/z80worker.ts
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
|
||||||
|
Midway/Williams Audio Boards
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
6809 MEMORY MAP
|
||||||
|
|
||||||
|
Function Address R/W Data
|
||||||
|
---------------------------------------------------------------
|
||||||
|
Program RAM 0000-07FF R/W D0-D7
|
||||||
|
|
||||||
|
Music (YM-2151) 2000-2001 R/W D0-D7
|
||||||
|
|
||||||
|
6821 PIA 4000-4003 R/W D0-D7
|
||||||
|
|
||||||
|
HC55516 clock low, digit latch 6000 W D0
|
||||||
|
HC55516 clock high 6800 W xx
|
||||||
|
|
||||||
|
Bank select 7800 W D0-D2
|
||||||
|
|
||||||
|
Banked Program ROM 8000-FFFF R D0-D7
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import { RAM, newAddressDecoder } from "../emu";
|
||||||
|
|
||||||
|
declare function importScripts(path:string);
|
||||||
|
declare function postMessage(msg);
|
||||||
|
|
||||||
|
var cpu, ram, rom, membus, iobus;
|
||||||
|
var audio;
|
||||||
|
var command = 0;
|
||||||
|
var dac = 0;
|
||||||
|
var current_buffer;
|
||||||
|
var tstates;
|
||||||
|
var last_tstate;
|
||||||
|
|
||||||
|
var timer;
|
||||||
|
var curTime;
|
||||||
|
var timerPeriod = 20;
|
||||||
|
var sampleRate;
|
||||||
|
var numChannels = 2;
|
||||||
|
var bufferLength;
|
||||||
|
|
||||||
|
var cpuFrequency = 18432000/6; // 3.072 MHz
|
||||||
|
var cpuCyclesPerFrame = cpuFrequency/60;
|
||||||
|
var cpuAudioFactor = 32;
|
||||||
|
|
||||||
|
rom = new RAM(0x4000).mem;
|
||||||
|
// sample: [0xe,0x0,0x6,0x0,0x78,0xb9,0x30,0x06,0xa9,0xd3,0x00,0x04,0x18,0xf6,0x0c,0x79,0xd6,0xff,0x38,0xee,0x76,0x18,0xea];
|
||||||
|
rom.fill(0x76); // HALT opcodes
|
||||||
|
|
||||||
|
function fillBuffer() {
|
||||||
|
var t = tstates / cpuAudioFactor;
|
||||||
|
while (last_tstate < t) {
|
||||||
|
current_buffer[last_tstate*2] = dac;
|
||||||
|
current_buffer[last_tstate*2+1] = dac;
|
||||||
|
last_tstate++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
ram = new RAM(0x400);
|
||||||
|
membus = {
|
||||||
|
read: newAddressDecoder([
|
||||||
|
[0x0000, 0x3fff, 0x3fff, function(a) { return rom ? rom[a] : null; }],
|
||||||
|
[0x4000, 0x7fff, 0x3ff, function(a) { return ram.mem[a]; }]
|
||||||
|
]),
|
||||||
|
write: newAddressDecoder([
|
||||||
|
[0x4000, 0x7fff, 0x3ff, function(a,v) { ram.mem[a] = v; }],
|
||||||
|
]),
|
||||||
|
isContended: function() { return false; },
|
||||||
|
};
|
||||||
|
iobus = {
|
||||||
|
read: function(addr) {
|
||||||
|
return command & 0xff;
|
||||||
|
},
|
||||||
|
write: function(addr, val) {
|
||||||
|
dac = (val & 0xff) << 8;
|
||||||
|
fillBuffer();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cpu = new exports.Z80();
|
||||||
|
cpu.connectMemoryBus(membus);
|
||||||
|
cpu.connectIOBus(iobus);
|
||||||
|
current_buffer = new Int16Array(bufferLength);
|
||||||
|
console.log('started audio');
|
||||||
|
}
|
||||||
|
|
||||||
|
function timerCallback() {
|
||||||
|
tstates = 0;
|
||||||
|
last_tstate = 0;
|
||||||
|
var numStates = Math.floor(bufferLength * cpuAudioFactor / numChannels);
|
||||||
|
while (tstates < numStates) {
|
||||||
|
tstates += cpu.advanceInsn();
|
||||||
|
}
|
||||||
|
tstates = 0;
|
||||||
|
fillBuffer();
|
||||||
|
postMessage({samples:current_buffer});
|
||||||
|
if (!cpu.saveState().halted) {
|
||||||
|
curTime += timerPeriod;
|
||||||
|
var dt = curTime - new Date().getTime();
|
||||||
|
if (dt < 0) dt = 0;
|
||||||
|
timer = setTimeout(timerCallback, dt);
|
||||||
|
} else {
|
||||||
|
timer = 0;
|
||||||
|
//console.log("HALT @ " + cpu.getPC());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
if (!bufferLength) return;
|
||||||
|
cpu.reset();
|
||||||
|
if (!timer) {
|
||||||
|
curTime = new Date().getTime() - timerPeriod*4;
|
||||||
|
timerCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onmessage = function(e) {
|
||||||
|
if (e && e.data) {
|
||||||
|
if (e.data.command) {
|
||||||
|
command = e.data.command & 0xff;
|
||||||
|
reset();
|
||||||
|
} else if (e.data.sampleRate) {
|
||||||
|
console.log(e.data);
|
||||||
|
sampleRate = e.data.sampleRate;
|
||||||
|
bufferLength = numChannels*sampleRate*timerPeriod/1000;
|
||||||
|
start();
|
||||||
|
reset();
|
||||||
|
} else if (e.data.rom) {
|
||||||
|
rom = e.data.rom;
|
||||||
|
command = 0x0;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
0000 56 _main::
|
||||||
|
57 ;<stdin>:10:
|
||||||
|
0000 0E 00 [ 7] 58 ld c,#0x00
|
||||||
|
59 ;<stdin>:11:
|
||||||
|
0002 60 00111$:
|
||||||
|
0002 06 00 [ 7] 61 ld b,#0x00
|
||||||
|
0004 62 00104$:
|
||||||
|
0004 78 [ 4] 63 ld a,b
|
||||||
|
0005 B9 [ 4] 64 cp a,c
|
||||||
|
0006 30 06 [12] 65 jr NC,00107$
|
||||||
|
0008 A9 [ 4] 66 xor a, c
|
||||||
|
0009 D3 00 [11] 67 out (_dac),a
|
||||||
|
000B 04 [ 4] 68 inc b
|
||||||
|
000C 18 F6 [12] 69 jr 00104$
|
||||||
|
000E 70 00107$:
|
||||||
|
71 ;<stdin>:10:
|
||||||
|
000E 0C [ 4] 72 inc c
|
||||||
|
000F 79 [ 4] 73 ld a,c
|
||||||
|
0010 D6 FF [ 7] 74 sub a, #0xff
|
||||||
|
0012 38 EE [12] 75 jr C,00111$
|
||||||
|
76 ;<stdin>:13:
|
||||||
|
0014 18 EA [12] 77 jr _main
|
||||||
|
|
||||||
|
**/
|
@ -1193,7 +1193,7 @@ export abstract class BaseWASMMachine {
|
|||||||
}
|
}
|
||||||
async loadWASM() {
|
async loadWASM() {
|
||||||
// fetch WASM
|
// fetch WASM
|
||||||
var wasmResponse = await fetch('wasm/'+this.prefix+'.wasm');
|
var wasmResponse = await fetch('res/'+this.prefix+'.wasm');
|
||||||
var wasmBinary = await wasmResponse.arrayBuffer();
|
var wasmBinary = await wasmResponse.arrayBuffer();
|
||||||
var wasmCompiled = await WebAssembly.compile(wasmBinary);
|
var wasmCompiled = await WebAssembly.compile(wasmBinary);
|
||||||
var wasmResult = await WebAssembly.instantiate(wasmCompiled);
|
var wasmResult = await WebAssembly.instantiate(wasmCompiled);
|
||||||
@ -1201,7 +1201,7 @@ export abstract class BaseWASMMachine {
|
|||||||
this.exports = wasmResult.exports;
|
this.exports = wasmResult.exports;
|
||||||
this.exports.memory.grow(32);
|
this.exports.memory.grow(32);
|
||||||
// fetch BIOS
|
// fetch BIOS
|
||||||
var biosResponse = await fetch('wasm/'+this.prefix+'.bios');
|
var biosResponse = await fetch('res/'+this.prefix+'.bios');
|
||||||
var biosBinary = await biosResponse.arrayBuffer();
|
var biosBinary = await biosResponse.arrayBuffer();
|
||||||
const cBIOSPointer = this.exports.malloc(0x5000);
|
const cBIOSPointer = this.exports.malloc(0x5000);
|
||||||
const srcArray = new Uint8Array(biosBinary);
|
const srcArray = new Uint8Array(biosBinary);
|
||||||
|
@ -77,6 +77,8 @@ var TOOL_TO_SOURCE_STYLE = {
|
|||||||
'js': 'javascript',
|
'js': 'javascript',
|
||||||
'xasm6809': 'z80',
|
'xasm6809': 'z80',
|
||||||
'cmoc': 'text/x-csrc',
|
'cmoc': 'text/x-csrc',
|
||||||
|
'yasm': 'gas',
|
||||||
|
'smlrc': 'text/x-csrc',
|
||||||
}
|
}
|
||||||
|
|
||||||
function gaEvent(category:string, action:string, label?:string, value?:string) {
|
function gaEvent(category:string, action:string, label?:string, value?:string) {
|
||||||
@ -1496,11 +1498,11 @@ function addFileToProject(type, ext, linefn) {
|
|||||||
alertError("Can't insert text in this window -- switch back to main file");
|
alertError("Can't insert text in this window -- switch back to main file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: lwtools and smaller c
|
||||||
function _addIncludeFile() {
|
function _addIncludeFile() {
|
||||||
var fn = getCurrentMainFilename();
|
var fn = getCurrentMainFilename();
|
||||||
var tool = platform.getToolForFilename(fn);
|
var tool = platform.getToolForFilename(fn);
|
||||||
if (fn.endsWith(".c") || tool == 'sdcc' || tool == 'cc65')
|
if (fn.endsWith(".c") || tool == 'sdcc' || tool == 'cc65' || tool == 'cmoc' || tool == 'smlrc')
|
||||||
addFileToProject("Header", ".h", (s) => { return '#include "'+s+'"' });
|
addFileToProject("Header", ".h", (s) => { return '#include "'+s+'"' });
|
||||||
else if (tool == 'dasm' || tool == 'zmac')
|
else if (tool == 'dasm' || tool == 'zmac')
|
||||||
addFileToProject("Include File", ".inc", (s) => { return '\tinclude "'+s+'"' });
|
addFileToProject("Include File", ".inc", (s) => { return '\tinclude "'+s+'"' });
|
||||||
@ -1515,9 +1517,9 @@ function _addIncludeFile() {
|
|||||||
function _addLinkFile() {
|
function _addLinkFile() {
|
||||||
var fn = getCurrentMainFilename();
|
var fn = getCurrentMainFilename();
|
||||||
var tool = platform.getToolForFilename(fn);
|
var tool = platform.getToolForFilename(fn);
|
||||||
if (fn.endsWith(".c") || tool == 'sdcc' || tool == 'cc65')
|
if (fn.endsWith(".c") || tool == 'sdcc' || tool == 'cc65' || tool == 'cmoc' || tool == 'smlrc')
|
||||||
addFileToProject("Linked C (or .s)", ".c", (s) => { return '//#link "'+s+'"' });
|
addFileToProject("Linked C (or .s)", ".c", (s) => { return '//#link "'+s+'"' });
|
||||||
else if (fn.endsWith("asm") || fn.endsWith(".s") || tool == 'ca65')
|
else if (fn.endsWith("asm") || fn.endsWith(".s") || tool == 'ca65' || tool == 'lwasm')
|
||||||
addFileToProject("Linked ASM", ".inc", (s) => { return ';#link "'+s+'"' });
|
addFileToProject("Linked ASM", ".inc", (s) => { return ';#link "'+s+'"' });
|
||||||
else
|
else
|
||||||
alertError("Can't add linked file to this project type (" + tool + ")");
|
alertError("Can't add linked file to this project type (" + tool + ")");
|
||||||
|
@ -15,6 +15,7 @@ const APPLE2_PRESETS = [
|
|||||||
{id:'hgrtest.a', name:"HGR Test (ASM)"},
|
{id:'hgrtest.a', name:"HGR Test (ASM)"},
|
||||||
{id:'conway.a', name:"Conway's Game of Life (ASM)"},
|
{id:'conway.a', name:"Conway's Game of Life (ASM)"},
|
||||||
{id:'lz4fh.a', name:"LZ4FH Graphics Compression (ASM)"},
|
{id:'lz4fh.a', name:"LZ4FH Graphics Compression (ASM)"},
|
||||||
|
// {id:'zap.dasm', name:"ZAP! (ASM)"},
|
||||||
// {id:'tb_6502.s', name:'Tom Bombem (assembler game)'},
|
// {id:'tb_6502.s', name:'Tom Bombem (assembler game)'},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import { NullProbe, Probeable, ProbeAll } from "../common/devices";
|
|||||||
// http://vide.malban.de/help/vectrex-tutorial-ii-starting-with-bios
|
// http://vide.malban.de/help/vectrex-tutorial-ii-starting-with-bios
|
||||||
// http://www.playvectrex.com/designit/chrissalo/bios.asm
|
// http://www.playvectrex.com/designit/chrissalo/bios.asm
|
||||||
// https://www.6809.org.uk/asm6809/doc/asm6809.shtml
|
// https://www.6809.org.uk/asm6809/doc/asm6809.shtml
|
||||||
|
// http://www.playvectrex.com/
|
||||||
|
|
||||||
var VECTREX_PRESETS = [
|
var VECTREX_PRESETS = [
|
||||||
{ id: 'hello.xasm', name: 'Hello World (ASM)' },
|
{ id: 'hello.xasm', name: 'Hello World (ASM)' },
|
||||||
|
151
src/platform/x86.ts
Normal file
151
src/platform/x86.ts
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
|
||||||
|
import { Platform, Base6502Platform, BaseMAMEPlatform, getOpcodeMetadata_6502, cpuStateToLongString_6502, getToolForFilename_6502, dumpStackToString, BaseDebugPlatform } from "../common/baseplatform";
|
||||||
|
import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, dumpRAM, KeyFlags, EmuHalt, ControllerPoller } from "../common/emu";
|
||||||
|
import { hex, lpad, lzgmini, byteArrayToString } from "../common/util";
|
||||||
|
import { CodeAnalyzer_nes } from "../common/analysis";
|
||||||
|
import { SampleAudio } from "../common/audio";
|
||||||
|
import { ProbeRecorder } from "../common/recorder";
|
||||||
|
import { NullProbe, Probeable, ProbeAll } from "../common/devices";
|
||||||
|
import { loadScript } from "../ide/ui";
|
||||||
|
|
||||||
|
// PC emulator: https://github.com/copy/v86
|
||||||
|
|
||||||
|
declare var V86Starter : any;
|
||||||
|
declare var V86 : any;
|
||||||
|
declare var CPU : any;
|
||||||
|
declare var fatfs : any;
|
||||||
|
|
||||||
|
const PC_PRESETS = [
|
||||||
|
{id:'hello.asm', name:'Hello World (ASM)'},
|
||||||
|
{id:'mandelg.asm', name:'Mandelbrot (ASM)'},
|
||||||
|
{id:'snake.c', name:'Snake Game (C)'},
|
||||||
|
];
|
||||||
|
|
||||||
|
class FATFSArrayBufferDriver {
|
||||||
|
buffer : ArrayBuffer;
|
||||||
|
data : DataView;
|
||||||
|
sectorSize : number;
|
||||||
|
numSectors : number;
|
||||||
|
constructor(buffer : ArrayBuffer) {
|
||||||
|
this.buffer = buffer;
|
||||||
|
this.data = new DataView(this.buffer);
|
||||||
|
this.sectorSize = 512;
|
||||||
|
this.numSectors = this.buffer.byteLength / this.sectorSize;
|
||||||
|
}
|
||||||
|
readSectors(sector, dest, cb) {
|
||||||
|
var ofs = this.sectorSize * sector;
|
||||||
|
for (var i=0; i<dest.length; i++) {
|
||||||
|
dest[i] = this.data.getUint8(i + ofs);
|
||||||
|
}
|
||||||
|
//console.log('read', sector, dest, cb);
|
||||||
|
cb(null);
|
||||||
|
}
|
||||||
|
writeSectors(sector, data, cb) {
|
||||||
|
var ofs = this.sectorSize * sector;
|
||||||
|
for (var i=0; i<data.length; i++) {
|
||||||
|
this.data.setUint8(i + ofs, data[i]);
|
||||||
|
}
|
||||||
|
//console.log('write', sector, data, cb);
|
||||||
|
cb(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class X86PCPlatform implements Platform {
|
||||||
|
|
||||||
|
mainElement;
|
||||||
|
video;
|
||||||
|
|
||||||
|
emulator;
|
||||||
|
v86;
|
||||||
|
fda_image;
|
||||||
|
fda_driver;
|
||||||
|
fda_fs;
|
||||||
|
|
||||||
|
constructor(mainElement) {
|
||||||
|
//super();
|
||||||
|
this.mainElement = mainElement;
|
||||||
|
}
|
||||||
|
getToolForFilename(s: string): string {
|
||||||
|
if (s.endsWith(".c")) return "smlrc";
|
||||||
|
return "yasm";
|
||||||
|
}
|
||||||
|
getDefaultExtension(): string {
|
||||||
|
return "asm";
|
||||||
|
}
|
||||||
|
getPresets() {
|
||||||
|
return PC_PRESETS;
|
||||||
|
}
|
||||||
|
pause(): void {
|
||||||
|
if (this.isRunning()) this.emulator.stop();
|
||||||
|
}
|
||||||
|
resume(): void {
|
||||||
|
if (!this.isRunning()) this.emulator.run();
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
this.emulator.restart();
|
||||||
|
}
|
||||||
|
isRunning() {
|
||||||
|
return this.emulator.is_running();
|
||||||
|
}
|
||||||
|
loadROM(title: string, rom: any) {
|
||||||
|
this.fda_fs.writeFile('main.exe', rom, {encoding:'binary'}, (e) => {
|
||||||
|
if (e) throw e;
|
||||||
|
else this.reset();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async start() {
|
||||||
|
await loadScript('./lib/libv86.js');
|
||||||
|
await loadScript('./lib/fatfs.js');
|
||||||
|
|
||||||
|
this.video = new RasterVideo(this.mainElement,640,480,{overscan:false});
|
||||||
|
this.video.create();
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList.add('pc-console');
|
||||||
|
div.classList.add('emuvideo');
|
||||||
|
this.mainElement.appendChild(div);
|
||||||
|
|
||||||
|
this.emulator = new V86Starter({
|
||||||
|
memory_size: 2 * 1024 * 1024,
|
||||||
|
vga_memory_size: 1 * 1024 * 1024,
|
||||||
|
screen_container: this.mainElement,
|
||||||
|
bios: {
|
||||||
|
url: "./res/seabios.bin",
|
||||||
|
},
|
||||||
|
vga_bios: {
|
||||||
|
url: "./res/vgabios.bin",
|
||||||
|
},
|
||||||
|
fda: {
|
||||||
|
url: "./res/freedos722.img",
|
||||||
|
size: 737280,
|
||||||
|
},
|
||||||
|
autostart: true,
|
||||||
|
});
|
||||||
|
return new Promise<void>( (resolve, reject) => {
|
||||||
|
this.emulator.add_listener("emulator-ready", () => {
|
||||||
|
console.log("emulator ready");
|
||||||
|
console.log(this.emulator);
|
||||||
|
this.v86 = this.emulator.v86;
|
||||||
|
this.fda_image = this.v86.cpu.devices.fdc.fda_image;
|
||||||
|
this.fda_driver = new FATFSArrayBufferDriver(this.fda_image.buffer);
|
||||||
|
this.fda_fs = fatfs.createFileSystem(this.fda_driver);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
readAddress(addr:number) {
|
||||||
|
return this.v86.cpu.mem8[addr];
|
||||||
|
}
|
||||||
|
getMemoryMap() { return { main:[
|
||||||
|
{name:'Real Mode IVT',start:0x0,size:0x400,type:'ram'},
|
||||||
|
{name:'BIOS Data Area',start:0x400,size:0x100,type:'ram'},
|
||||||
|
{name:'User RAM',start:0x500,size:0x80000-0x500,type:'ram'},
|
||||||
|
{name:'Extended BIOS Data Area',start:0x80000,size:0x20000,type:'ram'},
|
||||||
|
{name:'Video RAM',start:0xa0000,size:0x20000,type:'ram'},
|
||||||
|
{name:'Video BIOS',start:0xc0000,size:0x8000,type:'rom'},
|
||||||
|
{name:'BIOS Expansions',start:0xc8000,size:0x28000,type:'rom'},
|
||||||
|
{name:'PC BIOS',start:0xf0000,size:0x10000,type:'rom'},
|
||||||
|
] } };
|
||||||
|
}
|
||||||
|
|
||||||
|
PLATFORMS['x86'] = X86PCPlatform;
|
22
src/worker/wasm/smlrc.js
Normal file
22
src/worker/wasm/smlrc.js
Normal file
File diff suppressed because one or more lines are too long
BIN
src/worker/wasm/smlrc.wasm
Normal file
BIN
src/worker/wasm/smlrc.wasm
Normal file
Binary file not shown.
5051
src/worker/wasm/yasm.js
Normal file
5051
src/worker/wasm/yasm.js
Normal file
File diff suppressed because it is too large
Load Diff
BIN
src/worker/wasm/yasm.wasm
Normal file
BIN
src/worker/wasm/yasm.wasm
Normal file
Binary file not shown.
@ -259,6 +259,8 @@ var PLATFORM_PARAMS = {
|
|||||||
extra_compile_args: ['--vectrex'],
|
extra_compile_args: ['--vectrex'],
|
||||||
extra_link_args: ['-svectrex.scr', '-lcmoc-crt-vec', '-lcmoc-std-vec'],
|
extra_link_args: ['-svectrex.scr', '-lcmoc-crt-vec', '-lcmoc-std-vec'],
|
||||||
},
|
},
|
||||||
|
'x86': {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PLATFORM_PARAMS['sms-sms-libcv'] = PLATFORM_PARAMS['sms-sg1000-libcv'];
|
PLATFORM_PARAMS['sms-sms-libcv'] = PLATFORM_PARAMS['sms-sg1000-libcv'];
|
||||||
@ -2256,6 +2258,123 @@ function linkLWLINK(step:BuildStep) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// http://www.techhelpmanual.com/829-program_startup___exit.html
|
||||||
|
function compileSmallerC(step:BuildStep) {
|
||||||
|
loadNative("smlrc");
|
||||||
|
var params = step.params;
|
||||||
|
// stderr
|
||||||
|
var re_err1 = /^Error in "[/]*(.+)" [(](\d+):(\d+)[)]/;
|
||||||
|
var errors : WorkerError[] = [];
|
||||||
|
var errline = 0;
|
||||||
|
var errpath = step.path;
|
||||||
|
function match_fn(s) {
|
||||||
|
var matches = re_err1.exec(s);
|
||||||
|
if (matches) {
|
||||||
|
errline = parseInt(matches[2]);
|
||||||
|
errpath = matches[1];
|
||||||
|
} else {
|
||||||
|
errors.push({
|
||||||
|
line:errline,
|
||||||
|
msg:s,
|
||||||
|
path:errpath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gatherFiles(step, {mainFilePath:"main.c"});
|
||||||
|
var destpath = step.prefix + '.asm';
|
||||||
|
if (staleFiles(step, [destpath])) {
|
||||||
|
var args = ['-seg16',
|
||||||
|
//'-nobss',
|
||||||
|
'-no-externs',
|
||||||
|
step.path, destpath];
|
||||||
|
var smlrc = emglobal.smlrc({
|
||||||
|
instantiateWasm: moduleInstFn('smlrc'),
|
||||||
|
noInitialRun:true,
|
||||||
|
//logReadFiles:true,
|
||||||
|
print:match_fn,
|
||||||
|
printErr:match_fn,
|
||||||
|
});
|
||||||
|
// load source file and preprocess
|
||||||
|
var code = getWorkFileAsString(step.path);
|
||||||
|
var preproc = preprocessMCPP(step, null);
|
||||||
|
if (preproc.errors) return preproc;
|
||||||
|
else code = preproc.code;
|
||||||
|
// set up filesystem
|
||||||
|
var FS = smlrc['FS'];
|
||||||
|
//setupFS(FS, '65-'+getRootBasePlatform(step.platform));
|
||||||
|
populateFiles(step, FS);
|
||||||
|
FS.writeFile(step.path, code);
|
||||||
|
fixParamsWithDefines(step.path, params);
|
||||||
|
if (params.extra_compile_args) {
|
||||||
|
args.unshift.apply(args, params.extra_compile_args);
|
||||||
|
}
|
||||||
|
execMain(step, smlrc, args);
|
||||||
|
if (errors.length)
|
||||||
|
return {errors:errors};
|
||||||
|
var asmout = FS.readFile(destpath, {encoding:'utf8'});
|
||||||
|
putWorkFile(destpath, asmout);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
nexttool:"yasm",
|
||||||
|
path:destpath,
|
||||||
|
args:[destpath],
|
||||||
|
files:[destpath],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function assembleYASM(step:BuildStep) {
|
||||||
|
loadNative("yasm");
|
||||||
|
var errors = [];
|
||||||
|
gatherFiles(step, {mainFilePath:"main.asm"});
|
||||||
|
var objpath = step.prefix+".exe";
|
||||||
|
var lstpath = step.prefix+".lst";
|
||||||
|
var mappath = step.prefix+".map";
|
||||||
|
if (staleFiles(step, [objpath])) {
|
||||||
|
var args = [ '-X', 'vc',
|
||||||
|
'-a', 'x86', '-f', 'dosexe', '-p', 'nasm',
|
||||||
|
'-D', 'freedos',
|
||||||
|
//'-g', 'dwarf2',
|
||||||
|
//'-I/share/asminc',
|
||||||
|
'-o', objpath, '-l', lstpath, '--mapfile='+mappath,
|
||||||
|
step.path];
|
||||||
|
// return yasm/*.ready*/
|
||||||
|
var YASM = emglobal.yasm({
|
||||||
|
instantiateWasm: moduleInstFn('yasm'),
|
||||||
|
noInitialRun:true,
|
||||||
|
//logReadFiles:true,
|
||||||
|
print:print_fn,
|
||||||
|
printErr:msvcErrorMatcher(errors),
|
||||||
|
});
|
||||||
|
var FS = YASM['FS'];
|
||||||
|
//setupFS(FS, '65-'+getRootBasePlatform(step.platform));
|
||||||
|
populateFiles(step, FS);
|
||||||
|
//fixParamsWithDefines(step.path, step.params);
|
||||||
|
execMain(step, YASM, args);
|
||||||
|
if (errors.length)
|
||||||
|
return {errors:errors};
|
||||||
|
var objout, lstout, mapout;
|
||||||
|
objout = FS.readFile(objpath, {encoding:'binary'});
|
||||||
|
lstout = FS.readFile(lstpath, {encoding:'utf8'});
|
||||||
|
mapout = FS.readFile(mappath, {encoding:'utf8'});
|
||||||
|
putWorkFile(objpath, objout);
|
||||||
|
putWorkFile(lstpath, lstout);
|
||||||
|
//putWorkFile(mappath, mapout);
|
||||||
|
if (!anyTargetChanged(step, [objpath]))
|
||||||
|
return;
|
||||||
|
var symbolmap = {};
|
||||||
|
var segments = [];
|
||||||
|
var lines = parseListing(lstout, /\s*(\d+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+(.+)/i, 1, 2, 3);
|
||||||
|
var listings : CodeListingMap = {};
|
||||||
|
listings[lstpath] = {lines:lines, text:lstout};
|
||||||
|
return {
|
||||||
|
output:objout, //.slice(0),
|
||||||
|
listings:listings,
|
||||||
|
errors:errors,
|
||||||
|
symbolmap:symbolmap,
|
||||||
|
segments:segments
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
|
|
||||||
var TOOLS = {
|
var TOOLS = {
|
||||||
@ -2281,6 +2400,8 @@ var TOOLS = {
|
|||||||
'jsasm': compileJSASMStep,
|
'jsasm': compileJSASMStep,
|
||||||
'zmac': assembleZMAC,
|
'zmac': assembleZMAC,
|
||||||
'nesasm': assembleNESASM,
|
'nesasm': assembleNESASM,
|
||||||
|
'smlrc': compileSmallerC,
|
||||||
|
'yasm': assembleYASM,
|
||||||
'bataribasic': compileBatariBasic,
|
'bataribasic': compileBatariBasic,
|
||||||
'markdown': translateShowdown,
|
'markdown': translateShowdown,
|
||||||
'js': runJavascript,
|
'js': runJavascript,
|
||||||
|
@ -11,6 +11,8 @@ global.onmessage({data:{preload:'cc65', platform:'nes'}});
|
|||||||
global.onmessage({data:{preload:'ca65', platform:'nes'}});
|
global.onmessage({data:{preload:'ca65', platform:'nes'}});
|
||||||
global.onmessage({data:{preload:'cc65', platform:'apple2'}});
|
global.onmessage({data:{preload:'cc65', platform:'apple2'}});
|
||||||
global.onmessage({data:{preload:'ca65', platform:'apple2'}});
|
global.onmessage({data:{preload:'ca65', platform:'apple2'}});
|
||||||
|
global.onmessage({data:{preload:'cc65', platform:'c64'}});
|
||||||
|
global.onmessage({data:{preload:'ca65', platform:'c64'}});
|
||||||
global.onmessage({data:{preload:'sdcc'}});
|
global.onmessage({data:{preload:'sdcc'}});
|
||||||
|
|
||||||
// TODO: check msg against spec
|
// TODO: check msg against spec
|
||||||
@ -313,11 +315,10 @@ describe('Worker', function() {
|
|||||||
it('should assemble CA65', function(done) {
|
it('should assemble CA65', function(done) {
|
||||||
compile('ca65', ';#define LIBARGS ,\n\t.segment "HEADER"\n\t.segment "STARTUP"\n\t.segment "CHARS"\n\t.segment "VECTORS"\n\t.segment "SAMPLES"\n\t.segment "CODE"\n\tlda #0\n\tsta $1\n', 'nes', done, 131088, 2);
|
compile('ca65', ';#define LIBARGS ,\n\t.segment "HEADER"\n\t.segment "STARTUP"\n\t.segment "CHARS"\n\t.segment "VECTORS"\n\t.segment "SAMPLES"\n\t.segment "CODE"\n\tlda #0\n\tsta $1\n', 'nes', done, 131088, 2);
|
||||||
});
|
});
|
||||||
/* TODO
|
|
||||||
it('should compile C64 cc65 skeleton', function(done) {
|
it('should compile C64 cc65 skeleton', function(done) {
|
||||||
var csource = ab2str(fs.readFileSync('presets/c64/skeleton.cc65'));
|
var csource = ab2str(fs.readFileSync('presets/c64/skeleton.cc65'));
|
||||||
compile('cc65', csource, 'c64.wasm', done, 49152, 80, 0);
|
compile('cc65', csource, 'c64.wasm', done, 2753, 2, 0);
|
||||||
});
|
});
|
||||||
*/
|
// TODO: vectrex, x86
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user