|
org 100h
; add your code here
mov ax, cs mov ds, ax mov ax, 0xb800 mov es, ax xor ax, ax xor bx, bx xor dx, dx mov al, 0xff mov cx, 0x0008 s: xor dx, dx rcl al, 1 adc dl, 0x30 mov es:[bx], dl inc bx mov es:[bx], 0x0c inc bx loop s ret
; You may customize this and other start-up templates; ; The location of this template is c:\emu8086\inc\0_com_template.txt
org 100h
; add your code here mov ax, cs mov ds, ax mov ss, ax mov ax, 0xb800 mov es, ax mov ax, 0x6f4e ;mov bx, 2 ;mov bx, 8 mov bx, 10 ;mov bx, 16 xor cx, cx next_div: mov dx, 0 div bx push dx inc cx cmp ax, 0 jnz next_div mov si, bx xor bx, bx cmp si, 16 jnz outp ;如果是显示16进制则在值前面加上0x mov es:[bx], '0' inc bx mov es:[bx], 0x0c inc bx mov es:[bx], 'x' inc bx mov es:[bx], 0x0c inc bx outp: pop dx add dl, 0x30 cmp dl, 0x3a ;是A-F,要多加7 jl outc add dl, 0x07 outc: mov es:[bx], dl inc bx mov es:[bx], 0x0c inc bx loop outp hlt
/* * head.s contains the 32-bit startup code. * * NOTE!!! Startup happens at absolute address 0x00000000, which is also where * the page directory will exist. The startup code will be overwritten by * the page directory. */ .text .globl _idt,_gdt,_pg_dir _pg_dir: startup_32: movl $0x10,%eax mov %ax,%ds mov %ax,%es mov %ax,%fs mov %ax,%gs lss _stack_start,%esp call setup_idt call setup_gdt movl $0x10,%eax # reload all the segment registers mov %ax,%ds # after changing gdt. CS was already mov %ax,%es # reloaded in 'setup_gdt' mov %ax,%fs mov %ax,%gs lss _stack_start,%esp xorl %eax,%eax 1: incl %eax # check that A20 really IS enabled movl %eax,0x000000 cmpl %eax,0x100000 je 1b movl %cr0,%eax # check math chip andl $0x80000011,%eax # Save PG,ET,PE testl $0x10,%eax jne 1f # ET is set - 387 is present orl $4,%eax # else set emulate bit 1: movl %eax,%cr0 jmp after_page_tables
/* * setup_idt * * sets up a idt with 256 entries pointing to * ignore_int, interrupt gates. It then loads * idt. Everything that wants to install itself * in the idt-table may do so themselves. Interrupts * are enabled elsewhere, when we can be relatively * sure everything is ok. This routine will be over- * written by the page tables. */ setup_idt: lea ignore_int,%edx movl $0x00080000,%eax movw %dx,%ax /* selector = 0x0008 = cs */ movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
lea _idt,%edi mov $256,%ecx rp_sidt: movl %eax,(%edi) movl %edx,4(%edi) addl $8,%edi dec %ecx jne rp_sidt lidt idt_descr ret
/* * setup_gdt * * This routines sets up a new gdt and loads it. * Only two entries are currently built, the same * ones that were built in init.s. The routine * is VERY complicated at two whole lines, so this * rather long comment is certainly needed :-). * This routine will beoverwritten by the page tables. */ setup_gdt: lgdt gdt_descr ret
.org 0x1000 pg0:
.org 0x2000 pg1:
.org 0x3000 pg2: # This is not used yet, but if you # want to expand past 8 Mb, you'll have # to use it.
.org 0x4000 after_page_tables: pushl $0 # These are the parameters to main :-) pushl $0 pushl $0 pushl $L6 # return address for main, if it decides to. pushl $_main jmp setup_paging L6: jmp L6 # main should never return here, but # just in case, we know what happens.
/* This is the default interrupt "handler" :-) */ .align 2 ignore_int: incb 0xb8000+160 # put something on the screen movb $2,0xb8000+161 # so that we know something iret # happened
/* * Setup_paging * * This routine sets up paging by setting the page bit * in cr0. The page tables are set up, identity-mapping * the first 8MB. The pager assumes that no illegal * addresses are produced (ie >4Mb on a 4Mb machine). * * NOTE! Although all physical memory should be identity * mapped by this routine, only the kernel page functions * use the >1Mb addresses directly. All "normal" functions * use just the lower 1Mb, or the local data space, which * will be mapped to some other place - mm keeps track of * that. * * For those with more memory than 8 Mb - tough luck. I've * not got it, why should you :-) The source is here. Change * it. (Seriously - it shouldn't be too difficult. Mostly * change some constants etc. I left it at 8Mb, as my machine * even cannot be extended past that (ok, but it was cheap :-) * I've tried to show which constants to change by having * some kind of marker at them (search for "8Mb"), but I * won't guarantee that's all :-( ) */ .align 2 setup_paging: movl $1024*3,%ecx xorl %eax,%eax xorl %edi,%edi /* pg_dir is at 0x000 */ cld;rep;stosl movl $pg0+7,_pg_dir /* set present bit/user r/w */ movl $pg1+7,_pg_dir+4 /* --------- " " --------- */ movl $pg1+4092,%edi movl $0x7ff007,%eax /* 8Mb - 4096 + 7 (r/w user,p) */ std 1: stosl /* fill pages backwards - more efficient :-) */ subl $0x1000,%eax jge 1b xorl %eax,%eax /* pg_dir is at 0x0000 */ movl %eax,%cr3 /* cr3 - page directory start */ movl %cr0,%eax orl $0x80000000,%eax movl %eax,%cr0 /* set paging (PG) bit */ ret /* this also flushes prefetch-queue */
.align 2 .word 0 idt_descr: .word 256*8-1 # idt contains 256 entries .long _idt .align 2 .word 0 gdt_descr: .word 256*8-1 # so does gdt (not that that's any .long _gdt # magic number, but it works for me :^)
.align 3 _idt: .fill 256,8,0 # idt is uninitialized
_gdt: .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x00c09a00000007ff /* 8Mb */ .quad 0x00c09200000007ff /* 8Mb */ .quad 0x0000000000000000 /* TEMPORARY - don't use */ .fill 252,8,0 /* space for LDT's and TSS's etc */
| | boot.s | | boot.s is loaded at 0x7c00 by the bios-startup routines, and moves itself | out of the way to address 0x90000, and jumps there. | | It then loads the system at 0x10000, using BIOS interrupts. Thereafter | it disables all interrupts, moves the system down to 0x0000, changes | to protected mode, and calls the start of system. System then must | RE-initialize the protected mode in it's own tables, and enable | interrupts as needed. | | NOTE! currently system is at most 8*65536 bytes long. This should be no | problem, even in the future. I want to keep it simple. This 512 kB | kernel size should be enough - in fact more would mean we'd have to move | not just these start-up routines, but also do something about the cache- | memory (block IO devices). The area left over in the lower 640 kB is meant | for these. No other memory is assumed to be "physical", ie all memory | over 1Mb is demand-paging. All addresses under 1Mb are guaranteed to match | their physical addresses. | | NOTE1 abouve is no longer valid in it's entirety. cache-memory is allocated | above the 1Mb mark as well as below. Otherwise it is mainly correct. | | NOTE 2! The boot disk type must be set at compile-time, by setting | the following equ. Having the boot-up procedure hunt for the right | disk type is severe brain-damage. | The loader has been made as simple as possible (had to, to get it | in 512 bytes with the code to move to protected mode), and continuos | read errors will result in a unbreakable loop. Reboot by hand. It | loads pretty fast by getting whole sectors at a time whenever possible. | 1.44Mb disks: sectors = 18 | 1.2Mb disks: | sectors = 15 | 720kB disks: | sectors = 9 .globl begtext, begdata, begbss, endtext, enddata, endbss .text begtext: .data begdata: .bss begbss: .text BOOTSEG = 0x07c0 INITSEG = 0x9000 SYSSEG = 0x1000 | system loaded at 0x10000 (65536). ENDSEG = SYSSEG + SYSSIZE entry start start: mov ax,#BOOTSEG mov ds,ax mov ax,#INITSEG mov es,ax mov cx,#256 sub si,si sub di,di rep movw jmpi go,INITSEG go: mov ax,cs mov ds,ax mov es,ax mov ss,ax mov sp,#0x400 | arbitrary value >>512 mov ah,#0x03 | read cursor pos xor bh,bh int 0x10 mov cx,#24 mov bx,#0x0007 | page 0, attribute 7 (normal) mov bp,#msg1 mov ax,#0x1301 | write string, move cursor int 0x10 | ok, we've written the message, now | we want to load the system (at 0x10000) mov ax,#SYSSEG mov es,ax | segment of 0x010000 call read_it call kill_motor | if the read went well we get current cursor position ans save it for| posterity. mov ah,#0x03 | read cursor pos xor bh,bh int 0x10 | save it in known place, con_init fetches mov [510],dx | it from 0x90510. | now we want to move to protected mode cli | no interrupts allowed ! | first we move the system to it's rightful place mov ax,#0x0000 cld | 'direction'=0, movs moves forward do_move: mov es,ax | destination segment add ax,#0x1000 cmp ax,#0x9000 jz end_move mov ds,ax | source segment sub di,di sub si,si mov cx,#0x8000 rep movsw j do_move | then we load the segment descriptors end_move: mov ax,cs | right, forgot this at first. didn't work :-) mov ds,ax lidt idt_48 | load idt with 0,0 lgdt gdt_48 | load gdt with whatever appropriate | that was painless, now we enable A20 call empty_8042 mov al,#0xD1 | command write out #0x64,al call empty_8042 mov al,#0xDF | A20 on out #0x60,al call empty_8042 | well, that went ok, I hope. Now we have to reprogram the interrupts :-( | we put them right after the intel-reserved hardware interrupts, at | int 0x20-0x2F. There they won't mess up anything. Sadly IBM really | messed this up with the original PC, and they haven't been able to | rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, | which is used for the internal hardware interrupts as well. We just | have to reprogram the 8259's, and it isn't fun. mov al,#0x11 | initialization sequence out #0x20,al | send it to 8259A-1 .word 0x00eb,0x00eb | jmp $+2, jmp $+2 out #0xA0,al | and to 8259A-2 .word 0x00eb,0x00eb mov al,#0x20 | start of hardware int's (0x20) out #0x21,al .word 0x00eb,0x00eb mov al,#0x28 | start of hardware int's 2 (0x28) out #0xA1,al .word 0x00eb,0x00eb mov al,#0x04 | 8259-1 is master out #0x21,al .word 0x00eb,0x00eb mov al,#0x02 | 8259-2 is slave out #0xA1,al .word 0x00eb,0x00eb mov al,#0x01 | 8086 mode for both out #0x21,al .word 0x00eb,0x00eb out #0xA1,al .word 0x00eb,0x00eb mov al,#0xFF | mask off all interrupts for now out #0x21,al .word 0x00eb,0x00eb out #0xA1,al | well, that certainly wasn't fun :-(. Hopefully it works, and we don't | need no steenking BIOS anyway (except for the initial loading :-). | The BIOS-routine wants lots of unnecessary data, and it's less | "interesting" anyway. This is how REAL programmers do it. | | Well, now's the time to actually move into protected mode. To make | things as simple as possible, we do no register set-up or anything, | we let the gnu-compiled 32-bit programs do that. We just jump to | absolute address 0x00000, in 32-bit protected mode. mov ax,#0x0001 | protected mode (PE) bit lmsw ax | This is it! jmpi 0,8 | jmp offset 0 of segment 8 (cs) | This routine checks that the keyboard command queue is empty | No timeout is used - if this hangs there is something wrong with | the machine, and we probably couldn't proceed anyway. empty_8042: .word 0x00eb,0x00eb in al,#0x64 | 8042 status port test al,#2 | is input buffer full? jnz empty_8042 | yes - loop ret | This routine loads the system at address 0x10000, making sure | no 64kB boundaries are crossed. We try to load it as fast as| possible, loading whole tracks whenever we can. | | in: es - starting address segment (normally 0x1000) | | This routine has to be recompiled to fit another drive type, | just change the "sectors" variable at the start of the file | (originally 18, for a 1.44Mb drive) | sread: .word 1 | sectors read of current track head: .word 0 | current head track: .word 0 | current track read_it: mov ax,es test ax,#0x0fff die: jne die | es must be at 64kB boundary xor bx,bx | bx is starting address within segment rp_read: mov ax,es cmp ax,#ENDSEG | have we loaded all yet? jb ok1_read ret ok1_read: mov ax,#sectors sub ax,sread mov cx,ax shl cx,#9 add cx,bx jnc ok2_read je ok2_read xor ax,ax sub ax,bx shr ax,#9 ok2_read: call read_track mov cx,ax add ax,sread cmp ax,#sectors jne ok3_read mov ax,#1 sub ax,head jne ok4_read inc track ok4_read: mov head,ax xor ax,ax ok3_read: mov sread,ax shl cx,#9 add bx,cx jnc rp_read mov ax,es add ax,#0x1000 mov es,ax xor bx,bx jmp rp_read read_track: push ax push bx push cx push dx mov dx,track mov cx,sread inc cx mov ch,dl mov dx,head mov dh,dl mov dl,#0 and dx,#0x0100 mov ah,#2 int 0x13 jc bad_rt pop dx pop cx pop bx pop ax ret bad_rt: mov ax,#0 mov dx,#0 int 0x13 pop dx pop cx pop bx pop ax jmp read_track /* * This procedure turns off the floppy drive motor, so * that we enter the kernel in a known state, and * don't have to worry about it later. */kill_motor: push dx mov dx,#0x3f2 mov al,#0 outb pop dx ret gdt: .word 0,0,0,0 | dummy .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb) .word 0x0000 | base address=0 .word 0x9A00 | code read/exec .word 0x00C0 | granularity=4096, 386 .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb) .word 0x0000 | base address=0 .word 0x9200 | data read/write .word 0x00C0 | granularity=4096, 386 idt_48: .word 0 | idt limit=0 .word 0,0 | idt base=0L gdt_48: .word 0x800 | gdt limit=2048, 256 GDT entries .word gdt,0x9 | gdt base = 0X9xxxx msg1: . byte 13,10 .ascii "Loading system " . byte 13,10,13,10 .text endtext: .data enddata: .bss endbss:
1 ; 2012.6.30, Jinfeng @ SWUST 2 ; nasm boot.asm -o boot.bin 3 4 org 07c00h ; cs:ip = 07c00h 5 entry: 6 ; set env 7 mov ax,cs 8 mov ds,ax 9 mov es,ax 10 mov ss,ax 11 mov sp,0x400 12 13 load_system: 14 mov dx,0x0000 15 mov cx,0x0002 16 17 mov ax,0x1000 18 mov es,ax 19 xor bx,bx ; [es:bx] 20 21 mov ax,0x0200+2 ; 1024 bytes 22 int 0x13 23 jnc move_system 24 try_again: 25 jmp load_system 26 27 move_system: 28 cli ; don't need BIOS func 29 ; will open just before 'ret' to task 0 in new mode 30 cld 31 mov ax,0x1000 32 mov ds,ax 33 xor ax,ax 34 mov es,ax 35 mov cx,0x0200 36 sub si,si 37 sub di,di 38 rep movsb 39 40 load_gdtr: 41 mov ax,0x0000 42 mov ds,ax 43 44 mov ax,(gdtr-gdt) 45 mov word [gdtr],ax 46 mov dword [gdtr+2],gdt ; not 0x7c00+gdt ? 47 48 lidt [idtr] ; CPU request IDT before jump into new mode 49 lgdt [gdtr] 50 51 mov al,0x02 52 out 0x92,al ; open A20, enable 32-bit address 53 54 mov ax,0x0001 55 mov cr0,eax ; set PE flag in EFLAGS register 56 57 jmp dword 0x08:0 ; jmp to reset all registers in new mode 58 59 ;end!!! 60 61 gdt: dw 0,0,0,0 62 dw 0x1000,0x0000,0x9a00,0x00c0 ; 16Mb,0x0000,r/x 63 dw 0x1000,0x0000,0x9200,0x00c0 ; 10MB,0x0000,r/w 64 dw 0x0002,0x8000,0x920b,0x00c0 ; 8kb,0xb8000, 4kb<-swap->4kb 65 66 gdtr: dw 0x0000,0x0000,0x0000 67 idtr: dw 0x0000,0x0000,0x0000 68 69 times 510-($-$$) db 0 70 dw 0xaa55
在windows下,搭建MinGW+MSYS环境,基于mplayer的源码进行修改后,做出了自己的GUI界面,修改后运行的界面如下。 【主界面】
【均衡器】
修改部分:
1、增加频谱显示;
2、增加数码管数字显示(创建了一个STATIC窗口,重新指定窗口过程重绘窗口);
3、增加Media Player 11进度条显示(创建了一个STATIC窗口,重新指定窗口过程重绘窗口)。
4、增加均衡器(10段)。
以上部分的修改完全纯C开发,仅频谱绘图部分是原来的C++代码封装为dll后,导出C函数在mplayer里调用实现。
文件1 文件2 文件3 源码下载 请先阅读压缩包里的文件“请先读我.txt”。
|