123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702 |
- <!doctype html>
- <title>v86: sectorc</title>
- <script src="../build/libv86.js"></script>
- <script>
- "use strict";
- window.onload = function()
- {
- const libc = `int tmp1;
- int tmp2;
- void shutdown()
- {
- /* Shutdown via APM: coded in asm machine code directly */
- // Check for APM
- // | mov ah,0x53; mov al,0x00; xor bx,bx; int 0x15; jc error
- asm 180; asm 83; asm 176; asm 0; asm 49; asm 219;
- asm 205; asm 21; asm 114; asm 55;
- // Disconnect from any APM interface
- // | mov ah,0x53; mov al,0x04; xor bx,bx; int 0x15
- // | jc maybe_error; jmp no_error
- asm 180; asm 83; asm 176; asm 4; asm 49; asm 219;
- asm 205; asm 21; asm 114; asm 2; asm 235; asm 5;
- // Label: maybe_error
- // | cmp ah,0x03; jne error
- asm 128; asm 252; asm 3; asm 117; asm 38;
- // Label: no_error
- // Connect to APM interface
- // | mov ah,0x53; mov al,0x01; xor bx,bx; int 0x15; jc error
- asm 180; asm 83; asm 176; asm 1; asm 49; asm 219;
- asm 205; asm 21; asm 114; asm 28;
- // Enable power management for all devices
- // | mov ah,0x53; mov al,0x08; mov bx,0x0001; mov cx,0x0001
- // | int 0x15; jc error
- asm 180; asm 83; asm 176; asm 8;
- asm 187; asm 1; asm 0; asm 185; asm 1; asm 0;
- asm 205; asm 21; asm 114; asm 14;
- // Set the power state for all devices
- // | mov ah,0x53; mov al,0x7; mov bx,0x0001; mov cx,0x0003
- // | int 0x15; jc error
- asm 180; asm 83; asm 176; asm 7;
- asm 187; asm 1; asm 0; asm 185; asm 3; asm 0;
- asm 205; asm 21; asm 114; asm 0;
- // Label: error
- // | hlt; jmp error
- asm 244; asm 235; asm 253;
- }
- int store_far_seg;
- int store_far_off;
- int store_far_val;
- void store_far()
- {
- // mov es, store_far_seg
- store_far_seg = store_far_seg;
- asm 142; asm 192;
- // mov si, store_far_off
- store_far_off = store_far_off;
- asm 137; asm 198;
- // mov es:[si], store_far_val
- store_far_val = store_far_val;
- asm 38; asm 137; asm 4;
- }
- int div10_unsigned_n;
- int div10_unsigned_q;
- int div10_unsigned_r;
- void div10_unsigned()
- {
- /* Taken from "Hacker's Delight", modified to "fit your screen" */
- tmp1 = ( div10_unsigned_n >> 1 ) & 32767; // unsigned
- tmp2 = ( div10_unsigned_n >> 2 ) & 16383; // unsigned
- div10_unsigned_q = tmp1 + tmp2;
- tmp1 = ( div10_unsigned_q >> 4 ) & 4095; // unsigned
- div10_unsigned_q = div10_unsigned_q + tmp1;
- tmp1 = ( div10_unsigned_q >> 8 ) & 255; // unsigned
- div10_unsigned_q = div10_unsigned_q + tmp1;
- div10_unsigned_q = ( div10_unsigned_q >> 3 ) & 8191; // unsigned
- div10_unsigned_r = div10_unsigned_n
- - ( ( div10_unsigned_q << 3 ) + ( div10_unsigned_q << 1 ) );
- if( div10_unsigned_r > 9 ){
- div10_unsigned_q = div10_unsigned_q + 1;
- div10_unsigned_r = div10_unsigned_r - 10;
- }
- }
- int print_ch;
- void print_char()
- {
- /* Implement print char via serial port bios function accessed via int 0x14 */
- print_ch = print_ch; // mov ax,[&print_ch]
- asm 180; asm 1; // mov ah,1
- asm 186; asm 0; asm 0 ; // mov dx,0
- asm 205; asm 20; // int 0x14
- }
- // uses 'print_ch'
- void print_newline()
- {
- print_ch = 10;
- print_char();
- }
- int print_num; // input
- int print_u16_bufptr;
- int print_u16_cur;
- void print_u16()
- {
- print_u16_bufptr = 30000; // buffer for ascii digits
- if( print_num == 0 ){
- print_ch = 48;
- print_char();
- }
- print_u16_cur = print_num;
- while( print_u16_cur != 0 ){
- div10_unsigned_n = print_u16_cur;
- div10_unsigned();
- *(int*) print_u16_bufptr = div10_unsigned_r;
- print_u16_bufptr = print_u16_bufptr + 1;
- print_u16_cur = div10_unsigned_q;
- }
- while( print_u16_bufptr != 30000 ){ // emit them in reverse over
- print_u16_bufptr = print_u16_bufptr - 1;
- print_ch = ( *(int*) print_u16_bufptr & 255 ) + 48;
- print_char();
- }
- }
- // uses 'print_num' and 'print_ch'
- void print_i16()
- {
- if( print_num < 0 ){
- print_ch = 45; print_char(); // '-'
- print_num = 0 - print_num;
- }
- print_u16();
- }
- void vga_init()
- {
- // mov ah,0; mov al,0x13; int 0x10
- asm 180; asm 0; asm 176; asm 19; asm 205; asm 16;
- }
- void vga_clear()
- {
- // push di; xor di,di; mov bx,0xa000; mov es,bx;
- // mov cx,0x7d00; xor ax,ax; rep stos; pop di
- asm 87 ; asm 49 ; asm 255; asm 187; asm 0; asm 160;
- asm 142; asm 195; asm 185; asm 0; asm 125; asm 49;
- asm 192; asm 243; asm 171; asm 95;
- }
- int pixel_x;
- int pixel_y;
- void vga_set_pixel()
- {
- // need to multiply pixel_y by 320 = 256 + 64
- // use 'tmp1' for pixel index
- tmp1 = ( ( pixel_y << 8 ) + ( pixel_y << 6 ) ) + pixel_x;
- // store to 0xa000:pixel_idx
- // mov bx,0xa000; mov es,bx; mov bx,ax; mov BYTE PTR es:[bx],0xf
- tmp1 = tmp1;
- asm 187; asm 0; asm 160; asm 142; asm 195;
- asm 137; asm 195; asm 38; asm 198; asm 7; asm 15;
- }
- int port_num;
- int port_val;
- void port_inb()
- {
- dx = port_num;
- // mov dx,WORD PTR [0x464]; in al,dx
- asm 139; asm 22; asm 160; asm 4; asm 236;
- // mov WORD PTR [0x464],ax
- asm 137; asm 6; asm 100; asm 4;
- port_val = ax;
- }
- void port_inw()
- {
- // mov dx,WORD PTR [0x464]; in ax,dx
- dx = port_num;
- asm 139; asm 22; asm 160; asm 4; asm 237;
- // mov WORD PTR [0x464],ax
- asm 137; asm 6; asm 100; asm 4;
- port_val = ax;
- }
- void port_outb()
- {
- dx = port_num;
- ax = port_val;
- // mov dx,WORD PTR [0x464]
- asm 139; asm 22; asm 160; asm 4;
- // mov ax,WORD PTR [0x464]
- asm 139; asm 6; asm 100; asm 4;
- // outb dx,al
- asm 238;
- }
- void port_outw()
- {
- dx = port_num;
- ax = port_val;
- // mov dx,WORD PTR [0x464]
- asm 139; asm 22; asm 160; asm 4;
- // mov ax,WORD PTR [0x464]
- asm 139; asm 6; asm 100; asm 4;
- // outb dx,al
- asm 239;
- }
- void dump_code_segment_and_shutdown()
- {
- /* NOTE: This code is in a different segment from data, and our compiled pointer accesses
- do not leave the data segment, so we need a little machine code to grab data from the
- code segment and stash it in a variable for C */
- i = 0;
- while( i < 8192 ){ /* Just assuming 8K is enough.. might not be true */
- // (put "i" in ax); mov si,ax; mov ax,cs:[si]; mov [&a],ax
- i = i; asm 137; asm 198; asm 46; asm 139; asm 4; asm 137; asm 133; asm 98; asm 0;
- print_ch = a;
- print_char();
- i = i + 1;
- }
- shutdown();
- }
- `;
- const start = `void _start()
- {
- main();
- shutdown();
- }
- `;
- const hello = `int buf;
- int ptr;
- int len;
- void vga_write()
- {
- /* Text vga is located at b800:0000 */
- store_far_seg = 47104; // segment: 0xb800
- store_far_off = idx << 1;
- store_far_val = ( 15 << 8 ) | ( ch & 255 ); // white fg and black bg
- store_far();
- }
- int x_off;
- int y_off;
- void vga_write_ch()
- {
- if( ch != 10 ){
- idx = y_off + x_off;
- vga_write();
- x_off = x_off + 1;
- }
- if( ( ch == 10 ) | ( x_off == 80 ) ){
- y_off = y_off + 80;
- x_off = 0;
- }
- }
- int idx;
- void vga_clear()
- {
- idx = 0;
- while( idx < 2000 ){ // 80x25
- ch = 32; // char: ' '
- vga_write();
- idx = idx + 1;
- }
- pos = 0;
- }
- void main()
- {
- // dump_code_segment_and_shutdown();
- vga_clear();
- ch = 72; vga_write_ch();
- ch = 101; vga_write_ch();
- ch = 108; vga_write_ch();
- ch = 108; vga_write_ch();
- ch = 111; vga_write_ch();
- ch = 10; vga_write_ch();
- ch = 32; vga_write_ch();
- ch = 102; vga_write_ch();
- ch = 114; vga_write_ch();
- ch = 111; vga_write_ch();
- ch = 109; vga_write_ch();
- ch = 10; vga_write_ch();
- ch = 32; vga_write_ch();
- ch = 32; vga_write_ch();
- ch = 83; vga_write_ch();
- ch = 101; vga_write_ch();
- ch = 99; vga_write_ch();
- ch = 116; vga_write_ch();
- ch = 111; vga_write_ch();
- ch = 114; vga_write_ch();
- ch = 67; vga_write_ch();
- ch = 10; vga_write_ch();
- ch = 32; vga_write_ch();
- ch = 32; vga_write_ch();
- ch = 32; vga_write_ch();
- i = 0;
- while( i < 10 ){
- ch = 33; vga_write_ch();
- i = i + 1;
- }
- while( 1 ){ }
- }
- `;
- const sinwave = `/* A Sine-wave Animation
- Math time:
- ---------------------------
- Along the range [0, pi] we can approximate sin(x) very crudely with a 2nd order quadratic
- That is: y = a * x^2 + b * x + c
- Three unknowns need three constraints, so picking the easy ones:
- x = 0, y = 0
- x = pi/2, y = 1
- x = pi, y = 0
- Solving the linear system:
- | 0 0 1 | | a | | 0 |
- | pi^2/4 pi/2 1 | * | b | = | 1 |
- | pi^2 pi 1 | | c | | 0 |
- We get:
- a = -4 / pi^2
- b = 4 / pi
- c = 0
- And:
- y = 4x(pi - x)/(pi^2)
- Engineering time:
- ---------------------------
- We are working with a 320x200 vga. We also don't have floating-point math. So, the
- goal here is to do all the math in integer screen coordinates and accept some pixel
- approximation error.
- First, we want to center the wave in the middle, y = 100
- We'll let y vary +-50 pixels to remain on the screen, so [50, 150]
- We want to show an entire cycle (2pi) on the x-axis, so *50 gives us [0, ~314]
- This implies that the "x-origin" is at x = 157
- Substituting in everything, we get:
- y ~= 100 + x*(157 - x)/125
- The division by 125 is problematic as we don't have division. But luckily 128 is close enough.
- Thus, we get:
- y ~= 100 + (x*(157 - x)) >> 7
- The rest is just adjusting for the [0, pi] range reduction by negating the approximation
- along [pi, 2pi]
- NOTE: the screen coordinate system is upside-down and I don't bother to correct for that.
- it simply means that the animation starts at a +pi phase offset
- */
- int y;
- int x;
- int x_0;
- void sin_positive_approx()
- {
- y = ( x_0 * ( 157 - x_0 ) ) >> 7;
- }
- void sin()
- {
- x_0 = x;
- while( x_0 > 314 ){
- x_0 = x_0 - 314;
- }
- if( x_0 <= 157 ){
- sin_positive_approx();
- }
- if( x_0 > 157 ){
- x_0 = x_0 - 157;
- sin_positive_approx();
- y = 0 - y;
- }
- y = 100 + y;
- }
- int offset;
- int x_end;
- void draw_sine_wave()
- {
- x = offset;
- x_end = x + 314;
- while( x <= x_end ){
- sin();
- pixel_x = x - offset;
- pixel_y = y;
- vga_set_pixel();
- x = x + 1;
- }
- }
- int v_1;
- int v_2;
- void delay()
- {
- v_1 = 0;
- while( v_1 < 50 ){
- v_2 = 0;
- while( v_2 < 10000 ){
- v_2 = v_2 + 1;
- }
- v_1 = v_1 + 1;
- }
- }
- void main()
- {
- vga_init();
- offset = 0;
- while( 1 ){
- vga_clear();
- draw_sine_wave();
- delay();
- offset = offset + 1;
- if( offset >= 314 ){ // mod the value to avoid 2^16 integer overflow
- offset = offset - 314;
- }
- }
- }
- `;
- const twinkle = `/* References:
- http://muruganad.com/8086/8086-assembly-language-program-to-play-sound-using-pc-speaker.html
- https://en.wikipedia.org/wiki/Twinkle,_Twinkle,_Little_Star
- */
- void delay_1()
- {
- v_1 = 0;
- while( v_1 < 4000 ){
- v_2 = 0;
- while( v_2 < 10000 ){
- v_2 = v_2 + 1;
- }
- v_1 = v_1 + 1;
- }
- }
- void delay_2()
- {
- v_1 = 0;
- while( v_1 < 300 ){
- v_2 = 0;
- while( v_2 < 10000 ){
- v_2 = v_2 + 1;
- }
- v_1 = v_1 + 1;
- }
- }
- void audio_init()
- {
- // Configure PIC2 mode
- port_num = 67;
- port_val = 182;
- port_outb();
- }
- void audio_enable()
- {
- // Set bits 0 and 1 to enable
- port_num = 97;
- port_inb();
- port_val = port_val | 3;
- port_outb();
- }
- void audio_disable()
- {
- // Clear bits 0 and 1 to enable
- port_num = 97;
- port_inb();
- port_val = port_val & 65532;
- port_outb();
- }
- int audio_freq;
- void audio_freq_set()
- {
- // Set frequency
- port_num = 66;
- port_val = audio_freq & 255;
- port_outb();
- port_val = ( audio_freq >> 8 ) & 255;
- port_outb();
- }
- int note;
- void play_quarter_note()
- {
- audio_freq = note;
- audio_freq_set();
- audio_enable();
- delay_1();
- audio_disable();
- delay_2();
- }
- void play_half_note()
- {
- audio_freq = note;
- audio_freq_set();
- audio_enable();
- delay_1();
- delay_1();
- audio_disable();
- delay_2();
- }
- void play_section_1()
- {
- note = C; play_quarter_note();
- note = C; play_quarter_note();
- note = G; play_quarter_note();
- note = G; play_quarter_note();
- note = A; play_quarter_note();
- note = A; play_quarter_note();
- note = G; play_half_note();
- note = F; play_quarter_note();
- note = F; play_quarter_note();
- note = E; play_quarter_note();
- note = E; play_quarter_note();
- note = D; play_quarter_note();
- note = D; play_quarter_note();
- note = C; play_half_note();
- }
- void play_section_2()
- {
- note = G; play_quarter_note();
- note = G; play_quarter_note();
- note = F; play_quarter_note();
- note = F; play_quarter_note();
- note = E; play_quarter_note();
- note = E; play_quarter_note();
- note = D; play_half_note();
- note = G; play_quarter_note();
- note = G; play_quarter_note();
- note = F; play_quarter_note();
- note = F; play_quarter_note();
- note = E; play_quarter_note();
- note = E; play_quarter_note();
- note = D; play_half_note();
- }
- void main()
- {
- audio_init();
- audio_enable();
- C = 4560;
- D = 4063;
- E = 3619;
- F = 3416;
- G = 3043;
- A = 2711;
- play_section_1();
- play_section_2();
- play_section_1();
- audio_disable();
- }
- `;
- document.getElementById("source").onkeydown = function(e)
- {
- if(e.which == 13 && e.ctrlKey)
- {
- document.getElementById("run").onclick();
- }
- };
- document.getElementById("source").textContent = sinwave;
- document.getElementById("source").onkeydown = function(e)
- {
- if(e.which == 13 && e.ctrlKey)
- {
- document.getElementById("run").onclick();
- }
- };
- document.getElementById("examples").onchange = function()
- {
- document.getElementById("source").textContent = { sinwave, twinkle, hello }[this.value];
- };
- let emulator;
- document.getElementById("run").onclick = run;
- function run()
- {
- emulator && emulator.destroy();
- emulator = window.emulator = new V86({
- wasm_path: "../build/v86.wasm",
- memory_size: 32 * 1024 * 1024,
- vga_memory_size: 2 * 1024 * 1024,
- screen_container: document.getElementById("screen_container"),
- bios: { url: "../bios/seabios.bin" },
- vga_bios: { url: "../bios/vgabios.bin" },
- fda: { url: "../images/sectorc.bin" },
- autostart: true,
- });
- emulator.add_listener("emulator-ready", () => {
- const source = libc + document.getElementById("source").value + start;
- emulator.serial0_send(source);
- });
- document.getElementById("run").onclick = stop;
- document.getElementById("run").textContent = "stop";
- };
- function stop()
- {
- emulator && emulator.destroy();
- document.getElementById("run").onclick = run;
- document.getElementById("run").textContent = "run (ctrl-enter)";
- }
- }
- </script>
- <br>
- <textarea id=source rows=20 cols=80>
- </textarea>
- <br>
- <select id=examples>
- <option value=sinwave>Sine wave</option>
- <option value=hello>Hello</option>
- <option value=twinkle>Twinkle (audio)</option>
- </select>
- <button id=run>run (ctrl-enter)</button>
- <br>
- <hr>
- <div id="screen_container">
- <div style="white-space: pre; font: 14px monospace; line-height: 14px"></div>
- <canvas style="display: none"></canvas>
- </div>
- <hr>
- <a href="https://github.com/xorvoid/sectorc">sectorc</a> on <a href="/v86/">v86</a>
|